为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
斯蒂芬大帝 2023-05-22 17:02:52
我尝试实现的我正在实现一个客户端发送和接收 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 urlfunc (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 Packetfunc (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 Packetfunc (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 transportfunc (c *Client) ReadFromTransport() {    for {        time.Sleep(20 * time.Millisecond)        if c.Transport.Recv(c.RecvPacket) == false {            continue        }    }}问题有没有一种方法可以net.Conn在新消息到达时通知 get 而不是使用 for 循环?
查看完整描述

2 回答

?
MMTTMM

TA贡献1869条经验 获得超4个赞

有没有一种方法可以在新消息到达 net.conn 时通知 net.conn 而不是使用 for 循环?

不,不在标准包中。

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

查看完整回答
反对 回复 2023-05-22
?
一只斗牛犬

TA贡献1784条经验 获得超2个赞

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无论如何都不需要循环。


查看完整回答
反对 回复 2023-05-22
  • 2 回答
  • 0 关注
  • 147 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信