When communication occurs, in addition to the situation that one end of the communication initiates a communication request and the other end waits passively, there may be the situation that both endpoints of the communication have the intention of communication and both ends initiate a request to each other. When the communication behavior ends, the same situation exists. Both sides have no data to send to each other and finish communication at the same time. TCP supports this communication connection to be established and closed at the same time. When do the simultaneous connection creation and shutdown occur? Is it different from normal procedure? This article simulates and reproduces this kind of TCP connections and do some analysis in detail.
Simutaneous Connection Creation
The communication mode of most TCP is that a process passively listens on TCP port, waits for client process to send connection request actively, and provides service for client process. What if two processes simultaneously make TCP connection requests to each other? Since both ends are intended to connect to each other, the TCP layer as a transport layer has no reason to prevent both ends from connecting. The TCP protocol supports connection creation when both sides make a request at the same time, when both processes are both clients and servers. Note that setting up a connection at both ends is completely different from cross-linking two servers running on two hosts with two clients running on both hosts.
The sequence
When two processes establish a TCP connection at the same time, the connection establishment procedure is different from the three way handshakes that the client and server make a connection. The sequence the simultaneous connection process is as follows, and the client and server are not distinguished here. The difference between the three way handshakes established with a normal connection is that when both ends of the established connection expect an ACK acknowledgement of [1.syn], they receive a SYN request from [IP address, TCP port number].
The example
There are many ways to implement a simultaneous connection, and the core idea is to ensure that after the SYN segment at both ends is sent, it receives not ACK segment or RST segment, but SYN segment from the other endpoint.
Code
Both sides can follow the client code and add the part specifying the client port number and the service port number. 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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
int main(int argc, char **argv)
{
//初始化工作
int sockfd = 0; //Client进程的Socket文件描述符
int dstport = 0; //Server进程监听TCP端口号
int srcport = 0; //Client进程指定本地TCP端口号
char response[MAXLINE + 1]; //Server进程返回的响应内容
char request[] = "request,hostname\r\n"; //Client进程发出的请求消息
struct sockaddr_in servaddr; //用于存储Server进程所在主机的IP地址及TCP端口号
bzero(&servaddr, sizeof(servaddr));
bzero(response, MAXLINE + 1);
//设置将要连接服务器进程的IP地址和TCP端口号
sscanf(argv[3], "%d", &dstport);
servaddr.sin_family = AF_INET;
Inet_pton(AF_INET, argv[2], &servaddr.sin_addr);
servaddr.sin_port = htons((uint16_t) dstport);
//创建sockfd,AF_INET表示IPv4,SOCK_STREAM表示TCP
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
//强制绑定客户端端口号到sockfd
sscanf(argv[1], "%d", &srcport);
struct sockaddr_in clientaddr;
bzero(&clientaddr, sizeof(clientaddr));
clientaddr.sin_family = AF_INET;
clientaddr.sin_port = htons((uint16_t)srcport);
Bind(sockfd, (SA *) &clientaddr, sizeof(clientaddr));
//发起连接请求, 关联sockfd和Server进程的IP地址,TCP端口号
Connect(sockfd, (SA *) &servaddr, sizeof(servaddr));
//发送请求消息
Write(sockfd, (char*) request, strlen(request));
//等待响应消息
Readline(sockfd, response, sizeof(response));
printf("%s\n", response);
//关闭sockfd,通知服务进程通信结束
Close(sockfd);
//进程结束
exit(0);
}
Reproduction
Create a scenario where both TCP segments SYN arrive at the opposite end at the same time.
Step 1, select a network topology (simulated with GNS3 here) and power all the devices in the network.
Step 2: Ping from host 10.22.5.3/24 to host 10.16.56.2/24 and the result is OK to ensure that the ARP cache tables of the two hosts contain the router interface entry. 1
2
3
4
5
6
7
8
9toto@guru:~$ ping 10.16.56.2 -c 3
PING 10.16.56.2 (10.16.56.2) 56(84) bytes of data.
64 bytes from 10.16.56.2: icmp_seq=1 ttl=63 time=15.2 ms
64 bytes from 10.16.56.2: icmp_seq=2 ttl=63 time=10.4 ms
64 bytes from 10.16.56.2: icmp_seq=3 ttl=63 time=14.9 ms
--- 10.16.56.2 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2002ms
rtt min/avg/max/mdev = 10.445/13.535/15.200/2.187 ms
Step 3: suspend Router work (GNS3 function), IP packet forwarding stops, and packets received by each interface are cached.
Step 4. Execute the client process using GDB on the host 10.22.5.3 and 10.16.56.2, respectively. Using Wireshark to sniff packages at both ends, SYN segments at both ends are observed to have been sent and retransmitted. 1
2
3
4
5
6#The client process establishes a TCP connection from port 44444 to port 10.15.56.2:55555
toto@guru:~$ client 44444 10.16.56.2 55555
~
#The client process establishes a TCP connection from port 55555 to port 10.22.5.3:44444
toto@client:~$ client 55555 10.22.5.3 44444
~
Step 5: unlock the Router (GNS3 function), and the IP packet cached in the Router is forwarded immediately.
Step 6, both sides receive SYN segment connection establishment request at the same time, and the connection establishment is completed. To check the TCP connection status, 1
2
3
4
5
6
7
8
9
10
11#10.22.5.3
toto@guru:~$ netstat -ant | grep 55555
tcp 0 0 10.22.5.3:44444 10.16.56.2:55555 ESTABLISHED
#10.22.5.3, GDB printouts
toto@guru:~$ client 44444 10.16.56.2 55555
request,hostname
#10.16.56.2,GDB printouts
toto@client:~$ client 55555 10.16.56.2 44444
request,hostname
TCP Segments
The details of TCP segment data [1.syn n], [1.syn k], [2.syn k, ACK n+1], [2.syn n, ACK k+1] are as follows:
Initiate SYN connection requests from 10.22.5.3:44444 to 10.16.56.2:55555. ISN is 4240815619. Initiate SYN connection requests from 10.16.56.2:55555 to 10.22.5.3:44444. ISN is 2140328405. From 10.22.5.3:44444 to 10.16.56.2:55555, send an ACK reply with an ACK of 2140328406. Again, SYN is still 4240815619. From 10.16.56.2:55555 to 10.22.5.3:44444, send an ACK reply with an ACK of 4240815620. Again, SYN is still 2140328405.
Simultaneous disconnection
Similar to establishing a connection simutaneously, a TCP connection can also be disconnected at the same time. Normally, TCP uses the FIN segment to normally disconnect an established connection. Regardless of whether the connection is a client-server model or a simultaneous model, a completed connection can be disconnected simultaneously. In other words, simultaneous disconnection is independent of how the connection is established.
Sequence of disconnection
Since it is mandatory to take four waves to disconnect the two-way communication pipe, the number of waves does not change.
The FIN segment and the ACK segment may also often be sent together, so the following case occurs.
An example of simultaneous disconnection
Use the client/server structure. Make minor changes to the client and server code.
1 | //server.c |
To ensure that this is a simultaneous disconnect scenario, we only need to check the two TCP endpoints’ states that are both TIME_WAIT states. 1
2
3
4
5
6
7
8//服务端
toto@guru:~$ netstat -ant | grep 1982
tcp 0 0 0.0.0.0:1982 0.0.0.0:* LISTEN
tcp 0 0 10.22.5.3:1982 10.16.56.2:55555 TIME_WAIT
//客户端
toto@ClientOS:~$ netstat -ant | grep 1982
tcp 0 0 10.16.56.2:55555 10.22.5.3:1982 TIME_WAIT
TCP Segments
Segments details, [1.FIN n],[1.FIN k],[2.ACK n+1],[2.ACK k+1].
10.22.5.3:1982 to 10.16.56.2:55555, FIN segment, SEQ is 3717319262. 10.16.56.2:55555 to 10.22.5.3:1982, FIN segment, SEQ is 731343897. ACK 731343898. ACK 3717319263.
Summary
Simutaneous TCP connection extablishment requires both endpoints to initiate a SYN segment, so this kind of situation will not occur on the server - client model TCP communications, generally, it will often be observed in the point-to-point communication. In the simutaneous established connection, one endpoint send a SYN, the SYN from the counterpart should be on the way, or the previous endpoint may get a RST from the counter part. When the connection is disconnected at the same time, both ends of TCP enter the TIME_WAIT state, and the problems caused by the TIME_WAIT state will affect both ends, so pay more attention to such details when analyzing some hard-to-fix problems.