3
votes

I have this Go tcp socket

package main

import (
  "fmt"
  "io"
  "log"
  "net"
  "bytes"
)

func main() {

  l, err := net.Listen("tcp", ":1200")
  if err != nil {
    log.Fatal(err)
  }
  defer l.Close()
  for {

    conn, err := l.Accept()
    if err != nil {
      log.Fatal(err)
    }

    go func(c net.Conn) {

      var buf bytes.Buffer
      io.Copy(&buf, c)
      fmt.Println("total size:", buf.Len())
      s := buf.String()
      println(s)

      c.Close()
    }(conn)
  }
}

accept a message, transform it to string and display it, but if the connection is not closed by the client I am not able to see the message showed on the server as expected

How is possible to send multiple message from the client without the need to close the client connection (by the client) ?

Here the client in NodeJs

var net = require('net');

let packet = {
              Target: { Host: "", Port: "9000" },
              Name: { Family: "Newmarch", Personal: "Jan" },
              Email: [
                      { Kind: "home", Address: "[email protected]"},
                      { Kind: "work", Address: "[email protected]"}
                     ]
}


var client = new net.Socket();
client.connect(1200, '0.0.0.0', function() {
  console.log('Connected');
  client.write( (new Buffer(JSON.stringify(packet), 'UTF-8')) );
  client.end();
  //client.write('\n');
});

client.on('data', function(data) {
  console.log('Received: ' + data);
  client.destroy();
});

client.on('close', function() {
  console.log('Connection closed');
});

Thanks valeriano cossu

2
As the answers mentioned you have to break your messages somehow. TCP itself is a streaming protocol, not a packet based one.Kaveh Shahbazian

2 Answers

3
votes

Because you are getting a constant stream of data the server needs to know how to seperate messages. One way of doing that is using a new line character.

I have revised your code below.

Go server: package main

import (
    "bufio"
    "log"
    "net"
)

func main() {

    l, err := net.Listen("tcp", ":1200")
    if err != nil {
        log.Fatal(err)
    }
    defer l.Close()
    for {

        conn, err := l.Accept()
        if err != nil {
            log.Fatal(err)
        }

        go func(c net.Conn) {
            for {
                message, err := bufio.NewReader(conn).ReadString('\n')
                if err != nil {
                    log.Printf("Error: %+v", err.Error())
                    return
                }

                log.Println("Message:", string(message))
            }
        }(conn)
    }
}

Nodejs client:

var net = require('net');

let packet = {
              Target: { Host: "", Port: "9000" },
              Name: { Family: "Newmarch", Personal: "Jan" },
              Email: [
                      { Kind: "home", Address: "[email protected]"},
                      { Kind: "work", Address: "[email protected]"}
                     ]
}


var client = new net.Socket();
client.connect(1200, '0.0.0.0', function() {
  console.log('Connected');

  // Send 10 messages
  for(var i = 0; i < 10; i++) {
    client.write( (new Buffer(JSON.stringify(packet), 'UTF-8')) );
    client.write('\n');
  }

  client.end();

});

client.on('data', function(data) {
  console.log('Received: ' + data);
  client.destroy();
});

client.on('close', function() {
  console.log('Connection closed');
});
1
votes

From the io package documentation: https://golang.org/pkg/io/#Copy , the Copy function copies until it encounters EOF.

You don't send EOF manually but the client closing the connection does that, so the Copy function can finish the copying.

You can use bufio package to read strings with your delimiter:

line, err := bufio.NewReader(conn).ReadString('\n')

In the above case, the delimiter is new line character. You can reuse the reader to repeatedly call ReadString on it to retrieve more messages.