前言大家好,我是码农,周五,我们身处21世纪,我们的世界已经在不知不觉中,像许多互联网一样相互联系。互联网是一个通用术语。目前常用的有TCP和UDP协议。当然还有很多其他的协议,但是这次我们将重点介绍最常用的TCP和UDP协议。Socker编程我们学过的TCP和UDP统称为Socker编程,也叫socket编程。多台机器相互通信其实是一个非常复杂的过程。底层是从铺设网线、网线接口、交换机、路由器,到指定各种协议。然后到应用层QQ、微信等软件。如果没有一套标准,每次使用都得自己去执行。也许每个程序员都不是掉头发那么简单!有了Socker,Socker将各种繁琐的底层操作隐藏在应用层之前,我们可能只需要Socker.TCP就可以实现TCP协议的通信。Go语言TCPTCP是一种稳定可靠的长期连接。既然涉及到通信,那肯定有两个终端,至少一个是server,一个是client。就像我们的淘宝,每次打开淘宝都要去Link一下,当然淘宝不是直接TCP的。服务器在Go中实现服务器,服务器上的并发很简单,让每个连接由一个协程来处理就可以了!代码packagemainimport("bufio""fmt""net")funcprocess(connnet.Conn){deferconn.Close()for{reader:=bufio.NewReader(conn)buf:=make([]byte,128)n,err:=reader.Read(buf)iferr!=nil{fmt.Println("数据读取失败",err)return}recvStr:=string(buf[:n])fmt.Println("客户端发送的值:",recvStr)}}funcmain(){lister,err:=net.Listen("tcp","0.0.0.0:8008")iferr!=nil{fmt.Println("连接失败",err)}for{fmt.Println("等待建立连接,此时会阻塞")conn,err:=lister.Accept()//等待建立连接fmt.Println("连接建立成功,继续")iferr!=nil{fmt.Println("Connectionestablishmentfailed",err)//继续监听下一个连接continue}goprocess(conn)}}client客户端很简单,相对来说不需要并发,只需要连接。codepackagemainimport("bufio""fmt""net""os")//客户端funcmain(){conn,err:=net.Dial("tcp","192.168.10.148:8008")iferr!=nil{fmt.Println("连接服务器失败",err)}deferconn.Close()inputReader:=bufio.NewReader(os.Stdin)for{fmt.Println(":")input,_:=inputReader.ReadString('\n')_,err=conn.Write([]byte(input))iferr!=nil{fmt.Println("发送成功")}}}执行结果是这样的,我们实现了所有的并发处理服务器端的客户端结束请求。粘包我们先来看看什么是粘包。serverpackagemainimport("bufio""fmt""io""net")funcprocess(connnet.Conn){deferconn.Close()reader:=bufio.NewReader(conn)buf:=make([]byte,1024)for{n,err:=reader.Read(buf)//读取iferr==io.EOF{fmt.Println("reading")break}//读取错误iferr!=nil{fmt.Println("dataReadfailed",err)return}recvStr:=string(buf[:n])fmt.Println("客户端发送的值:",recvStr)}}funcmain(){lister,err:=net.Listen("tcp","0.0.0.0:8008")iferr!=nil{fmt.Println("连接失败",err)return}deferlister.Close()for{fmt.Println("等待连接,会阻塞")conn,err:=lister.Accept()//等待建立连接fmt.Println("连接建立成功,继续")iferr!=nil{fmt.Println("建立连接失败",err)//继续继续听下一个链接}goprocess(conn)}}clientpackagemainimport("fmt""net")//clientfuncmain(){conn,err:=net.Dial("tcp","192.168.10.148:8008")iferr!=nil{fmt.Println("连接服务器失败",err)}deferconn.Close()fori:=0;i<10;i++{sendStr:="你好worldadsasdfasdfadsfadsfadsadsasdasdads"conn.Write([]byte(sendStr))time.Sleep(time.Second)}}注:第18行代码sleepfor1s执行结果如果我把第18行代码执行结果直接注释成一行,什么?什么情况?不应该和以前一样吗???每次发送一个值,那边都会收到。操作系统上面的软件,当我们向服务器发送一个数据的时候,是通过调用操作系统的相关接口来发送的,操作系统再经过各种复杂的操作发送给对方机器,但是操作系统有一个发送数据的缓冲区,默认情况下,如果缓冲区有一个size,如果buffer未满,则不会发送数据,所以上面client发送数据时,系统buffer未满,一直压在操作系统的buffer中,最后发现没有数据,所以它被一次性发送到服务器,但为什么sleep(1)再次工作在?这是因为缓冲区被多个程序使用,1秒足够其他程序填满缓冲区,然后各自发送自己的数据,这就是为什么第一次操作没问题,但第二次出现问题,因为第二次是我们客户端全功能解决粘包工具功能。我们将封装的解包函数socker_sitck/stick.gopackagesocker_stickimport("bufio""bytes""encoding/binary""fmt")//Encode对消息进行编码funcEncode(messagestring)([]byte,error){length:=int32(len(message))varpkg=new(bytes.Buffer)//写入消息头err:=binary.Write(pkg,binary.LittleEndian,length)iferr!=nil{fmt.Println("写入消息头失败",err)returnnil,err}//写入消息实体err=binary.Write(pkg,binary.LittleEndian,[]byte(message))iferr!=nil{fmt.Println("写入消息实体失败",err)returnnil,err}returnpkg.Bytes(),nil}//解码解码消息funcDecode(reader*bufio.Reader)(string,error){//读取信息长度lengthByte,_:=reader.Peek(4)lengthBuff:=bytes.NewBuffer(lengthByte)varlengthint32err:=binary.Read(lengthBuff,binary.LittleEndian,&length)iferr!=nil{return"",err}//BuffRead返回缓冲区中可读字节数ifint32(reader.Buffered())
