smw*_*dia 24 networking webserver network-programming
当我们启动服务器应用程序时,我们总是需要指出它侦听的端口号.但这种"倾听机制"是如何在幕后实施的呢?
我目前的想象是这样的:
操作系统将端口号与某个缓冲区相关联.服务器应用程序的职责是监视此缓冲区.如果此缓冲区中没有数据,则服务器应用程序的侦听操作将仅阻止该应用程序.
当某些数据从线路到达时,操作系统将知道该数据,然后检查数据并查看它是否针对此端口号.然后它将填充相应的缓冲区.然后OS将通知被阻止的服务器应用程序,服务器应用程序将获取数据并继续运行.
问题是:
如果上述情况是正确的,那么操作系统怎么知道有来自电线的数据呢?它不能是繁忙的民意调查.它是某种基于中断的机制吗?
如果有太多数据到达且缓冲区不够大,是否会有数据丢失?
"监听端口"操作真的是阻塞操作吗?
非常感谢.
Mar*_*wis 19
虽然其他答案似乎正确地解释了事情,但让我给出一个更直接的答案:你的想象力是错误的.
有没有缓冲的应用程序监视.相反,应用程序在某个时刻调用listen(),并且OS从那时起就记得该应用程序对该端口号的新连接感兴趣.任何时候只有一个应用程序可以表明对某个端口的兴趣.
listen操作不会阻塞.相反,它立即返回.可能阻碍的是什么accept().系统具有积压的传入连接(缓冲已接收的数据),并在每次调用accept时返回其中一个连接.接受不传输任何数据; 然后,应用程序必须对接受的套接字执行recv()调用.
至于你的问题:
正如其他人所说:硬件中断.NIC将数据报完全从线路中断,中断,并在内存中分配一个地址以将其复制到.
对于TCP,不会有数据丢失,因为在通信期间总会有足够的内存.TCP具有流量控制,发送方将在接收方没有更多内存之前停止发送.对于UDP和新的TCP连接,可能会丢失数据; 发送方通常会得到一个错误指示(因为系统保留内存以接受另外一个数据报).
见上文:听自己不阻塞; 接受是.
listen或等效时指定队列连接数.select,poll/epoll)或异步(重叠I/O,完成端口)机制.典型的 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 网络编程的非常好的细节,并且可以提供关于这个主题的更多见解。