加入收藏 | 设为首页 | 会员中心 | 我要投稿 聊城站长网 (https://www.0635zz.com/)- 智能语音交互、行业智能、AI应用、云计算、5G!
当前位置: 首页 > 综合聚焦 > 移动互联 > 通讯 > 正文

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

发布时间:2023-07-06 11:10:47 所属栏目:通讯 来源:
导读:在 TCP 网络通信过程中,我们都是先有 server 端调用 listen 监听某个端口号,然后 client 向 server 发起连接请求,最终建立起连接。

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

对于 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 连接
 
复制
 
# nc 10.115.20.30 1234 -p 1234
 
# netstat -anp | grep 1234
 
tcp 0 0 10.115.20.30:1234 10.115.20.30:1234 ESTABLISHED 2050/nc
 
上述可以看到源端口号等于目的端口号,并且也完成链路的建立。
 
复制
 
# strace nc 10.115.20.30 1234 -p 1234
 
execve("/usr/bin/nc", ["nc", "10.115.20.30", "1234", "-p", " 1234"], [/* 31 vars */]) = 0
 
brk(NULL) = 0x23d4000
 
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f213f394000
 
...
 
munmap(0x7f213f393000, 4096) = 0
 
open("/usr/share/ncat/ca-bundle.crt", O_RDONLY) = -1 ENOENT (No such file or directory)
 
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
 
fcntl(3, F_GETFL) = 0x2 (flags O_RDWR)
 
fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
 
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
 
bind(3, {sa_family=AF_INET, sin_port=htons(1234), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
 
//bind后直接就是connect,并没有进行listen
 
connect(3, {sa_family=AF_INET, sin_port=htons(1234), sin_addr=inet_addr("10.115.20.30")}, 16) = -1 EINPROGRESS (Operation now in progress)
 
select(4, [3], [3], [3], {10, 0}) = 1 (out [3], left {9, 999998})
 
getsockopt(3, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
 
select(4, [0 3], [], [], NULL
 
从跟踪结果来看,自己连接自己(公用同一个socket)完成了链路的建立。
 
自己连接自己只是同时连接中的一个特例。
 
 

(编辑:聊城站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!