TCP如何在解复用中读取IP地址?

Posted

技术标签:

【中文标题】TCP如何在解复用中读取IP地址?【英文标题】:How can the TCP read the IP address in demultiplexing? 【发布时间】:2020-09-25 05:37:30 【问题描述】:

大多数计算机网络书籍解释 TCP/IP 堆栈时提到:当层收到其 PDU(无论是帧还是段...)时,请执行以下操作:

检查字段,做一些事情并决定是否将消息传递到它上面的层。 如果该层决定将消息传递给它上面的层,则上面的层将在之后再次执行相同的上一步(删除上一层标头)。

如果这是真的,那么问题就来了:TCP 如何知道源 IP 地址(在网络层标头中),该地址将用于将段移动到相应的套接字。

提前致谢!

【问题讨论】:

在 TCP 套接字的情况下,它已经与套接字关联;在 UDP 的情况下,它是要传递给应用程序的数据的一部分,因此它被提供给 UDP 层。但分层并不像某些文本暗示或陈述的那样干净利落。引擎盖下有很多偷窥。 【参考方案1】:

他们在(介绍性)教科书中关于网络堆栈中数据包遍历的内容只是教学性的。如果我们看看它是如何实现的,它会复杂得多。让我们考虑一下 Linux。

Harald Welte 的文章The journey of a packet through the Linux 2.4 network stack 总结了不同阶段的数据包遍历。

我引用文章的相关部分来回答你的问题。

    IP 数据包处理程序是通过从 net/ipv4/ip_output.c:ip_init() 调用的 net/core/dev.c:dev_add_pack() 注册的。

    IPv4 数据包处理函数是 net/ipv4/ip_input.c:ip_rcv()。经过一些初始检查(如果数据包是针对此主机的,...),将计算 ip 校验和。对长度和 IP 协议版本 4 进行了额外检查。此时,每个未通过完整性检查的数据包都将被丢弃。

    遍历成功后调用net/ipv4/ipv_input.c:ip_rcv_finish()。在 ip_rcv_finish() 内部,数据包的目的地是通过调用路由函数 net/ipv4/route.c:ip_route_input() 来确定的。此外,如果我们的 IP 数据包有 IP 选项,它们现在被处理。根据 net/ipv4/route.c:ip_route_input_slow() 做出的路由决策,我们的数据包的旅程将在以下函数之一中继续:

    net/ipv4/ip_input.c:ip_local_deliver() : 数据包的目的地是本地的,我们必须处理第 4 层协议并将其传递给用户空间进程。

    net/ipv4/ip_forward.c:ip_forward() : 数据包的目的地不是本地的,我们必须将其转发到另一个网络

    net/ipv4/route.c:ip_error() : 发生错误,我们无法为此数据包找到合适的路由表条目。

    net/ipv4/ipmr.c:ip_mr_input() : 这是一个多播数据包,我们必须做一些多播路由。

注意:一些与 Netfilter 挂钩相关的遍历阶段被跳过。所有阶段请参考原文。

net/ipv4/in_input.c:ip_local_deliver() 是我们感兴趣的函数。如前所述,它处理第 4 层协议并将其传递给用户空间。它是如何实现的可以从 Linux 内核代码中看出,简而言之,假设ip_local_deliver() 知道第 3 层细节并没有什么坏处。

【讨论】:

@IbrahimAlnefisi 由于您是社区新手,请刷新此链接someone-answers

以上是关于TCP如何在解复用中读取IP地址?的主要内容,如果未能解决你的问题,请参考以下文章

Java TCP/IP协议的Socket如何设置端口复用?

如何在 C++ 中读取 Windows 默认网关 IP 地址

如何获取 boost::asio::ip::tcp::socket 的 IP 地址?

IP 地址在哪里是 TCP 标头 - 第 3 层如何知道应用程序正在发送数据包

C#以太网上位机如何读取西门子PLC的IO点状态?

TCP / IP如何选择源IP地址[重复]