The right way to detect tcp broken connection ? Manual keepalive idle , and don't worked SetWriteDeadLine

huangapple go评论73阅读模式
英文:

The right way to detect tcp broken connection ? Manual keepalive idle , and don't worked SetWriteDeadLine

问题

我有一个关于TCP连接的问题。

我有一个用Go语言编写的服务器,它在某个端口上监听TCP连接。
我还有一个用Java编写的Android客户端。
客户端与服务器建立连接,然后在没有任何规定的情况下交换一些数据。

当Android更改网络类型时,例如从移动网络切换到WiFi,连接会中断,但服务器不知道这个问题,并认为客户端已经准备好接收一些数据。

我需要尽快在我的服务器上检测到这个问题。最理想的情况是立即检测到。

起初,我在Go语言中使用了SetKeepAlive(true)SetKeepAlivePeriod(10 * time.Second)。这个方法可以工作,但速度不够快。因为SetKeepAlivePeriod会将TCP keepalive时间(空闲时间)TCP keepalive间隔设置为相同的值。例如,在Linux中,tcp keepalive retry=8,那么在(10 + 8*10)= 90秒 = 1分30秒后才会检测到连接问题。这个速度非常非常慢:(。如何手动设置空闲时间和间隔?我看了这个库https://github.com/felixge/tcpkeepalive,但我不信任这个库,因为在这个库中,socket fd被复制而没有清除。

我可以设置SetKeepAlivePeriod(1 * time.Second),但性能如何?在我的情况下,连接可能是高负载或空闲的。

然后,我考虑使用SetWriteDeadline。这对我非常有用,因为我不知道何时从客户端接收消息,但我知道何时向客户端发送消息。但是当我使用SetWriteDeadline时,它不起作用。
例如:

var request *http.Request

conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
err := request.Write(conn)
if err != nil {
    if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
        log.Println("Connection WriteDeadline timeout")
    }
    conn.Close();
} else {
    conn.SetWriteDeadline(time.Time{})
}

当在客户端断开连接后,我向连接中写入一些数据,Write方法返回nil而没有错误。就好像数据已经发送并且服务器成功接收到了来自客户端的ACK,但是怎么可能呢?

更新 28.10.2015 22:35

我决定尝试使用这个库https://github.com/felixge/tcpkeepalive。对于我的问题,它完美地工作了:)

ka, _ := tcpkeepalive.EnableKeepAlive(conn)
ka.SetKeepAliveCount(2)
ka.SetKeepAliveInterval(3 * time.Second)
ka.SetKeepAliveIdle(10 * time.Second)
英文:

I have some problem with a TCP connection.

I have a server written in go which listen tcp connection on some port.
And I have client written in Java for Android.
Client establish connection with server, and then exchange some data both without any laws.

When Android changes the network type, for example from mobile network to wifi. Connection is broken, but server don't know about this problem, and think that client all ready to take a some data.

I need to detect this problem on my server so quick as possible. Ideally immediately

First I used in go SetKeepAlive(true) and SetKeepAlivePeriod(10 * time.Second). It's worked, but not quickly as I need. Because go SetKeepAlivePeriod, set tcp keepalive time(idle) and tcp keepalive interval to same. For example in linux tcp keepalive retry=8, then problem with connection detected after (10 + 8*10) = 90sec = 1 min 30sec. It is very very slow :(. How to set idle and interval manual ? I watching this lib https://github.com/felixge/tcpkeepalive, but I don't trust this lib, because, in this lib socket fd copying without clear.

I can set SetKeepAlivePeriod(1 * time.Second), but whats about performance ? In my case, connection may be a heavily loaded or idle.

Then, i think about SetWriteDeadline. It's very useful for me, because i don't know when i receive message from client, but i know when i send message to client. But when i used SetWriteDeadline, is not working.
For example

<!-- language-all: lang-go -->

var request *http.Request

conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
err := request.Write(conn)
if err != nil {
	if neterr, ok := err.(net.Error); ok &amp;&amp; neterr.Timeout() {
		log.Println(&quot;Connection WriteDeadline timeout&quot;)
	}
	conn.Close();
} else {
	conn.SetWriteDeadline(time.Time{})
}

When after connection broken on client, I Write some data into connection, method Write return nil without error. As though data already send and server success accepted ACK from client, but how ?

Update 28.10.2015 22:35

I decided to try this https://github.com/felixge/tcpkeepalive library. And yet it works perfectly for my problem :).

ka, _ := tcpkeepalive.EnableKeepAlive(conn)
ka.SetKeepAliveCount(2)
ka.SetKeepAliveInterval(3 * time.Second)
ka.SetKeepAliveIdle(10 * time.Second)

答案1

得分: 1

为了简化事情,请不要使用TCP级别的东西来确保您的业务会话。您真正需要的是检测中断的会话,因此在业务级别上不断发送ping-pong。您可以简单地计算负载,例如使用带有TCP头的“ping”字符串,应该是30字节。

英文:

to make thing simple, please do not use TCP level things to make sure your business session things. what you need in real is detecting broken session, so keep sending ping-pong in business level. you can calculate the load simply, like a "ping" string with tcp header, should be in 30bytes.

huangapple
  • 本文由 发表于 2015年8月27日 07:02:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/32238082.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定