拒绝的 TCP 连接不会返回错误。

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

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.

huangapple
  • 本文由 发表于 2014年5月9日 17:25:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/23561040.html
匿名

发表评论

匿名网友

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

确定