【问题标题】:unix network processunix 网络进程
【发布时间】:2009-10-09 16:58:52
【问题描述】:

我想知道如何在 unix 中实现 tcp/ip 通信。当您通过套接字进行发送时,tcp/level 工作(组装数据包、crc 等)是否在与调用代码相同的执行上下文中执行?

或者,似乎更有可能的是,一条消息被发送到其他负责 tcp 通信的守护进程?这个过程然后接收消息并执行复制内存缓冲区和组装数据包等请求的工作?那么,调用代码会立即恢复执行,并且 tcp 工作是并行完成的吗?这是正确的吗?

详细信息将不胜感激。谢谢!

【问题讨论】:

    标签: unix networking tcp


    【解决方案1】:

    TCP/IP stack 是您的kernel 的一部分。发生的情况是您调用了一个准备“kernel trap”的辅助方法。这是一种特殊的异常,它将 CPU 置于具有更多特权的模式(“内核模式”)。在陷阱内部,内核检查异常的参数。其中之一是要调用的函数的编号。

    调用该函数时,它会将数据复制到内核缓冲区中,并为要处理的数据做好一切准备。然后它从陷阱中返回,CPU 恢复寄存器并恢复其原始模式并继续执行代码。

    某些内核thread 会拾取数据的副本并使用网络驱动程序将其发送出去,进行所有的错误处理等。

    所以,是的,在复制必要的数据后,您的代码会恢复,实际的数据传输会并行发生。

    请注意,这是针对 TCP 数据包的。 TCP 协议为您完成所有错误处理和握手,因此您可以将所有数据提供给它,它会知道该怎么做。如果连接出现问题,您会在一段时间后注意到,因为 TCP 协议可以自行处理短暂的网络中断。这意味着在出现错误之前,您已经“发送”了一些数据。这意味着只有在第 N 次调用 send() 或尝试关闭连接时,您才会收到第一个数据包的错误代码(close() 将挂起,直到接收方确认所有数据包)。

    UDP 协议不缓冲。当呼叫返回时,数据包正在发送中。但它是“一劳永逸”,所以你只知道司机把它放在了电线上。如果你想知道它是否已经到达某个地方,你必须自己想办法实现它。通常的方法是让接收方发回一个 ack UDP 数据包(也可能会丢失)。

    【讨论】:

      【解决方案2】:

      否 - 没有并行执行。确实,进行系统调用时的执行上下文与通常的执行上下文不同。当您进行系统调用时,例如通过网络发送数据包,您必须切换到内核的上下文 - 内核自己的内存映射和堆栈,而不是您在进程中获得的虚拟内存。

      但是没有守护进程神奇地调度您的呼叫。程序的其余执行必须等待系统调用完成并返回它将返回的任何值。这就是为什么当您从系统调用返回时,您可以指望返回值立即可用 - 值如实际从套接字读取或写入文件的字节数。

      我试图为上下文切换到内核空间的工作原理找到一个很好的解释。这是一个很好的深入研究,甚至专注于特定于架构的实现:

      http://www.ibm.com/developerworks/linux/library/l-system-calls/

      【讨论】:

      • 虽然对send() 的调用不会立即返回,但它会在数据出现在线之前返回。所以它确实与应用代码的执行并行发送。
      • 嗯,好点子,亚伦。我想答案是:这很复杂。有些工作肯定会立即发生,有些工作会在以后发生,与您自己的代码并行。所以我明确的“不”是错误的。
      • @Igor 目前正在阅读 Richard W. Stevens 的“unix 网络编程”,我只同意 Aaron 的回答。内核为您(为您的应用程序)执行所有 TCP 工作,例如在超时后重新发送未确认的 paquet;让我们更进一步:同时,如果达到完整的 TCP 窗口大小,则应用程序对 send() 的所有新调用实际上可能会缓冲数据。 (我可能不完全正确,我自己不是 tcp 大师,但想法就在这里..) -1.
      猜你喜欢
      • 1970-01-01
      • 2015-09-12
      • 2021-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多