英文:
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 (
"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
}
......
}
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 < 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, &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
}
Used in:
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)
}
答案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 "io"
......
pdu := make([]byte, pduLen)
io.ReadFull(conn, pdu)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论