dtn43447 2017-10-13 11:34
浏览 43

如何为Go中写入的每个连接发送单独的数据包?

Problem

I want to run a load test with a high number of requests per second. I have written a socket sender and a receiver in Go. The sender sends a lot of packets to port 7357, each one containing the current time in nanoseconds. The receiver listens in port 7357 and parses each message, computing the latency.

The problem is that when reading I get multiple packets in one conn.Read(). I understand that this means that I am in fact sending multiple messages per packet: each conn.Write() does not send a socket packet, but it waits for some time and then gets coalesced with the next (or the next few) before sending.

Question

How can I make sure that each conn.Write() is sent individually through the socket as a separate packet? Note: I don't want to reinvent TCP, I just want to simulate the load from a number of external entities that send a message each.

Steps Taken

I have searched the documentation but there seems to be no conn.Flush() or similar. I have tried using a buffered writer:

writer := bufio.NewWriter(conn)
...
bytes, err := writer.Write(message)
err = writer.Flush()

No errors, but still I get mixed packets at the receiving end. I have also tried doing a fake conn.Read() of 0 bytes after every conn.Write(), but it didn't work either. Sending a message terminator such as does not seem to make any difference. Finally, Nagle algorithm is disabled by default, but I have called tcp.SetNoDelay(true) for good measure.

In Node.js I managed to do the trick with a setImmediate() after each socket.write(): setImmediate() waits for all I/O to finish before continuing. How can I do the same in Go so I get separate packets?

Code Snippets

Send:

func main() {
  conn, _ := net.Dial("tcp", ":7357")
  defer conn.Close()
  for {
    timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
    conn.Write([]byte(timestamp))
    conn.Read(buff)
  }
}

Receive:

func main() {
  listen, _ := net.Listen("tcp4", ":7357")
  defer listen.Close()
  for {
    conn, _ := listen.Accept()
    go handler(conn)
  }
}
func handler(conn net.Conn) {
  defer conn.Close()
  var buf = make([]byte, 1024)
  for {
    conn.Read(buf)
    data := string(buf[:n])
    timestamp, _ := strconv.ParseInt(data, 10, 64)
    elapsed := timestamp - time.Now().UnixNano()
    log.Printf("Elapsed %v", elapsed)
  }
}

Error handling has been removed for legibility, but it is thoroughly checked in the actual code. It crashes when running the strconv.ParseInt() the first time, with a value out of range error since it receives a lot of timestamps coalesced.

  • 写回答

2条回答 默认 最新

  • douzaipou3327 2017-10-13 20:00
    关注

    You can read predefined number of bytes from the socket on each iteration, that might help, but you need to create your own protocol, that will be handled by your application. Without proto impossible to guarantee that everything will work stable, because on the receiver you cannot understand where is the begin and where is the end of message.

    评论

报告相同问题?

悬赏问题

  • ¥15 python的qt5界面
  • ¥15 无线电能传输系统MATLAB仿真问题
  • ¥50 如何用脚本实现输入法的热键设置
  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀
  • ¥20 手写数字识别运行c仿真时,程序报错错误代码sim211-100