php小编鱼仔今天给大家介绍一个关于"禁用 keepalive 时 io.Copy 超时"的问题。在使用Go语言中的io.Copy函数进行数据传输时,如果禁用了keepalive,可能会导致传输超时的问题。这个问题可能会给开发者带来一些困扰,因此我们需要了解一些解决方法来避免这个问题的发生。下面就让我们一起来看看如何解决这个问题吧!
问题内容
当我禁用 linux keepalive 时
sudo sysctl -w net.ipv4.tcp_keepalive_probes=0
登录后复制
并运行以下代码
package main
import (
"fmt"
"io"
"net"
"os"
"sync"
"time"
)
func main() {
go func() {
listen, err := net.Listen("tcp", "127.0.0.1:9390")
if err != nil {
fmt.Printf("net listen fail, reason: [%s]n", err.Error())
os.Exit(1)
}
defer listen.Close()
for {
conn, err := listen.Accept()
if err != nil {
fmt.Printf("net accept fail, reason: [%s]n", err.Error())
continue
}
_, err = io.Copy(conn, conn)
if err != nil {
fmt.Printf("net Copy fail, reason: [%s]n", err.Error())
continue
}
conn.Close()
}
}()
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
for {
time.Sleep(1 * time.Second)
tcpAddr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:9390")
fmt.Println("tcp client resolve success: ", tcpAddr.String())
tcpConn, err := net.DialTCP("tcp", nil, tcpAddr)
if err != nil {
fmt.Println("tcp connect fail: ", err.Error())
return
}
time.Sleep(100 * time.Second)
tcpConn.Close()
fmt.Println("tcp end")
}
}()
wg.Wait()
}
登录后复制
io.Copy 将返回“splice: 连接超时”
如果我启用 keepalive
sudo sysctl -w net.ipv4.tcp_keepalive_probes=3
登录后复制
io.Copy就可以了
我尝试tcp客户端以1秒的间隔发送数据包并禁用tcp_keepalive,也可以。
我编写了另一个代码来代替 io.Copy
buf := make([]byte, 10)
for {
conn.SetReadDeadline(time.Now().Add(30 * time.Second))
n, err := conn.Read(buf)
if err != nil {
fmt.Println("read fail: ", err.Error())
break
}
_, err = conn.Write(buf[:n])
if err != nil {
fmt.Println("write fail: ", err.Error())
break
}
}
conn.Close()
登录后复制
15秒后读取超时,30秒不工作
为什么会这样,太奇怪了?
解决方法
答案:
当“kernel tcp stack”使用keepalive检测网络时,当“kernel tcp stack”需要发送keepalive时,net.ipv4.tcp_keepalive_probes = 0将会超时
以上就是禁用 keepalive 时 io.Copy 超时的详细内容,更多请关注每日运维网(www.mryunwei.com)其它相关文章!