0

我最近一直在研究一些服务器-客户端代码,我发现了一个非常令人困惑的问题。我server在端口上监听并设置backlog = 2,我的客户端创建 5 个线程connect.

man中,我注意到

The backlog parameter defines the maximum length for the queue of pending
 connections.  If a connection request arrives with the queue full, the
 client may receive an error with an indication of ECONNREFUSED.  Alterna-
 tively, if the underlying protocol supports retransmission, the request
 may be ignored so that retries may succeed.

这意味着我的客户端连接将失败或稍后重试

但是当我的客户端运行时,它只是收到一个 SIGPIPE 信号并失败了。

所以我运行sudo tcpdump -ilo0 port 10000并得到结果:

summertekiMacBook-Pro:选择 Summer$ sudo tcpdump -ilo0 端口 10000

tcpdump:详细输出被抑制,使用 -v 或 -vv 进行完整的协议解码监听 lo0,链接类型 NULL(BSD 环回),捕获大小 65535 字节

10:29:16.396240 IP localhost.56347 > localhost.ndmp: 标志 [S], seq 3366561899, win 65535, options [mss 16344,nop,wscale 4,nop,nop,TS val 396158772 ecr 0,sackOK,eol],长度 0

10:29:16.396241 IP localhost.56349 > localhost.ndmp: Flags [S], seq 902832276, win 65535, options [mss 16344,nop,wscale 4,nop,nop,TS val 396158772 ecr 0,sackOK,eol],长度 0

10:29:16.396242 IP localhost.56351 > localhost.ndmp: 标志 [S], seq 1956535575, win 65535, options [mss 16344,nop,wscale 4,nop,nop,TS val 396158772 ecr 0,sackOK,eol],长度 0

10:29:16.396244 IP localhost.56348 > localhost.ndmp: Flags [S], seq 2161003109, win 65535, options [mss 16344,nop,wscale 4,nop,nop,TS val 396158772 ecr 0,sackOK,eol],长度 0

10:29:16.396246 IP localhost.56350 > localhost.ndmp: 标志 [S], seq 1318035540, win 65535, options [mss 16344,nop,wscale 4,nop,nop,TS val 396158772 ecr 0,sackOK,eol],长度 0

10:29:16.396296 IP localhost.ndmp > localhost.56347: 标志 [S.], seq 2871094527, ack 3366561900, win 65535, options [mss 16344,nop,wscale 4,nop,nop,TS val 396158772 ecr 396158872 ,eol],长度为 0

10:29:16.396307 IP localhost.ndmp > localhost.56351: 标志 [S.], seq 3931313020, ack 1956535576, win 65535, options [mss 16344,nop,wscale 4,nop,nop,TS val 396158772 ecr 396158872 ,eol],长度为 0

10:29:16.396332 IP localhost.ndmp > localhost.56349: 标志 [S.], seq 3467781056, ack 902832277, win 65535, options [mss 16344,nop,wscale 4,nop,nop,TS val 396158772 ecr 396158772, ,eol],长度为 0

10:29:16.396349 IP localhost.ndmp > localhost.56348: 标志 [S.], seq 2666080832, ack 2161003110, win 65535, options [mss 16344,nop,wscale 4,nop,nop,TS val 396158772 ecr 396158872 ,eol],长度为 0

10:29:16.396366 IP localhost.ndmp > localhost.56350: 标志 [S.], seq 2467582351, ack 1318035541, win 65535, options [mss 16344,nop,wscale 4,nop,nop,TS val 396158772 ecr 396158872 ,eol],长度为 0

10:29:16.396375 IP localhost.56347 > localhost.ndmp: 标志 [.], ack 1, win 9186, 选项 [nop,nop,TS val 396158772 ecr 396158772], 长度 0

10:29:16.396381 IP localhost.56351 > localhost.ndmp: 标志 [.], ack 1, win 9186, 选项 [nop,nop,TS val 396158772 ecr 396158772], 长度 0

10:29:16.396386 IP localhost.56349 > localhost.ndmp: 标志 [.], ack 1, win 9186, options [nop,nop,TS val 396158772 ecr 396158772], 长度 0

10:29:16.396391 IP localhost.56348 > localhost.ndmp: 标志 [.], ack 1, win 9186, 选项 [nop,nop,TS val 396158772 ecr 396158772], 长度 0

10:29:16.396398 IP localhost.56350 > localhost.ndmp: 标志 [.], ack 1, win 9186, options [nop,nop,TS val 396158772 ecr 396158772], 长度 0

10:29:16.396408 IP localhost.ndmp > localhost.56347: 标志 [R], seq 2871094528, win 0, length 0

10:29:16.396413 IP localhost.ndmp > localhost.56351: 标志 [R], seq 3931313021, win 0, length 0

10:29:16.396419 IP localhost.56347 > localhost.ndmp: 标志 [P.], seq 1:1001, ack 1, win 9186, options [nop,nop,TS val 396158772 ecr 396158772], 长度 1000

10:29:16.396424 IP localhost.56351 > localhost.ndmp: 标志 [P.], seq 1:1001, ack 1, win 9186, options [nop,nop,TS val 396158772 ecr 396158772], 长度 1000

10:29:16.396429 IP localhost.ndmp > localhost.56349: 标志 [.], ack 1, win 9186, options [nop,nop,TS val 396158772 ecr 396158772], 长度 0 10:29:16.396435 IP localhost.ndmp > localhost.56348:标志 [R],seq 2666080833,win 0,长度 0

10:29:16.396441 IP localhost.ndmp > localhost.56350:标志 [.],ack 1,win 9186,选项 [nop,nop,TS val 396158772 ecr 396158772],长度 0

10:29:16.396454 IP localhost.ndmp > localhost.56347: 标志 [R], seq 2871094528, win 0, length 0

10:29:16.396460 IP localhost.ndmp > localhost.56351: 标志 [R], seq 3931313021, win 0, length 0

unix 网络编程connect()将启动3 次握手程序,并在服务器发送syn && ack时返回。

tcpdump输出中,前 10 行告诉服务器回复 syn & sck 虽然积压为 2。后来,客户端发送最后一次 ack和服务器返回 rst

在我看来,连接返回值!= -1 表示连接已建立并且客户端能够发送数据。但是上面的日志显示它不是那样工作的。

那么谁能告诉我哪个是正确的?

4

2 回答 2

2

最后,在花时间谷歌搜索之后,我得到了对上面行为显示的解释。

我检查了linux手册,它显示:

笔记

TCP 套接字上 backlog 参数的行为在 Linux 2.2 中发生了变化。现在它指定完全建立的等待被接受的套接字的队列长度而不是不完整的连接请求的数量。可以使用 /proc/sys/net/ipv4/tcp_max_syn_backlog 设置不完整套接字队列的最大长度。当 syncookies 被启用时,没有逻辑上的最大长度并且这个设置被忽略。有关详细信息,请参阅 tcp(7)。

而且,在freebsd手册中(osx的手册没有给出任何细节,但是因为两个操作系统都是基于bsd的^.^):

请注意,在 FreeBSD 4.5和同步缓存的引入之前,积压参数还决定了不完整连接队列的长度,该队列在完成 TCP 的 3 次握手过程中持有 TCP 套接字。这些不完整的连接现在完全保存同步缓存中,不受队列长度的影响。不再需要增加积压值来帮助处理拒绝服务攻击。

总之,改变 backlog 行为的原因似乎是为了保护服务免受syn flood 攻击

于 2013-10-31T16:05:31.910 回答
0

当您尝试在损坏/关闭的管道上发送数据时,您会收到 SIGPIPE 信号。根据您的 tcpdump 数据和您的解释:

  • 从 5 个不同的客户端端口 (56347-56351) 正确建立了所有 5 个 TCP 连接(使用 3 次握手)。
  • 然后服务器在端口 47 和 51 的连接中发送一个 Reset。这会破坏管道。
  • 几乎同时,数据从端口 47 和 51(在客户端)发送([P],推送)到服务器。当内核决定时,这些数据可能已经在套接字发送缓冲区中准备发送。稍后服务器再次使用 Reset [R] 响应,但这并没有改变任何东西。
  • 实际上你 tcpdump 中的最后 4 行并不影响这个解释。

连接实际上在您的客户端程序中返回了 OK。我敢肯定,因为所有连接都已建立,3 次握手完成。问题是,在那之后您立即尝试发送数据,我敢打赌您会尝试在每个套接字中多次发送数据。我假设每个线程处理一个套接字。第二次或第三次(或更多)线程尝试在端口 56347 或 56351 的套接字上发送数据时,由于已从服务器接收到 RESET,因此管道中断,并且操作系统将向进程发送信号 SIGPIPE。

听积压似乎在您的服务器上工作正常。似乎 3 个连接被正确处理,只有 2 个被拒绝。可能服务器处理第一个连接的速度足够快,可以为积压中的下一个 2 留出位置。最后两个未能成功,因为积压太小(2)。

于 2013-10-28T19:41:01.880 回答