此项目有对应的Android端demo有需求请联系下方QQ
TCP粘包和拆包产生的原因
- 应用程序写入数据的字节大小大于套接字发送缓冲区的大小
- 进行MSS大小的TCP分段。MSS是最大报文段长度的缩写。MSS是TCP报文段中的数据字段的最大长度。数据字段加上TCP首部才等于整个的TCP报文段。所以MSS并不是TCP报文段的最大长度,而是:MSS=TCP报文段长度-TCP首部长度
- 以太网的payload大于MTU进行IP分片。MTU指:一种通信协议的某一层上面所能通过的最大数据包大小。如果IP层有一个数据包要传,而且数据的长度比链路层的MTU大,那么IP层就会进行分片,把数据包分成托干片,让每一片都不超过MTU。注意,IP分片可以发生在原始发送端主机上,也可以发生在中间路由器上。
TCP粘包和拆包的解决策略
- 消息定长。例如100字节。
- 在包尾部增加回车或者空格符等特殊字符进行分割,典型的如FTP协议
- 将消息分为消息头和消息尾。(len+data模式)
- 其它复杂的协议,如RTMP协议等。
废话不多说直接上代码
服务端
package network import ( "net" "bufio" "bytes" "encoding/binary" ) type TcpClient struct { tag string conn net.Conn r *bufio.Reader } func NewTcpClint(conn net.Conn) *TcpClient { return &TcpClient{conn: conn, r: bufio.NewReader(conn)} } func (c *TcpClient) LocalAddr() net.Addr { return c.conn.LocalAddr() } func (c *TcpClient) RemoteAddr() net.Addr { return c.conn.RemoteAddr() } func (c *TcpClient) Close() error { return c.conn.Close() } func (c *TcpClient) Write(message []byte) (int, error) { // 读取消息的长度 var length = int32(len(message)) var pkg = new(bytes.Buffer) //写入消息头 err := binary.Write(pkg, binary.BigEndian, length) if err != nil { return 0, err } //写入消息体 err = binary.Write(pkg, binary.BigEndian, message) if err != nil { return 0, err } nn, err := c.conn.Write(pkg.Bytes()) if err != nil { return 0, err } return nn, nil } func (c *TcpClient) Read() ([]byte, error) { // Peek 返回缓存的一个切片,该切片引用缓存中前 n 个字节的数据, // 该操作不会将数据读出,只是引用,引用的数据在下一次读取操作之 // 前是有效的。如果切片长度小于 n,则返回一个错误信息说明原因。 // 如果 n 大于缓存的总大小,则返回 ErrBufferFull。 lengthByte, err := c.r.Peek(4) if err != nil { return nil, err } //创建 Buffer缓冲器 lengthBuff := bytes.NewBuffer(lengthByte) var length int32 // 通过Read接口可以将buf中得内容填充到data参数表示的数据结构中 err = binary.Read(lengthBuff, binary.BigEndian, &length) if err != nil { return nil, err } // Buffered 返回缓存中未读取的数据的长度 if int32(c.r.Buffered()) < length+4 { return nil, err } // 读取消息真正的内容 pack := make([]byte, int(4+length)) // Read 从 b 中读出数据到 p 中,返回读出的字节数和遇到的错误。 // 如果缓存不为空,则只能读出缓存中的数据,不会从底层 io.Reader // 中提取数据,如果缓存为空,则: // 1、len(p) >= 缓存大小,则跳过缓存,直接从底层 io.Reader 中读 // 出到 p 中。 // 2、len(p) < 缓存大小,则先将数据从底层 io.Reader 中读取到缓存 // 中,再从缓存读取到 p 中。 _, err = c.r.Read(pack) if err != nil { return nil, err } return pack[4:], nil } package controller import ( "fmt" "test/tcp/network" "io" "net" ) func ServerRun() { lister, err := net.Listen("tcp", "192.168.2.28:8888") fmt.Println("服务启动成功:192.168.2.28:8888") CheckErr(err) defer lister.Close() for { conn, err := lister.Accept() CheckErr(err) fmt.Println("用户接入") client := network.NewTcpClint(conn) go func() { defer client.Close() for { data, err := client.Read() if err == io.EOF { fmt.Println("断开链接") return } if err != nil { continue } switchController(data, client) } }() } } func CheckErr(err error) { if err != nil { panic(err) } } func switchController(data []byte, c *network.TcpClient) { fmt.Println("读到的数据: " + string(data)) switch string(data) { case "ping": c.Write([]byte("pong")) fmt.Println("发出的数据: pong") break } }
客户端
package main import ( "testing" "net" "log" "fmt" "encoding/binary" "bytes" "time" ) func Test(t *testing.T) { conn, err := net.Dial("tcp", "192.168.2.28:8888") if err != nil { log.Println("dial error:", err) return } defer conn.Close() for { data, _ := Encode("1") time.Sleep(time.Second * 4) _, err := conn.Write(data) fmt.Println(err) } } func Encode(message string) ([]byte, error) { // 读取消息的长度 var length = int32(len(message)) var pkg = new(bytes.Buffer) // 写入消息头 err := binary.Write(pkg, binary.BigEndian, length) if err != nil { return nil, err } // 写入消息实体 err = binary.Write(pkg, binary.BigEndian, []byte(message)) if err != nil { return nil, err } return pkg.Bytes(), nil }
联系 QQ: 3355168235
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 使用 SRI 解决 CDN 劫持
- 使用 parted 解决大于 2T 的磁盘分区
- 使用 spring 的 IOC 解决程序耦合
- Nuxt使用axios跨域问题解决方法
- 使用 Redis 解决“树”形数据的复杂查询
- 手动下载 Chrome,解决 puppeteer 无法使用问题
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Nature of Code
Daniel Shiffman / The Nature of Code / 2012-12-13 / GBP 19.95
How can we capture the unpredictable evolutionary and emergent properties of nature in software? How can understanding the mathematical principles behind our physical world help us to create digital w......一起来看看 《The Nature of Code》 这本书的介绍吧!