tcp双方试图同时连接

时间:2010-02-09 18:03:24

标签: sockets tcp

考虑TCP的三次握手。它解释为here

现在上面的文章提到双方可能会同时尝试连接,在这种情况下三方握手可以正常工作。

我们可以使用套接字api模拟这种情况吗? 我们通常使用套接字编码的是被动打开(服务器)和活动打开(客户端)?

3 个答案:

答案 0 :(得分:15)

可以使用套接字API同时打开TCP。正如尼古拉所提到的,这是一个执行以下序列的时间问题,使得初始SYN彼此交叉。

bind addr1, port1
connect addr2, port2
bind addr2, port2
connect addr1, port1

以下是我使用单个Linux主机实现同步打开的方法。

  1. 使用netem

    降低环回接口的速度
    tc qdisc add dev lo root handle 1:0 netem delay 5sec
    
  2. 运行netcat两次

    netcat -p 3000 127.0.0.1 2000
    netcat -p 2000 127.0.0.1 3000
    
  3. 两个netcat进程相互连接,从而产生单个TCP连接

    $ lsof -nP -c netcat -a -i # some columns removed 
    COMMAND   PID NAME
    netcat  27911 127.0.0.1:2000->127.0.0.1:3000 (ESTABLISHED)
    netcat  27912 127.0.0.1:3000->127.0.0.1:2000 (ESTABLISHED)
    

    这是tcpdump向我展示的内容(为清晰起见编辑了输出)

    127.0.0.1.2000 > 127.0.0.1.3000: Flags [S], seq 1139279069
    127.0.0.1.3000 > 127.0.0.1.2000: Flags [S], seq 1170088782
    127.0.0.1.3000 > 127.0.0.1.2000: Flags [S.], seq 1170088782, ack 1139279070
    127.0.0.1.2000 > 127.0.0.1.3000: Flags [S.], seq 1139279069, ack 1170088783
    

答案 1 :(得分:4)

作为参考,除了来自sigjuice和Nikolai的可靠答案之外,还提供一个示例,使用python可以轻松实现同步打开。在两个不同的python解释器中,执行:

>>> import socket
>>> s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s1.bind(('localhost', 1111))
>>> s1.connect(('localhost', 2222))
>>> s1.send('hello')
5
>>> s1.recv(5)
'world'

>>> import socket
>>> s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s2.bind(('localhost', 2222))
>>> s2.connect(('localhost', 1111))
>>> s2.recv(5)
'hello'
>>> s2.send('world')
5

(连接调用必须在两个绑定调用都返回后才会出现)

答案 2 :(得分:3)

我们做被动服务器和活动客户端,因为它易于理解,[相对]易于实现,并且易于编码。想想商店和顾客,我们会遇到以下情况之一:

  • 客户去商店(活跃客户端),商店是开放的(被动服务器) - 两者都很高兴。
  • 客户去商店,商店关闭(没有服务器收听) - 没有运气给客户。
  • 商店是开放的,没有顾客来 - 商店没有运气。
  • 商店关闭,没有顾客来 - 谁在乎:)

由于服务器被动地等待客户端连接,因此很容易预测何时可以进行连接。不需要预先协议(除服务器地址和端口号之外)。

另一方面,同时打开会受到双方连接超时的影响,即必须仔细协调才能进行连接,以便SYN交叉“飞行”。这是TCP协议的一个有趣的工件,但我认为它在实践中没有任何用处。

您可以尝试通过打开套接字,将其绑定到端口(以便另一方知道连接到哪里)以及尝试连接来尝试模拟此操作。双方都是对称的。可以尝试使用带有-p选项的netcat。你必须要快得多:)