golang net.Conn 有新消息可以通知吗?
Can golang net.Conn get notified when there is a new message?
我尝试实现的
我正在实现一个发送和接收 unix 数据包并与已经用 C++ 实现的服务器交互的客户端。
至此,客户端可以成功接收和向服务器发送数据包。但是我用了一个for循环,一直调用Recv看有没有新消息
我做了什么
我实现了一个数据包class,这样客户端和服务器就可以按照相同的规则对消息进行编码和解码。 Transport 是一个包装 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
在新消息到达时得到通知而不是使用 for 循环?
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
}
这隐藏了未区分的 'false' 响应背后的错误。如果发生不可恢复的错误(假设服务器关闭连接),您的客户端将无限期循环(在此过程中消耗大量 CPU)。如果您需要公开错误,return 它们。如果你想懒惰地进行概念验证,panic()
如果必须的话,但不要 return 对所有这些结果都相同,否则你将无法正确处理个别错误情况.在您的情况下,这是一个有争议的问题,因为您无论如何都不需要 for
循环。
Is there a method to have the net.conn get notified when a new message arriving net.conn instead of using a for loop?
不,不在标准包中。
在循环中从 net.Conn 读取()是检测消息到达的常用方法。如果您需要执行多个并发任务,您可以将循环封装在写入通道的 goroutine 中,并包装一个 for 循环加上 select 围绕从该通道读取。
在标准包之外,您可以通过 https://github.com/tidwall/evio
等项目探索事件驱动的 IO
我尝试实现的
我正在实现一个发送和接收 unix 数据包并与已经用 C++ 实现的服务器交互的客户端。
至此,客户端可以成功接收和向服务器发送数据包。但是我用了一个for循环,一直调用Recv看有没有新消息
我做了什么
我实现了一个数据包class,这样客户端和服务器就可以按照相同的规则对消息进行编码和解码。 Transport 是一个包装 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
在新消息到达时得到通知而不是使用 for 循环?
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
}
这隐藏了未区分的 'false' 响应背后的错误。如果发生不可恢复的错误(假设服务器关闭连接),您的客户端将无限期循环(在此过程中消耗大量 CPU)。如果您需要公开错误,return 它们。如果你想懒惰地进行概念验证,panic()
如果必须的话,但不要 return 对所有这些结果都相同,否则你将无法正确处理个别错误情况.在您的情况下,这是一个有争议的问题,因为您无论如何都不需要 for
循环。
Is there a method to have the net.conn get notified when a new message arriving net.conn instead of using a for loop?
不,不在标准包中。
在循环中从 net.Conn 读取()是检测消息到达的常用方法。如果您需要执行多个并发任务,您可以将循环封装在写入通道的 goroutine 中,并包装一个 for 循环加上 select 围绕从该通道读取。
在标准包之外,您可以通过 https://github.com/tidwall/evio
等项目探索事件驱动的 IO