The method of reading an integral network PDU in Go

huangapple go评论81阅读模式
英文:

The method of reading an integral network PDU in 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?个人认为循环的代码有点丑陋。

英文:

I am developing a simple Go server program which receives client's request and process it. And the code is simplified as this:

package main

import (
	&quot;fmt&quot;
	&quot;net&quot;
	&quot;os&quot;
)

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(&quot;tcp&quot;, fmt.Sprintf(&quot;%s:%s&quot;, os.Args[1], os.Args[2]))
	checkError(err)

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

}

I assume every request's length is 32 bytes (just an example). Because the TCP is a stream protocol, I need to use a loop to check whether an integral PDU is read:

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

Is there any method to assure that an integral PDU is read? Personally, I think the loop code is a little ugly.

答案1

得分: 1

这个例子是根据接收到的PDU的具体情况而定的,但是它会查找大小,然后读取所有内容(使用io.ReadFull()函数)。

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)
}
英文:

It can depend on the exact nature of the PDU you are receiving, but this example will look for the size, and then read everything (using 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, &amp;size)
    b := make([]byte, size)
    // _, err := conn.Read(b)
    _, err := io.ReadFull(conn, b)
    if err == nil {
      return string(b)
    }
  }
  return &quot;&quot;
}

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

Used in:

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

答案2

得分: 0

在golang-nuts讨论了这个问题之后:如何读取一个整数网络PDU?
代码应该是:

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

After discussing this issue in golang-nuts: How to read an integral network PDU?
The code should be:

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

huangapple
  • 本文由 发表于 2014年5月21日 14:44:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/23775814.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定