1. TCP黏包

    服务端代码如下:

    客户端代码如下:

    1. func main() {
    2. conn, err := net.Dial("tcp", "127.0.0.1:30000")
    3. if err != nil {
    4. fmt.Println("dial failed, err", err)
    5. return
    6. }
    7. defer conn.Close()
    8. for i := 0; i < 20; i++ {
    9. msg := `Hello, Hello. How are you?`
    10. conn.Write([]byte(msg))
    11. }
    12. }

    将上面的代码保存后,分别编译。先启动服务端再启动客户端,可以看到服务端输出结果如下:

    主要原因就是tcp数据传递模式是流模式,在保持长连接的时候可以进行多次的收和发。

    “粘包”可发生在发送端也可发生在接收端:

    1. 1.Nagle算法造成的发送端的粘包:Nagle算法是一种改善网络传输效率的算法。简单来说就是当我们提交一段数据给TCP发送时,TCP并不立刻发送此段数据,而是等待一小段时间看看在等待期间是否还有要发送的数据,若有则会一次把这两段数据发送出去。

    1.1.2. 解决办法

    出现”粘包”的关键在于接收方不确定将要传输的数据包的大小,因此我们可以对数据包进行封包和拆包的操作。

    我们可以自己定义一个协议,比如数据包的前4个字节为包头,里面存储的是发送的数据的长度。

    接下来在服务端和客户端分别使用上面定义的proto包的Decode和Encode函数处理数据。

    服务端代码如下:

    1. // socket_stick/server2/main.go
    2. func process(conn net.Conn) {
    3. defer conn.Close()
    4. reader := bufio.NewReader(conn)
    5. for {
    6. msg, err := proto.Decode(reader)
    7. if err == io.EOF {
    8. return
    9. }
    10. if err != nil {
    11. fmt.Println("decode msg failed, err:", err)
    12. return
    13. }
    14. fmt.Println("收到client发来的数据:", msg)
    15. }
    16. }
    17. listen, err := net.Listen("tcp", "127.0.0.1:30000")
    18. if err != nil {
    19. fmt.Println("listen failed, err:", err)
    20. return
    21. }
    22. defer listen.Close()
    23. for {
    24. conn, err := listen.Accept()
    25. if err != nil {
    26. fmt.Println("accept failed, err:", err)
    27. continue
    28. }
    29. go process(conn)
    30. }
    31. }