当我们说"听一个港口"时会发生什么?

smw*_*dia 24 networking webserver network-programming

当我们启动服务器应用程序时,我们总是需要指出它侦听的端口号.但这种"倾听机制"是如何在幕后实施的呢?

我目前的想象是这样的:

操作系统将端口号与某个缓冲区相关联.服务器应用程序的职责是监视此缓冲区.如果此缓冲区中没有数据,则服务器应用程序的侦听操作将仅阻止该应用程序.

当某些数据从线路到达时,操作系统将知道该数据,然后检查数据并查看它是否针对此端口号.然后它将填充相应的缓冲区.然后OS将通知被阻止的服务器应用程序,服务器应用程序将获取数据并继续运行.

问题是:

  • 如果上述情况是正确的,那么操作系统怎么知道有来自电线的数据呢?它不能是繁忙的民意调查.它是某种基于中断的机制吗?

  • 如果有太多数据到达且缓冲区不够大,是否会有数据丢失?

  • "监听端口"操作真的是阻塞操作吗?

非常感谢.

Mar*_*wis 19

虽然其他答案似乎正确地解释了事情,但让我给出一个更直接的答案:你的想象力是错误的.

没有缓冲的应用程序监视.相反,应用程序在某个时刻调用listen(),并且OS从那时起就记得该应用程序对该端口号的新连接感兴趣.任何时候只有一个应用程序可以表明对某个端口的兴趣.

listen操作不会阻塞.相反,它立即返回.可能阻碍的是什么accept().系统具有积压的传入连接(缓冲已接收的数据),并在每次调用accept时返回其中一个连接.接受不传输任何数据; 然后,应用程序必须对接受的套接字执行recv()调用.

至于你的问题:

  • 正如其他人所说:硬件中断.NIC将数据报完全从线路中断,中断,并在内存中分配一个地址以将其复制到.

  • 对于TCP,不会有数据丢失,因为在通信期间总会有足够的内存.TCP具有流量控制,发送方将在接收方没有更多内存之前停止发送.对于UDP和新的TCP连接,可能会丢失数据; 发送方通常会得到一个错误指示(因为系统保留内存以接受另外一个数据报).

  • 见上文:听自己不阻塞; 接受是.

  • 在TCP服务器端,当您说“ listen()立即返回”时,这意味着“ listen()”会调用“ sys_listen()”,后者会在内部在“ TCP_listen()”上启动内核线程,然后返回。`accept()`将通过`wait()`操作在sys_accept()上阻塞。在客户端,`connect()-> sys_connect()调用与服务器的TCP_listen()进行三向握手的TCP_connect()。成功握手后,被阻塞的sys_accept()将解除阻塞并调用TCP_accept()以创建一个新的数据套接字,并退出accept()调用。在失败握手时,sys_accept()将解除阻塞并调用TCP_deny()。 (2认同)

Ant*_*hyy 7

  1. 除了阻塞部分,您的描述基本上是正确的.操作系统通常使用中断来处理I/O事件,如到达网络数据包,因此无需阻止.
  2. 是的,如果同时发生太多连接尝试,有些会被反弹.调用listen或等效时指定队列连接数.
  3. 不它不是.当连接到达时,操作系统会在控制套接字上引发一个事件.您可以选择在等待此事件时阻止,或者您可以使用某些非阻塞(select,poll/epoll)或异步(重叠I/O,完成端口)机制.

  • @smwikipedia这是一个硬件中断.NIC包含几个数据包过滤器,用于监视有关嵌入式MAC和IPV4地址的传入数据包(所谓的数据报).这些过滤器主要在硬件状态机或专用处理器中实现(匹配这些字段不是一项复杂的任务,但它在通用处理器上执行不良).当NIC收到具有匹配的IPV4地址(ip.dest == nic.ip,或ip.dest == multicast/broadcast)或匹配的MAC地址的数据报时,会触发中断. (4认同)
  • 当然是硬件中断.NIC比你描述的要复杂一些 - 它们处理以太网级和部分IP/TCP级处理(这称为卸载) - 但基本上OS为NIC分配缓冲区以便通过DMA/busmaster和NIC写入传入的数据包数据包到达时会引发中断.发送数据的排列方式类似:OS维护一个描述要发送的数据包的缓冲区队列,NIC处理此队列并在队列变空时引发中断.所有现代I/O控制器(总线主控模式下的USB,IDE/SATA)工作方式基本相同. (4认同)
  • 谢谢安东.中断是有道理的.那么它是软件还是硬件中断?如果是软件中断,则必须通过某段代码引发中断,并且此代码需要知道数据何时到达.所以它基本上回到了我原来的问题 - 繁忙的汇集或什么.如果是硬件中断,则必须设计NIC(网络接口卡),以便在从线路检测到某些信号时,它将会切换CPU.中断信号可以通过8259芯片或类似的东西.如果我错了,请纠正我.任何评论都表示赞赏. (2认同)

Nee*_*era 5

当我们说“监听端口”时会发生什么?

典型的 TCP 服务器调用序列是

socket() -> bind()-> listen() -> accept() -> read()/write() -> close()
Run Code Online (Sandbox Code Playgroud)

socket函数创建的套接字被假定为活动套接字(将发出connect())。listen()函数将未连接的套接字转换为被动套接字。这意味着内核应该开始接受传入的连接请求。listen()函数的第二个参数指定给定的 2 个队列的监听套接字的总队列长度 - (1) 完整的连接队列 - 为连接完成的 3 路握手 (2) 不完整的连接队列 - 从客户端收到的 SYN 等待 3 路 TCP 的完成握手

最后accept()由 TCP 服务器调用,从完成连接队列的前端返回下一个完成的连接。如果 accept() 成功,它将返回一个新的套接字描述符,该描述符引用客户端和服务器之间的 TCP 连接。

现在回答您的问题 * 操作系统内核中的网络堆栈读取每个传入的 IP 数据包,根据其 TCP/IP 标头字段对数据包进行分类。网络上的 IP 数据包的到达由以太网驱动程序作为中断提供服务,然后内核模式 TCP/IP 堆栈接管

  • 对于数据,如果您指的是 SYN 数据包,则 Posix.1g 可以选择忽略新传入的 SYN 或在连接队列已满时向客户端发送 RST。在 3 次握手完成后到达的数据,但在服务器调用之前accept应该由服务器 TCP 排队,直到连接套接字的接收缓冲区的大小。

  • listen() 操作是一个阻塞调用,并在连接状态被称为被动以允许传入的 TCP 客户端连接后返回。

有关 TCP 协议的更多详细信息,请参阅维基百科 -可靠传输的握手、排序和确认。

本书 提供了关于 TCP/IP Unix 网络编程的非常好的细节,并且可以提供关于这个主题的更多见解。