dongzanghui4624
2015-10-06 22:10
浏览 1.0k
已采纳

如何在Go中查询TCP连接状态?

On the client side of a TCP connection, I am attempting to to reuse established connections as much as possible to avoid the overhead of dialing every time I need a connection. Fundamentally, it's connection pooling, although technically, my pool size just happens to be one.

I'm running into a problem in that if a connection sits idle for long enough, the other end disconnects. I've tried using something like the following to keep connections alive:

err = conn.(*net.TCPConn).SetKeepAlive(true)
if err != nil {
    fmt.Println(err)
    return
}
err = conn.(*net.TCPConn).SetKeepAlivePeriod(30*time.Second)
if err != nil {
    fmt.Println(err)
    return
}

But this isn't helping. In fact, it's causing my connections to close sooner. I'm pretty sure this is because (on a Mac) this means the connection health starts being probed after 30 seconds and then is probed at 8 times at 30 second intervals. The server side must not be supporting keepalive, so after 4 minutes and 30 seconds, the client is disconnecting.

There might be nothing I can do to keep an idle connection alive indefinitely, and that would be absolutely ok if there were some way for me to at least detect that a connection has been closed so that I can seamlessly replace it with a new one. Alas, even after reading all the docs and scouring the blogosphere for help, I can't find any way at all in go to query the state of a TCP connection.

There must be a way. Does anyone have any insight into how that can be accomplished? Many thanks in advance to anyone who does!

EDIT:

Ideally, I'd like to learn how to handle this, low-level with pure go-- without using third-party libraries to accomplish this. Of course if there is some library that does this, I don't mind being pointed in its direction so I can see how they do it.

图片转代码服务由CSDN问答提供 功能建议

在TCP连接的客户端上,我尝试重用已建立的连接,以免 每次需要连接时都要进行拨号的开销。 从根本上讲,它是连接池,尽管从技术上讲,我的池大小恰好是一个。

我遇到了一个问题,如果连接闲置了足够长的时间,另一端 断开。 我尝试使用类似以下的方法来保持连接活动:

  err = conn。(* net.TCPConn).SetKeepAlive(true)
if err!= nil {  
 fmt.Println(err)
 return 
} 
err = conn。(* net.TCPConn).SetKeepAlivePeriod(30 * time.Second)
if err!= nil {
 fmt.Println(err)\  n返回
} 
   
 
 

,但这无济于事。 实际上,这导致我的连接更快关闭。 我非常确定这是因为(在Mac上)这意味着30秒钟后开始检测连接状况,然后以30秒的间隔对8次进行检测。 服务器端一定不支持keepalive ,因此在4分30秒后,客户端将断开连接。

我可能无能为力,无法保持 闲置的连接无限期地保持活动状态,如果我可以通过某种方法至少检测某个连接已关闭,这样我就可以用一个新的连接无缝地替换它,那绝对没问题。 las,即使在阅读了所有文档并在Blogosphere上寻求帮助之后,我也无法找到任何方式来查询TCP连接的状态。

方式。 有谁对如何实现有任何见识?

编辑:

理想地,我想学习如何 使用go完全处理低级问题,而无需使用第三方库来完成此任务。 当然,如果有一些图书馆可以做到这一点,我不介意指向它的方向,这样我就可以看到他们是如何做到的。

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

2条回答 默认 最新

  • douchi1945 2015-10-08 14:48
    已采纳

    The socket api doesn't give you access to the state of the connection. You can query the current state it in various ways from the kernel (/proc/net/tcp[6] on linux for example), but that doesn't make any guarantee that further sends will succeed.

    I'm a little confused on one point here. My client is ONLY sending data. Apart from acking the packets, the server sends nothing back. Reading doesn't seem an appropriate way to determine connection status, as there's noting TO read.

    The socket API is defined such that that you detect a closed connection by a read returning 0 bytes. That's the way it works. In Go, this is translated to a Read returning io.EOF. This will usually be the fastest way to detect a broken connection.

    So am I supposed to just send and act on whatever errors occur? If so, that's a problem because I'm observing that I typically do not get any errors at all when attempting to send over a broken pipe-- which seems totally wrong

    If you look closely at how TCP works, this is the expected behavior. If the connection is closed on the remote side, then your first send will trigger an RST from the server, fully closing the local connection. You either need to read from the connection to detect the close, or if you try to send again you will get an error (assuming you've waited long enough for the packets to make a round trip), like "broken pipe" on linux.

    To clarify... I can dial, unplug an ethernet cable, and STILL send without error. The messages don't get through, obviously, but I receive no error

    If the connection is actually broken, or the server is totally unresponsive, then you're sending packets off to nowhere. The TCP stack can't tell the difference between packets that are really slow, packet loss, congestion, or a broken connection. The system needs to wait for the retransmission timeout, and retry the packet a number of times before failing. The standard configuration for retries alone can take between 13 and 30 minutes to trigger an error.

    What you can do in your code is

    • Turn on keepalive. This will notify you of a broken connection more quickly, because the idle connection is always being tested.
    • Read from the socket. Either have a concurrent Read in progress, or check for something to read first with select/poll/epoll (Go usually uses the first)
    • Set timeouts (deadlines in Go) for everything.

    If you're not expecting any data from the connection, checking for a closed connection is very easy in Go; dispatch a goroutine to read from the connection until there's an error.

    notify := make(chan error)
    
    go func() {
        buf := make([]byte, 1024)
        for {
            n, err := conn.Read(buf)
            if err != nil {
                notify <- err
                return
            }
            if n > 0 {
                fmt.Println("unexpected data: %s", buf[:n])
            }
        }
    }()
    
    点赞 打赏 评论
  • dongmuyuan3046 2015-10-06 22:56
    • There is no such thing as 'TCP connection state', by design. There is only what happens when you send something. There is no TCP API, at any level down to the silicon, that will tell you the current state of a TCP connection. You have to try to use it.

    • If you're sending keepalive probes, the server doesn't have any choice but to respond appropriately. The server doesn't even know that they are keepalives. They aren't. They are just duplicate ACKs. Supporting keepalive just means supporting sending keepalives.

    点赞 打赏 评论

相关推荐 更多相似问题