Solution to the golang network socket sticky packet problem

  • 2020-06-01 09:59:59
  • OfStack

This article illustrates the solution to the golang network socket sticky packet problem with an example. I will share it with you for your reference as follows:

I saw a lot of people asking this question, so I wrote an example today, hoping to help you

First of all, say 1 what is sticky packet: baidu is more popular language refers to the TCP protocol, a number of packet data sent by the sender to the receiver when receiving sticky packet, from the receiving buffer, the head of the last packet data immediately followed by the tail of the first packet data.

The solution is as follows:

Server:

package main
import (
    "bytes"
    "encoding/binary"
    "fmt"
    "io"
    "net"
)
func main() {
    // Listen on port
    ln, err := net.Listen("tcp", ":6000")
    if err != nil {
        fmt.Printf("Listen Error: %s\n", err)
        return
    }
    // Listening to the circulation
    for {
        // Accept client links
        conn, err := ln.Accept()
        if err != nil {
            fmt.Printf("Accept Error: %s\n", err)
            continue
        }
        // Handle client links
        go handleConnection(conn)
    }
}
func handleConnection(conn net.Conn) {
    // Close links
    defer conn.Close()
    // The client
    fmt.Printf("Client: %s\n", conn.RemoteAddr())
    // Message buffer
    msgbuf := bytes.NewBuffer(make([]byte, 0, 10240))
    // The data buffer
    databuf := make([]byte, 4096)
    // The length of the message
    length := 0
    // The length of the message uint32
    ulength := uint32(0)
    // Data cycle
    for {
        // Read the data
        n, err := conn.Read(databuf)
        if err == io.EOF {
            fmt.Printf("Client exit: %s\n", conn.RemoteAddr())
        }
        if err != nil {
            fmt.Printf("Read error: %s\n", err)
            return
        }
        fmt.Println(databuf[:n])
        // Data is added to the message buffer
        n, err = msgbuf.Write(databuf[:n])
        if err != nil {
            fmt.Printf("Buffer write error: %s\n", err)
            return
        }
        // Message segmentation loop
        for {
            // The message header
            if length == 0 && msgbuf.Len() >= 4 {
                binary.Read(msgbuf, binary.LittleEndian, &ulength)
                length = int(ulength)
                // Check for long messages
                if length > 10240 {
                    fmt.Printf("Message too length: %d\n", length)
                    return
                }
            }
            // The message body
            if length > 0 && msgbuf.Len() >= length {
                fmt.Printf("Client messge: %s\n", string(msgbuf.Next(length)))
                length = 0
            } else {
                break
            }
        }
    }
}

Client:

package main
import (
    "bytes"
    "encoding/binary"
    "fmt"
    "net"
    "time"
)
func main() {
    // Link server
    conn, err := net.Dial("tcp", "127.0.0.1:6000")
    if err != nil {
        fmt.Printf("Dial error: %s\n", err)
        return
    }
    // Client information
    fmt.Printf("Client: %s\n", conn.LocalAddr())
    // Message buffer
    msgbuf := bytes.NewBuffer(make([]byte, 0, 1024))
    // The message content
    message := []byte(" I am a utf-8 The news of the ")
    // The length of the message
    messageLen := uint32(len(message))
    // Total message length
    mlen := 4 + len(message)
    // write 5 message
    for i := 0; i < 10; i++ {
        binary.Write(msgbuf, binary.LittleEndian, messageLen)
        msgbuf.Write(message)
    }
    // Single package sent 1 message
    conn.Write(msgbuf.Next(mlen))
    time.Sleep(time.Second)
    // Single package sent 3 message
    conn.Write(msgbuf.Next(mlen * 3))
    time.Sleep(time.Second)
    // Send an incomplete header
    conn.Write(msgbuf.Next(2))
    time.Sleep(time.Second)
    // Send the rest of the message
    conn.Write(msgbuf.Next(mlen - 2))
    time.Sleep(time.Second)
    // Send an incomplete message body
    conn.Write(msgbuf.Next(mlen - 6))
    time.Sleep(time.Second)
    // Send the rest of the message
    conn.Write(msgbuf.Next(6))
    time.Sleep(time.Second)
    // Multiple segments
    conn.Write(msgbuf.Next(mlen + 2))
    time.Sleep(time.Second)
    conn.Write(msgbuf.Next(-2 + mlen - 8))
    time.Sleep(time.Second)
    conn.Write(msgbuf.Next(8 + 1))
    time.Sleep(time.Second)
    conn.Write(msgbuf.Next(-1 + mlen + mlen))
    time.Sleep(time.Second)
    // Close links
    conn.Close()
}

I hope this article has been helpful to you in programming Go.


Related articles: