Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Whats the correct way to use net.Conn.Read for persistant TCP sockets

Tags:

tcp

go

sockets

I have a working TCP socket setup on my Go server. I accept an incoming connection, run a for loop and read incoming data using the net.Conn.Read function.

But it just doesn't make sense to me. How does it know the full message has been received in order to continue with a return of message size?

This is my code currently:

 func (tcpSocket *TCPServer) HandleConnection(conn net.Conn) {

    println("Handling connection! ", conn.RemoteAddr().String(), " connected!")    
    recieveBuffer := make([]byte, 50) // largest message we ever get is 50 bytes

    defer func() {          
        fmt.Println("Closing connection for: ", conn.RemoteAddr().String())
        conn.Close()
    }()

    for {
        // how does it know the end of a message vs the start of a new one?
        messageSize, err := conn.Read(recieveBuffer) 
        if err != nil {
            return
        }
        if messageSize > 0 { // update keep alive since we got a message
            conn.SetReadDeadline(time.Now().Add(time.Second * 5))    
        }
    }
}

Lets say my application sends a message which is 6 bytes long (could be any size). How does conn.Read know when its received the end of said message to then continue?

My experience mainly lies in C#, so Go is but unusual here. For my C# application the messages have the size of the message contained in first byte, then i use a for loop to read the remaining bytes up to message size.

Yet the above code in Go seems to get the full message and continues - it some how automatically knows the size of my message?

I am really confused how this is happening or if its just working by luck when i'm actually approaching it wrong.

All my messages have the header in the first byte stating the size of the message. But it seems i don't need it on a Go server, am i misunderstanding how this works?

like image 603
WDUK Avatar asked Dec 01 '17 01:12

WDUK


People also ask

How does TCP maintain connection?

When two hosts are connected over a network via TCP/IP, TCP Keepalive Packets can be used to determine if the connection is still valid, and terminate it if needed. Most hosts that support TCP also support TCP Keepalive. Each host (or peer) periodically sends a TCP packet to its peer which solicits a response.

How many sockets are required for a TCP connection?

For most socket interfaces, the maximum number of sockets allowed per each connection between an application and the TCP/IP sockets interface is 65535. The exceptions to this rule are the C sockets interface and the C sockets interface for CICS®, where the maximum allowed for both of these interfaces is 2000.


1 Answers

TCP doesn't provide any message framing, it's up to you to buffer the stream and parse the messages according to whatever protocol you've defined.

When parsing a TCP stream, it's often useful to immediately wrap the connection in a bufio.Reader, as not only can it make reading more efficient, but it provides you with more useful methods. An example of how you could parse your protocol could be:

buff := make([]byte, 50)
c := bufio.NewReader(conn)

for {
    // read a single byte which contains the message length
    size, err := c.ReadByte()
    if err != nil {
        return err
    }

    // read the full message, or return an error
    _, err := io.ReadFull(c, buff[:int(size)])
    if err != nil {
        return err
    }

    fmt.Printf("received %x\n", buff[:int(size)])
}
like image 57
JimB Avatar answered Oct 20 '22 21:10

JimB