猿问

golang net.Conn 可以在有新消息时得到通知吗?

我尝试实现的

我正在实现一个客户端发送和接收 unixpackets 并与已经用 C++ 实现的服务器交互。
至此,客户端可以成功接收和向服务器发送数据包。但是我用了一个for循环,一直调用Recv看有没有新消息。

我做了什么

我实现了一个 Packet 类,以便客户端和服务器可以遵循相同的规则对消息进行编码和解码。Transport 是一个包装一个net.Conn. Client由Transport、接收Packet和发送Packet组成。
我使用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在新消息到达时通知 get 而不是使用 for 循环?


斯蒂芬大帝
浏览 148回答 2
2回答

MMTTMM

有没有一种方法可以在新消息到达 net.conn 时通知 net.conn 而不是使用 for 循环?不,不在标准包中。在循环中从 net.Conn 读取()是检测消息到达的常用方法。如果您需要执行多个并发任务,您可以将循环封装在一个写入通道的 goroutine 中,并包装一个 for 循环和 select around 从该通道读取。

一只斗牛犬

net.conn.Read自动阻塞,直到连接上的数据可用。您不必循环等待数据出现。有一个简单的套接字服务器(在 python3 中只是为了清除语言障碍)import socket, os, sysaddr='/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 mainimport (  "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.pyWaiting for connectionRecived b'here is data'Waiting for connection客户端说:$ go run t.goResponse:  thank younet.Conn此处未配置读取超时,因此它愿意等待所需的时间。我还要提一下:if err != nil {    return false}这隐藏了无区别的“错误”响应背后的错误。如果发生不可恢复的错误(比方说服务器关闭连接),您的客户端将无限期循环(在此过程中占用大量 CPU)。如果您需要暴露错误,请返回它们。如果您想偷懒进行概念验证,panic()如果必须的话,可以使用它们,但不要为所有这些返回相同的结果,否则您将无法正确处理个别错误情况。在您的情况下,这是一个有争议的问题,因为您for无论如何都不需要循环。
随时随地看视频慕课网APP

相关分类

Go
我要回答