问题:客户端需要创建tcp连接,如果由于某种原因连接断开,则需要重新连接,也可以随时要求断开连接。
服务器不在我手中,连接上没有数据发送,只需要建立连接即可。
我使用TCP的实现保持有效,我遵循了https://thenotexpert.com/golang-tcp-keepalive/
func (s *State) spawnCtrlConnection() (quit chan struct{}) {
quit = make(chan struct{}, 1)
go func(addr string) {
tcpAddr, err := net.ResolveTCPAddr("tcp", s.addr())
if err != nil {
s.HandleError(err)
return
}
conn, err := net.DialTCP("tcp", nil, tcpAddr)
if err != nil {
s.HandleError(err)
return
}
defer func() {
conn.Close()
}()
conn.SetKeepAlive(true)
conn.SetKeepAlivePeriod(time.Second * time.Duration(s.WaitInterval))
rawConn, err := conn.SyscallConn()
if err != nil {
s.HandleError(err)
return
}
rawConn.Control(
func(fdPtr uintptr) {
fd := int(fdPtr)
// Ping amount
err = syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPCNT, s.PingAmount)
if err != nil {
s.HandleError(err)
return
}
// Retry interval
err = syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, s.RetryInterval)
if err != nil {
s.HandleError(err)
return
}
})
for {
select {
case <-quit:
return
default:
data := make([]byte, 1)
_, err = conn.Read(data)
// it blocks here forever and (<- quit will never receive anything)
// setting explicit timeout doesn't help either, as it will timeout for obvious reason
// conn.SetDeadline(time.Now().Add(time.Second * time.Duration(s.WaitInterval)))
// if err != nil {
// if err, ok := err.(net.Error); ok && err.Timeout() {
// fmt.Println("timeout", err.Error())
// } else {
// fmt.Println("I am here", err.Error())
// }
// }
// WHAT SHOULD I CODE
}
}
}()
return
}
我不明白,我应该编写什么代码来检测断开连接。
可能是我误解了tcp keep-alive的概念。
请帮助。
答案 0 :(得分:1)
这是建议的代码。
只要没有关闭退出,for !done
循环将在连接关闭后重新连接。
for conn != nil
循环将重复执行选择。
将SetDeadLine
放在Read
之前。当死线插入时,我们确实会收到Timeout()错误。请注意,我相信当keep alive失败时,我们也可能会超时。
func (s *State) spawnCtrlConnection() (quit chan struct{}) {
quit = make(chan struct{})
go func() {
var done bool
for !done {
// ... open connection ...
for conn != nil {
var buf [1]byte
select {
case <-quit:
conn.Close()
conn = nil
done = true
continue
default:
conn.SetDeadline(time.Now().Add(time.Duration(s.WaitInterval)*time.Second))
_, err = conn.Read(buf[:])
if err != nil {
if err == io.EOF {
conn.Close()
conn = nil
continue
}
if err, ok := err.(net.Error); ok && err.Timeout() {
continue
} else {
fmt.Println("I am here", err.Error())
}
}
}
}
}
}()
return quit
}