在Go中读取整体网络PDU的方法

时间:2014-05-21 06:44:16

标签: tcp network-programming go

我正在开发一个简单的Go服务器程序,它接收客户端的请求并对其进行处理。代码简化为:

package main

import (
    "fmt"
    "net"
    "os"
)

const (
    pduLen = 32
)

func checkError(err error) {
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
}

func main() {
    var buffer [4096]byte
    var count int

    conn, err := net.Dial("tcp", fmt.Sprintf("%s:%s", os.Args[1], os.Args[2]))
    checkError(err)

    for count < pduLen {
        n, err := conn.Read(buffer[count:])
        checkError(err)
        count += n
    }
    ......

}

我假设每个请求的长度都是32个字节(只是一个例子)。因为TCP是流协议,所以我需要使用循环来检查是否读取了整数PDU:

for count < pduLen {
    n, err := conn.Read(buffer[count:])
    checkError(err)
    count += n
}

是否有任何方法可以确保读取完整的PDU?就个人而言,我认为循环代码有点难看。

2 个答案:

答案 0 :(得分:1)

它可能取决于您收到的PDU的确切性质,但this example将查找大小,然后阅读所有内容(使用io.ReadFul())。

func read(conn net.Conn, key string) string {
  fmt.Fprintf(conn, GenerateCommand(OP_GET, key))
  if verify(conn) {
    var size uint16
    binary.Read(conn, binary.LittleEndian, &size)
    b := make([]byte, size)
    // _, err := conn.Read(b)
    _, err := io.ReadFull(conn, b)
    if err == nil {
      return string(b)
    }
  }
  return ""
}

func verify(conn net.Conn) bool {
  b := make([]byte, 1)
  conn.Read(b)
  return b[0] == ERR_NO_ERROR
}

用于:

conn, err := net.Dial("tcp", ":12345")
if err != nil {
  t.Error(err)
}
write(conn, "foo", "bar")
if !verify(conn) {
  t.Error("Bad write!")
}
if r := read(conn, "foo"); r != "bar" {
  t.Errorf("Bad read! Got %v", r)
}

答案 1 :(得分:0)

在golang-nuts讨论此问题后:How to read an integral network PDU? 代码应该是:

import "io"
......
pdu := make([]byte, pduLen)
io.ReadFull(conn, pdu)