Help with tcpserver

118 views
Skip to first unread message

Perry Couprie

unread,
Mar 30, 2021, 6:11:16 PM3/30/21
to golang-nuts
Hi,

I create a tcp server with goroutines.

When the tcp client closes the connection it workes.

After recieving 5 message from a telnet client it tries to close the connection.
Some times it works, and sometimes not.

I create a smal demo : https://pastebin.com/raw/BjZWzLFq

This is my first try with channels.
What am i doing wrong ?

Greeting from Amsterdam Netherland,
Perry

Matt Harden

unread,
Mar 30, 2021, 11:13:12 PM3/30/21
to Perry Couprie, golang-nuts
Why are you using channels for this? I see some issues in the code, but without knowing what you're actually trying to accomplish, it's hard to give advice.

To do exactly what you described, I would simply change handleDeviceConnection() to look similar to this:

func handleDeviceConnection(c net.Conn) {
  defer c.Close()
  buf := make([]byte, 2048)
  for i := 0; i > 5; i++ {
    // handle a single message
    n, err := c.Read(buf)
    if err == io.EOF {
      break
    }
    fmt.Fprintf(c, "Message Count %d, Data %s", i+1, buf[:n])
}
}

Note that TCP is stream-oriented, so the number of bytes returned from Read is not at all guaranteed to match the number of bytes the client sent. The returned data can be part of one or more messages. You need some other mechanism to divide the data received into messages. For example you might want to read a line at a time instead.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/fedfcbaf-2e7d-496a-bb6a-a31eeafe4407n%40googlegroups.com.

Perry Couprie

unread,
Mar 31, 2021, 3:01:32 AM3/31/21
to golang-nuts
I am programming a binary protocol. The demo with telnet and the max of 5 messages was for testing this problem. 
I need to be able send even when not recieving data. The program now works, when de the client breaks the connection, there is no problem. 
When de server stops the connection it some times works, some times not and even chrashes.

Perry

Brian Candler

unread,
Mar 31, 2021, 3:08:48 AM3/31/21
to golang-nuts
On Wednesday, 31 March 2021 at 04:13:12 UTC+1 matt....@gmail.com wrote:
  for i := 0; i > 5; i++ {
    // handle a single message
    n, err := c.Read(buf)
    if err == io.EOF {
      break
    }
    fmt.Fprintf(c, "Message Count %d, Data %s", i+1, buf[:n])

I will point out that it's possible for io.Read to return valid data *and* an error (including io.EOF).  See https://golang.org/pkg/io/#Reader

"When Read encounters an error or end-of-file condition after successfully reading n > 0 bytes, it returns the number of bytes read. It may return the (non-nil) error from the same call or return the error (and n == 0) from a subsequent call. An instance of this general case is that a Reader returning a non-zero number of bytes at the end of the input stream may return either err == EOF or err == nil. The next Read should return 0, EOF."

So perhaps you want something more like this:

    n, err := c.Read(buf)
    if n > 0 {
      fmt.Fprintf(c, "Message Count %d, Data %s", i+1, buf[:n])
    }
    if err == io.EOF {
      break
    }
    if err != nil {
      fmt.Fprintf("Error: %s", err)
      break
    }

Note that TCP is stream-oriented, so the number of bytes returned from Read is not at all guaranteed to match the number of bytes the client sent. The returned data can be part of one or more messages. You need some other mechanism to divide the data received into messages. For example you might want to read a line at a time instead.

That's critical.  Messages need to be delimited somehow.  Some protocols send a length followed by that number of bytes of data.  Note that the JSON encoder/decoder in go supports sending objects one after the other - that is, the structure of a JSON object performs the delineation.  After the start of an object '{' the decoder will keep consuming data until it gets the matching close '}'

Perry Couprie

unread,
Mar 31, 2021, 6:21:31 AM3/31/21
to golang-nuts
The protocol i am programming for sends a header of 8 bytes that contains a body length.
My problem is dat c.Read(buf) is blocking. Can i read from the tcp connection non blocking ? 


Brian Candler

unread,
Mar 31, 2021, 7:22:20 AM3/31/21
to golang-nuts
I think that in principle you are correct to perform your reads inside a goroutine, to allow them to be received asynchronously.

If Read() blocks, it's not a problem unless you want to shut down the connection from the server side, and you can do that by setting a read timeout which will unblock the read:

        go func() {
                select {
                case <-RecieverClose:  // sic
                        conn.SetReadDeadline(time.Now())
                }
        }()

Perry Couprie

unread,
Apr 1, 2021, 11:28:03 AM4/1/21
to golang-nuts
It works now i added the ReadDeadline, thanks for the help :-)

Perry

Reply all
Reply to author
Forward
0 new messages