我正在实现一个客户端,它发送和接收unixpackets并与已经用C ++实现的服务器交互。
到目前为止,客户端可以成功接收数据包并将其发送到服务器。但是我使用了for循环来不断调用 Recv 来查看是否有新消息。
我实现了Packet类,以便客户端和服务器可以遵循相同的规则来编码和解码消息。传输是一种包装 net.Conn 的结构。客户端由传输,接收数据包和发送数据包组成。
我使用了 for循环继续调用 Recv 来查看是否有新消息到达 net.conn
type Packet struct {
Length uint32
Data []byte
ReadOffset uint32
WriteOffset uint32
}
type Transport struct {
url string
conn net.Conn
}
// connect to url
func (transport *Transport) Dial(url string) error {
c, err := net.Dial("unixpacket", url)
if err != nil {
return err
}
transport.url = url
transport.conn = c
return nil
}
// sending Packet
func (transport *Transport) Send(p *Packet) bool {
readBuffer := (p.Data)[p.ReadOffset : p.WriteOffset]
_, err := transport.conn.Write(readBuffer)
if err != nil {
return false
}
return true
}
// receiving Packet
func (transport *Transport) Recv(p *Packet) bool {
writeBuffer := (p.Data)[p.WriteOffset :]
_, err := transport.conn.Read(writeBuffer)
if err != nil {
return false
}
return true
}
type Client struct {
Transport *Transport
RecvPacket *Packet
SendPacket *Packet
}
// keep checking transport
func (c *Client) ReadFromTransport() {
for {
time.Sleep(20 * time.Millisecond)
if c.Transport.Recv(c.RecvPacket) == false {
continue
}
}
}
是否有一种方法可以让新消息到达 net.conn 时通知net.conn而不是使用for循环?
答案 0 :(得分:3)
net.conn.Read
自动阻塞,直到连接上有可用数据为止。您不必循环就可以等待数据出现。
具有一个简单的套接字服务器(在python3中只是为了清除语言障碍)
import socket, os, sys
addr='/tmp/a_unix_socket'
if os.path.exists(addr):
os.unlink(addr)
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.bind(addr)
sock.listen(1)
while True:
print("Waiting for connection", file=sys.stderr)
conn, client_addr = sock.accept()
data =conn.recv(128)
print("Recived {}".format(data))
conn.sendall(b'thank you')
conn.close()
我可以这样做一个golang客户:
package main
import (
"net"
"fmt"
)
func main() {
conn, err := net.Dial("unix", "/tmp/a_unix_socket")
if err != nil {
panic(err)
}
conn.Write([]byte("here is data"))
result := make([]byte, 128)
_, err = conn.Read(result)
if err != nil {
panic(err)
}
fmt.Println("Response: ", string(result))
conn.Close()
}
服务器端说:
$ python3 ./t.py
Waiting for connection
Recived b'here is data'
Waiting for connection
客户端说:
$ go run t.go
Response: thank you
net.Conn
此处未配置读取超时,因此它愿意等待尽可能长的时间。
让我也提一下:
if err != nil {
return false
}
这隐藏了无法区分的“假”响应背后的错误。在发生不可恢复的错误(假设服务器关闭连接)的情况下,客户端将无限期循环(在此过程中占用大量CPU)。如果需要公开错误,请返回它们。如果您想懒于进行概念验证,请根据需要panic()
,但不要对所有它们返回相同的结果,否则您将无法正确处理单个错误情况。在您的情况下,这是一个有争议的问题,因为无论如何您都不需要for
循环。
答案 1 :(得分:2)
是否有一种方法可以让新消息到达net.conn时通知net.conn而不是使用for循环?
否,不在标准包装中。
从net.Conn中的Read()ing循环是检测消息到达的常用方法。如果您需要执行多个并发任务,则可以将循环封装在写入通道的goroutine中,并包装for循环以及从该通道读取数据的选择。
除了标准软件包之外,您还可以使用https://github.com/tidwall/evio
等项目探索事件驱动的IO