英文:
How can I make net.Read wait for input in golang?
问题
所以我正在用Go为我的电梯制作一个服务器,并且我正在使用TCP连接作为一个goroutine运行函数“handler”。
我希望它从连接中读取数据,如果在一定的时间内没有检测到信号,我希望它返回一个错误。
func handler(conn net.Conn){
conn.SetReadTimeout(5e9)
for{
data := make([]byte, 512)
_,err := conn.Read(data)
}
}
只要我有一个客户端通过连接发送数据,它似乎工作得很好,但是一旦客户端停止发送,net.Read函数就会返回错误EOF,并且没有任何延迟开始循环。
这可能是Read函数应该工作的方式,但是有人能否建议另一种处理该问题的方法,而不必每次想读取东西时都关闭和打开连接?
英文:
So I'm making a server for my elevator in Go, and I'm running the function "handler" as a goroutine with a TCP-connection.
I want it to read from a connection, and if no signal is detected within a certain timespan I want it to return an error.
func handler(conn net.Conn){
conn.SetReadTimeout(5e9)
for{
data := make([]byte, 512)
_,err := conn.Read(data)
}
}
As long as I have a client sending stuff over the connection it seems to be working fine, but as soon as the client stops sending the net.Read function returns the error EOF and starts looping with no delay whatsoever.
This might be how Read is supposed to work, but could someone suggest another way to handle the problem without having to close and open the connection every time I want to read something?
答案1
得分: 21
Read正常工作,我认为。听起来你想让net.Read像Go中的通道一样工作。在Go中,这很容易,只需将net.Read包装在一个运行的goroutine中,并使用select从通道中读取。goroutine非常廉价,通道也是如此。
示例:
ch := make(chan []byte)
eCh := make(chan error)
// 启动一个goroutine来从我们的网络连接中读取数据
go func(ch chan []byte, eCh chan error) {
for {
// 尝试读取数据
data := make([]byte, 512)
_,err := conn.Read(data)
if err != nil {
// 如果遇到错误,则发送错误
eCh<- err
return
}
// 如果读取到数据,则发送数据
ch<- data
}
}(ch, eCh)
ticker := time.Tick(time.Second)
// 不断从连接中读取数据
for {
select {
// 这个case表示我们在连接上收到了数据
case data := <-ch:
// 处理数据
// 这个case表示我们遇到了错误并且goroutine已经结束
case err := <-eCh:
// 处理错误然后退出循环
break;
// 这将在读取超时时触发
case <-ticker:
// 什么都不做?这只是为了让我们能够在需要时超时。
// 除非你想在超时时执行特定操作,否则你可能不需要将其放在这里。
}
}
英文:
Read is working as expected I think. It sounds like you want the net.Read to work like a channel in Go. This is pretty easy in go just wrap the net.Read in a running goroutine and use select to read from channels a goroutine is really cheap and so is a channel
Example:
ch := make(chan []byte)
eCh := make(chan error)
// Start a goroutine to read from our net connection
go func(ch chan []byte, eCh chan error) {
for {
// try to read the data
data := make([]byte, 512)
_,err := conn.Read(data)
if err != nil {
// send an error if it's encountered
eCh<- err
return
}
// send data if we read some.
ch<- data
}
}(ch, eCh)
ticker := time.Tick(time.Second)
// continuously read from the connection
for {
select {
// This case means we recieved data on the connection
case data := <-ch:
// Do something with the data
// This case means we got an error and the goroutine has finished
case err := <-eCh:
// handle our error then exit for loop
break;
// This will timeout on the read.
case <-ticker:
// do nothing? this is just so we can time out if we need to.
// you probably don't even need to have this here unless you want
// do something specifically on the timeout.
}
}
答案2
得分: 1
可能是因为垃圾回收器(GC)从GC的视角来看,net.Conn
变成了一个无法访问的对象,所以垃圾回收器关闭了连接的一端。为了防止这种情况发生:在客户端停止发送数据后,确保客户端连接被存储在一个可以被你的代码访问的变量中。
另一种可能是在程序的某个地方关闭了连接的一端,但你并不知道。
英文:
It is possible that the garbage collector (GC) closes one end of the connection because the net.Conn
becomes an unreachable object from GC viewpoint. In order to prevent this: after the client stops sending, make sure that the client connection is stored in a variable that is accessible by your code.
Another option is that somewhere in your program you are closing one end of the connection without knowing about it.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论