英文:
rejected tcp connection does not return error
问题
我在Golang的net包上进行了一些实验。
当我使用客户端连接服务器(没有关闭连接)时,我发现服务器出现了以下错误:
"打开的文件太多"
这是有道理的,因为我的操作系统设置了文件打开限制。
然而,我发现客户端在连接服务器时从未返回错误,这很奇怪,因为服务器已经拒绝了一些连接请求。
// 服务器代码
package main
import (
"log"
"net"
)
func main() {
listener, err := net.Listen("tcp", "localhost:7070")
if err != nil {
log.Fatalln(err)
}
for {
conn, err := listener.Accept()
if err != nil {
log.Println(err, conn)
continue
}
}
}
// 客户端代码
package main
import (
"log"
"net"
)
func main() {
cnt := 0
for {
conn, err := net.Dial("tcp", "localhost:7070")
if err != nil {
log.Println("!", conn.RemoteAddr())
continue
}
cnt++
n, err := conn.Write([]byte("hello"))
if err != nil {
log.Fatalln(err)
}
log.Println(cnt, n)
}
}
有人能告诉我这里发生了什么吗?
谢谢。
英文:
I did some experiment on Golang net package.
When I use a client to connect a server (without close connections), I found that server had error like this:
"too many open files"
It makes sense because the file open limit set in my os.
However, I found that client never returned errors when connecting to server, which is weird since server had already rejected some of connection requests.
// Server code
package main
import (
"log"
"net"
)
func main() {
listener, err := net.Listen("tcp", "localhost:7070")
if err != nil {
log.Fatalln(err)
}
for {
conn, err := listener.Accept()
if err != nil {
log.Println(err, conn)
continue
}
}
}
// Client code
package main
import (
"log"
"net"
)
func main() {
cnt := 0
for {
conn, err := net.Dial("tcp", "localhost:7070")
if err != nil {
log.Println("!", conn.RemoteAddr())
continue
}
cnt++
n, err := conn.Write([]byte("hello"))
if err != nil {
log.Fatalln(err)
}
log.Println(cnt, n)
}
}
Can anyone tell me what happens here?
thx.
答案1
得分: 2
TCP握手是在服务器上由内核TCP/IP堆栈异步执行的,然后服务器应用程序才接受它,所以即使您的服务器代码无法接受连接,它也会在TCP级别上连接。这就是为什么net.Dial()成功的原因。
当您的服务器代码无法接受连接时,TCP/IP堆栈将关闭连接。
net.Write()只是将数据传递给本地TCP/IP堆栈,该堆栈将异步发送数据。如果在服务器代码有机会(无法)接受连接之前完成此操作,那么就不会出现错误,因为TCP连接仍然可用。如果您的客户端执行第二次写入,或者等待一段时间,net.Write()也应该失败。
英文:
The TCP handshake is asynchronously performed on the server by the kernel TCP/IP stack before the server application accepts it, so even if your server code fails to accept the connection, it will be connected at the TCP level. That's why the net.Dial() succeeds.
When your server code accept of the connection fails, the TCP/IP stack will close the connection though.
net.Write() just passes data onto the local TCP/IP stack, which will asynchronously send the data. If this is done before the server code has had a chance to (fail to) accept the connection, there's no error as the tcp connection is still operational. If your client perform a 2. write, or perhaps waits a bit, net.Write() should fail too.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论