一个人也可以建立 TCP 连接呢

今天(恰巧是今天)看到有人在 SegmentFault 上问「TCP server 为什么一个端口可以建立多个连接?」。提问者认为 client 端就不能使用相同的本地端口了。理论上来说,确定一条链路,只要五元组(源IP、源端口号、目标IP、目标端口号、协议)唯一就可以了,所以这不应该是技术限制。而实际上,Linux 3.9 之后确实可以让客户端使用相同的地址来连接不同的目标,只不过要提前跟内核说好而已。

当然,你不能使用同一个 socket,不然调用connect连接的时候会报错:


1

[Errno 106] (EISCONN) Transport endpoint is already connected

man 2 connect里说了:

Generally, connection-based protocol sockets may successfully connect() only once; connectionless protocol sockets may use connect() multiple times to change their association.

想也是,一个 socket 连接到多个目标,那发送的时候到底发给谁呢?TCP 又不像 UDP 那样无状态的,以前做过什么根本不管。

那用多个 socket 就可以了嘛。服务端其实也一直是用多个 socket 来处理多个连接的不是么,每次accept都生成个新的 socket。


1

2

3

4

5

6

7

8

9

10

11

>>> import socket

>>> s = socket.socket()

# since Linux 3.9, 见 man 7 socket

>>> s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)

>>> s2 = socket.socket()

>>> s2.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)

>>> s.bind((‘127.0.0.1‘, 12345))

>>> s2.bind((‘127.0.0.1‘, 12345))

# 都可以使用同一本地地址来连接哦

>>> s.connect((‘127.0.0.1‘, 80))

>>> s2.connect((‘127.0.0.1‘, 4321))

连上去之后 netstat 的输出(4568 进程是上边这个程序,另两个进程一个是 nginx,另一个是我的另一个 Python 程序):


1

2

3

4

5

6

7

>>> netstat -npt | grep 12345

(Not all processes could be identified, non-owned process info

 will not be shown, you would have to be root to see it all.)

tcp        0      0 127.0.0.1:4321          127.0.0.1:12345         ESTABLISHED 18284/python3

tcp        0      0 127.0.0.1:12345         127.0.0.1:4321          ESTABLISHED 4568/python3

tcp        0      0 127.0.0.1:80            127.0.0.1:12345         ESTABLISHED -

tcp        0      0 127.0.0.1:12345         127.0.0.1:80            ESTABLISHED 4568/python3

当然你要是连接相同的地址会报错的:


1

OSError: [Errno 99] Cannot assign requested address

那个五元组已经被占用啦。

同时创建连接:恰巧你也在这里

有时候,我们不能一个劲地等待。主动出击也是可以的,即便对方并没有在等待。

这个在 TCP 里叫「simultaneous open」,用于 TCP 打洞。但是比起 UDP 打洞难多了,因为那个「simultaneous」字眼:必须同时调用connect,双方的 SYN 包要交叉,早了或者晚了都是会被拒绝的。

所以手工就办不到啦,在本地测试也不容易办到。我本地的系统时间是使用 NTP 同步的,再用一个时钟也和 NTP 同步的 VPS 就可以啦,我这里延迟 80ms 左右,足够那两个 SYN 「在空中会面」了。以下是代码:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

#!/usr/bin/env python3

import time

import sys

import socket

import datetime

def wait_until(t):

  deadline = t.timestamp()

  to_wait = deadline - time.time()

  time.sleep(to_wait)

s = socket.socket()

s.bind((‘‘, 1314))

if sys.argv[1] == ‘local‘:

  ip = ‘VPS 的地址‘

else:

  ip = ‘我的地址‘

t = datetime.datetime(2015, 8, 19, 22, 14, 30)

wait_until(t)

s.connect((ip, 1314))

s.send(b‘I love you.‘)

print(s.recv(1024))

当然,我是公网 IP。在内网里包就不容易进来啦。

然后双方在约定的时间之前跑起来即可,结果是这样子的:


1

2

3

4

5

6

7

# 本地

>>> python3 t.py local

b‘I love you.‘

# VPS 上

>>> python3 t.py remote

b‘I love you.‘

一个人也可以建立 TCP 连接呢

如果你没有 VPS,或者没有公网 IP,也是有活动可以参与的哦。即使只有一个 socket,也可以自己连接到自己的:


1

2

3

4

5

6

7

8

>>> import socket                                                              

>>> s = socket.socket()

>>> s.bind((‘127.0.0.1‘, 1314))

>>> s.connect((‘127.0.0.1‘, 1314))

>>> s.send(b‘I love you.‘)

11

>>> s.recv(1024)

b‘I love you.‘

netstat 输出:


1

2

>>> netstat -npt | grep 1314

tcp        0      0 127.0.0.1:1314          127.0.0.1:1314          ESTABLISHED 8050/python 

时间: 2024-09-29 20:46:40

一个人也可以建立 TCP 连接呢的相关文章

通过UDP建立TCP连接

解释 通过UDP广播查询服务器的IP地址,然后再建立TCP点对点连接. 应用场景 在服务器IP未知时,并且已知服务器与客户端明确在一个局域网或者允许组播的子网下. 通过UDP发现服务器地址然后再进行TCP连接. (PS:万维网很多路由器对组播进行了限制,所以不能通过UDP报文在万维网上进行服务器查询) 主要问题 Android真机和模拟器对组播处理不同 Android不同系统版本对组播处理不同 不同网络对组播有限制,如部分路由网络限制UDP报文 简单实现 传统组播方式,通过255.255.255

图说使用socket建立TCP连接

在网络应用如火如荼的今天,熟悉TCP/IP网络编程,那是最好不过.如果你并不非常熟悉,不妨花几分钟读一读. 为了帮助快速理解,先上个图,典型的使用socket建立和使用TCP/UDP连接过程为(截图来源戳这里): 下面仅讲述TCP连接建立的过程. (参考资料来自这里) 1. Initial State (初始阶段) o TCP is connection based, ... establishing it is a complex multistage process o initially

python 批量执行脚本(服务端和客户端建立TCP连接)

有很多开源的批量部署的工具可以使用,比如puppet, ansible , saltstack , chef . 但这些工具都有自己的一套语法规则,你得按照他的语法来编写程序,然后批量执行. 那有没有方法可以直接写bash 或者Python脚本,然后批量执行呢? 方法当然是有的,需要自己写程序来传输脚本,拷贝文件,再复杂点,可以自定义脚本式同步还是异步执行,自定义要执行的主机组,等等,需要根据自己的业务需要来想. 这里只是抛砖引玉,我采用建立socket(TCP)连接来批量执行脚本. 服务端脚本

建立TCP连接的三次握手

请求端(通常称为客户)发送一个 SYN 报文段( SYN 为 1 )指明客户打算连接的服务器的端口,以及初始顺序号( ISN ).服务器发回包含服务器的初始顺序号( ISN )的 SYN 报文段( SYN 为 1 )作为应答.同时,将确认号设置为客户的 ISN 加 1 以对客户的 SYN 报文段进行确认( ACK 也为 1 ).客户必须将确认号设置为服务器的 ISN 加 1 以对服务器的 SYN 报文段进行确认( ACK 为 1 ),该报文通知目的主机双方已完成连接建立. 三次握手协议可以完成两

建立TCP连接过程

1.服务器实例化一个ServerSocket 对象, 表示通过服务器上的端口通信. ServerSocket serverSocket = new ServerSocket(port); 2.服务器调用ServerSocket的Accept方法,该方法一直等待直到客户端连接到服务器上给定的端口. Socket server = serverSocket.accept(); 3.服务器正在等待时,客户端实例化一个Socket对象, 指定服务器名称和端口号来请求连接. Socket client =

客户端与服务端建立tcp连接三次握手之前做了什么----DNS

操作系统在握手之前进行了DNS查询   DNS 迭代查询 1.操作系统会首先在本地缓存中查询IP 2.没有的话会去系统配置的DNS服务中去查询 3.如果这时候还没得话,会直接去 DNS 根服务器查询,这一步查询会找出负责 com 这个一级域名的服务器 4.然后去该服务器查询 google 这个二级域名 5.接下来三级域名的查询其实是我们配置的,你可以给 www 这个域名配置一个 IP,然后还可以给别的三级域名配置一个 IP PS:DNS 是基于 UDP 做的查询, 原文地址:https://ww

TCP server 为什么一个端口可以建立多个连接?

https://segmentfault.com/q/1010000003101541 如果是tcp client用同一个本地端口去连不同的两个服务器ip,连第二个时就会提示端口已被占用.但服务器的监听端口,可以accept多次,建立多个socket:我的问题是服务器一个端口为什么能建立多个连接而客户端却不行呢? 2015年08月16日提问 评论 邀请回答 编辑 更多 默认排序时间排序 5个回答 答案对人有帮助,有参考价值8答案没帮助,是错误的答案,答非所问 已采纳 TCP server 可以,

TCP连接的三路握手

本文内容参考<Unix网络编程>,大概描述了TCP连接的三次握手过程,这是我看到的最清楚的描述,记录在这里,希望能帮助到大家对于TCP连接过程的理解. 传输控制协议(TCP)是TCP/IP协议簇里非常重要的一个协议.它提供客户与服务器之间的连接,并且提供可靠的数据传输功能.关于这个协议的具体规定,请参考相关文献.这里简单讲述一下三路握手. 建立一个TCP连接时会发生以下几个过程: 1.服务器必须做好接受外来的连接的准备.这个过程通过调用socket.bind和listen这三个函数来完成. 2

TCP连接的建立与终止

我们通过一个例子来说说TCP连接的建立与断开: 在这个例子中,客户端发起连接,发送请求,服务端响应请求,然后客户端主动关闭连接. 建立连接的过程: 1.客户端发出段1,SYN表示连接请求,如图中所示,序号是1000,每发送一个数据字节,这个序号就要加1,这样在接收端可以根据序号排出数据包的正确顺序,也可以发现丢包的情况,SYN和FIN位也要占一个序号,从第一段可以看出,这次发送的数据是0(即没有发送数据),但是由于SYN要占一位,因此下次发送数据要从1001开始.mss表示最大段尺寸,如果一个段