当我们启动服务器应用程序时,我们总是需要指出它侦听的端口号。但这种“倾听机制”是如何在幕后实施的呢?
我目前的想象力是这样的:
操作系统将端口号与某个缓冲区相关联。服务器应用程序的职责是监视此缓冲区。如果此缓冲区中没有数据,则服务器应用程序的监听操作将仅 阻止 应用程序。
当某些数据从线路到达时,操作系统将 知道 ,然后检查数据并查看它是否以此端口号为目标。然后它将填充 对应的 缓冲区。然后操作系统将通知被阻止的服务器应用程序,服务器应用程序将获取数据并继续运行。
问题是:
如果上述情况是正确的,那么操作系统 如何知道 的数据是否来自电线?它不能是繁忙的民意调查。是某种基于中断的机制吗?
如果数据到达太多且缓冲区不够大,会否有数据丢失?
“侦听端口”操作真的是阻塞操作吗?
非常感谢。
答案 0 :(得分:16)
虽然其他答案似乎正确地解释了事情,但让我给出一个更直接的答案:你的想象力是错误的。
应用程序监视的无缓冲区。相反,应用程序在某个时刻调用listen(),并且OS从那时起就记得该应用程序对该端口号的新连接感兴趣。任何时候只有一个应用程序可以表明对某个端口的兴趣。
listen操作不阻止。相反,它立即返回。可阻止的是accept()
。系统具有积压的传入连接(缓冲已接收的数据),并在每次调用accept时返回其中一个连接。接受不传输任何数据;然后,应用程序必须对接受的套接字执行recv()调用。
关于你的问题:
正如其他人所说:硬件中断。 NIC将数据报完全从线路中断,中断,并在内存中分配一个地址以将其复制到。
对于TCP,不会有数据丢失,因为在通信过程中总会有足够的内存。 TCP具有流量控制,发送方将在接收方没有更多内存之前停止发送。对于UDP和新的TCP连接,可能会丢失数据;发件人通常会得到一个错误指示(因为系统保留内存以接受另外一个数据报)。
见上文:听本身没有阻塞;接受是。
答案 1 :(得分:7)
listen
或其等效项时,会指定到队列的连接数。select
,poll/epoll
)或异步(重叠I / O,完成端口)机制。答案 2 :(得分:3)
如果上述情况是正确的,那么操作系统如何知道从线路到达的数据?它不能是一个繁忙的池。它是某种基于中断的机制吗?
硬件通过发送事件来告诉它,硬件中断导致事件处理程序运行。
如果有太多数据到达并且缓冲区不够大,会有数据丢失吗?
是的,但TCP使用了一种窗口机制。操作系统告诉另一端它有多少缓冲区,它可以动态地执行此操作。所以它可能从我有4k的缓冲区开始。在2k到达之后,另一端可以发送2k以上,但我们可以确认前2k。如果另一端快速发送,我们的操作系统将丢弃它。它还会告诉它减速并重新确认已经有的东西。当缓冲区空闲时,我们可以告诉另一端继续它将重新发送我们尚未确认的内容。操作系统在使用TCP时为我们完成所有这些操作,但不是为UDP。
“侦听端口”操作真的是阻塞操作吗?
是但非常非常快。 听起来几乎没有,只是操作系统的一个注释。如果有人试图连接到该端口,我将负责处理它。接受等待那种联系。
操作系统不需要提前分配任何缓冲区。 Listen将一些元数据写入os表。 连接进入使用下一个连接处理缓冲区。 后来的数据进来并使用数据缓冲区,每个连接不需要分配数据缓冲区。一个连接上的大量未决数据可能会导致其他连接上的可用缓冲区减少。您的操作系统可能有政策和机制来使事情变得公平。
答案 3 :(得分:2)
What happens when we say "listen to a port"?
典型的TCP服务器调用序列是
socket() -> bind()-> listen() -> accept() -> read()/write() -> close()
由socket
函数创建的套接字被假定为活动套接字(将发出connect()
)。 listen()
函数将未连接的套接字转换为被动套接字。这意味着内核应该开始接受传入的连接请求。 listen()
函数的第二个参数指定2个队列的给定侦听套接字的总队列长度 -
(1)完成连接队列 - 完成连接的3路握手
(2)不完整的连接队列 - 从客户端收到的SYN等待3路TCP握手的完成
最后,TCP服务器调用accept()
以从完成的连接队列的前面返回下一个已完成的连接。如果accept()成功,则返回一个新的套接字描述符,该描述符引用客户端和服务器之间的TCP连接。
现在回答你的问题 *操作系统内核中的网络堆栈,读取每个传入的IP数据包,根据数据包的TCP / IP头字段对数据包进行分类。 IP数据包到达线路由以太网驱动程序作为中断提供服务,并从那里开始内核模式TCP / IP堆栈接管
对于数据,如果您的意思是SYN数据包,Posix.1g可以选择忽略新的传入SYN或在连接队列已满时向客户端发送RST。在3次握手完成之后但在服务器调用accept
之前到达的数据应该由服务器TCP排队到连接套接字的接收缓冲区的大小。
listen()
操作是一个阻塞调用,在连接状态被动为允许传入TCP客户端连接后返回。
有关TCP协议的详细信息,请参阅Wikipedia - 可靠传输的抖动,排序和确认。
这个book提供了有关TCP / IP Unix网络编程的非常好的细节,可以提供有关该主题的更多信息。