简体   繁体   English

了解 BSD 接口

[英]Understanding BSD interface

I'm trying to understand how the events in a BSD socket interface translate to the state of a TCP Connection.我试图了解 BSD 套接字接口中的事件如何转换为 TCP 连接的 state。 In particular, I'm trying to understand at what stage in the connection process accept() returns on the server side特别是,我试图了解在连接过程的哪个阶段accept()在服务器端返回

  1. client sends SYN客户端发送 SYN
  2. server sends SYN+ACK服务器发送 SYN+ACK
  3. client sends ACK客户端发送 ACK

In which one of these steps does accept() return? accept()在哪一个步骤中返回?

accept returns when the connection is complete.连接完成时accept返回。 The connection is complete after the client sends his ACK .客户端发送他的 ACK 后连接完成。

accept gives you a socket on which you can communicate. accept给你一个可以通信的套接字。 Of course you know, you can't communicate until the connection is established.当然你知道,在建立连接之前你不能通信。 And the connection can't be established before the handshake.并且在握手之前无法建立连接。

It wouldn't make sense to return before the client sens his ACK.在客户端感知到他的 ACK 之前返回是没有意义的。 It is entirely possible he won't say anything after the initial SYN.在最初的 SYN 之后,他完全有可能不会说任何话。

The TCP/IP stack code in the kernel normally[1] completes the three-way handshake entirely without intervention from any user space code. kernel 中的 TCP/IP 堆栈代码通常 [1] 完全完成三次握手,无需任何用户空间代码的干预。 The three steps you list all happen before accept() returns.您列出的三个步骤都发生accept()返回之前。 Indeed, they may happen before accept() is even called!事实上,它们可能发生在accept()甚至被调用之前!

When you tell the stack to listen() for connections on a particular TCP port, you pass a backlog parameter, which tells the kernel how many connections it can silently accept on behalf of your program at once.当您告诉堆栈为特定 TCP 端口上的连接listen()时,您传递了一个backlog参数,该参数告诉 kernel 它可以代表您的程序一次静默接受多少个连接。 It is this queue that is being used when the kernel automatically accepts new connection requests, and there that they are held until your program gets around to accept() ing them.当 kernel 自动接受新的连接请求时,正在使用这个队列,并且它们一直保留在那里,直到您的程序开始accept()它们。 When there is one or more connections in the listen backlog queue when you call accept() , all that happens is that the oldest is removed from the queue and bound to a new socket.[2]当您调用accept()时,当侦听积压队列中有一个或多个连接时,所发生的一切就是从队列中删除最旧的连接并绑定到一个新的套接字。 [2]

In other words, if your program calls listen(sd, 5) , then goes into an infinite do-nothing loop so that it never calls accept() , five concurrent client connection requests will succeed, from the clients' point of view.换句话说,如果您的程序调用listen(sd, 5) ,然后进入一个无限的无操作循环,因此它永远不会调用accept() ,从客户端的角度来看,五个并发的客户端连接请求将成功。 A sixth connection request will get stalled on the first SYN packet until either the program owning the TCP port calls accept() or one of the other clients drops its connection.第六个连接请求将在第一个 SYN 数据包上停止,直到拥有 TCP 端口的程序调用accept()或其他客户端之一断开其连接。


[1] Firewall and other stack modifications can change this behavior, of course. [1] 当然,防火墙和其他堆栈修改可以改变这种行为。 I am speaking here only of default BSD sockets stack behavior.我在这里只说默认的 BSD sockets 堆栈行为。

[2] If there are no connections waiting in the backlog when you call accept() , it blocks by default, unless the listener socket was set to non-blocking, in which case it returns -1 and errno is EWOULDBLOCK . [2] 如果在调用accept()时没有等待在 backlog 中的连接,它默认阻塞,除非侦听器套接字设置为非阻塞,在这种情况下它返回 -1 并且errnoEWOULDBLOCK

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM