网络通信 频道

如果没有 listen,能否建立 TCP 连接?

  在 TCP 网络通信过程中,我们都是先有 server 端调用 listen 监听某个端口号,然后 client 向 server 发起连接请求,最终建立起连接。

  那么,要是没有一端进行监听,是否可以建立起 TCP 连接呢?

  对于 TCP 来讲,一条链路的建立是通过三次握手来完成,而三次握手的过程是由内核完成的,显然三次握手应用程序是无法干扰的。

  因此我们可能会想到使用原始套接字来接收 IP 报文,通过应用层来构造三次握手报文来完成三次握手的过程,但是该方法是行不通的,因为原始套接字在收到对端的回应报文 syn+ack 报文时,系统会自动给对端回应 RST 报文中断连接。 该现象原来的文章分析过,本文不在分析。若要实现套接字的三次握手成功,需要解决系统自动回应 RST 报文,比如通过 iptable 过滤掉 RST 报文。

  在TCP的三次握手中,client 收到对端回应的 syn+ack 报文后,之所以能找到对应的套接口,是因为在 connect 时根据端口号把套接字加入到 tcp_hashinfo.ehash 的 hash 表中。而原始套接字会自动回复 RST 报文,就是没有在 hash 表中加入套接字,导致找不到套接字。

  因此我们可以得到,只要避免找不到套接字就可以完成链路的建立。所以,两端同时打开套接字也可完成链路的建立,并不需要其中一端进行 listen。

  同时连接

  测试步骤就是2台机器各自绑定一个本地地址和端口号,然后同时向对端绑定的端口发送connect 请求,具体例子不再贴出。

  在同时连接中,两端同时发送 SYN 报文而进入 SYN_SENT 状态;当每一端收到 SYN 后状态变为 SYN_RCVD, 发送 SYN 并对收到的 SYN 进行确认;当双方都收到对端的 SYN 及相应的 ACK, 状态变迁为 ESTABLISHED。状态变迁过程如下:

  以上是两端互相 connect 完成链路的建立,若要去掉两端,我们也可以实现connect 本端绑定的IP和端口号。

  使用 nc 测试一个 自己连接自己的 TCP 连接

  上述可以看到源端口号等于目的端口号,并且也完成链路的建立。

  从跟踪结果来看,自己连接自己(公用同一个socket)完成了链路的建立。

  自己连接自己只是同时连接中的一个特例。

0
相关文章