开发者

tcp two sides trying to connect simultaneously

开发者 https://www.devze.com 2022-12-20 03:15 出处:网络
Consider the three way handshake of TCP. It is explained here. Now the article above mentions that two sides may try to connect simultaneously and the three way handshake works fine in this case.

Consider the three way handshake of TCP. It is explained here.

Now the article above mentions that two sides may try to connect simultaneously and the three way handshake works fine in this case.

Can we simulate this situation using the sockets api. what we usuall开发者_Go百科y code using sockets is a passive open(server) and an active open(client)?


It is possible to cause a simultaneous TCP open using the sockets API. As Nikolai mentions, it is a matter of executing the following sequence with a timing such that the initial SYNs cross each other.

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

Here's how I achieved a simultaneous open using a single Linux host.

  1. Slow down the loopback interface using netem

    tc qdisc add dev lo root handle 1:0 netem delay 5sec
    
  2. Run netcat twice

    netcat -p 3000 127.0.0.1 2000
    netcat -p 2000 127.0.0.1 3000
    

The two netcat processes connect to each other resulting in a single TCP connection

$ 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)

Here's what tcpdump showed me (output edited for clarity)

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


For reference, and to provide an example in addition to the solid answers from sigjuice and Nikolai, simultaneous open can easily be achieved with python. In two different python interpreters, do:

>>> 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'

and:

>>> 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

(the connect calls must come after both bind calls have returned)


We do passive server and active client because it's easy to understand, [relatively] easy to implement, and easy to code for. Think of a store and a customer, we'd be in one of these situations:

  • Customer goes to the store (active client), the store is open (passive server) - both are happy.
  • Customer goes to the store, the store is closed (no server listening) - no luck for the customer.
  • Store is open, no customers come - no luck for the store.
  • Store is closed and no customers come - who a cares :)

Since the server passively waits for clients to connect it's easy to predict when a connection can take place. No pre-agreements (other then server address and port number) are necessary.

The simultaneous open, on the other hand, is subject to connect timeouts on both sides, i.e. this has to be carefully orchestrated for connection to take place so that SYNs cross "in-flight". It's an interesting artifact of the TCP protocol but I don't see any use for it in practice.

You can probably try simulating this by opening a socket, binding it to a port (so the other side knows where to connect to), and trying to connect. Both sides are symmetric. Can probably try that with netcat with -p option. You'd have to be pretty quick though :)

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号