TCP IP network programming (5) TCP-based server and client (supplementary)

Perfect implementation of echo client

Problems with echo client

In the previous section, there are problems in the TCP-based server and echo client:

If the data is too large, the operating system may divide the data into multiple packets and send them to the client. The client may call the read function before receiving all the data packets.

The problem lies with the client, not the server. Let’s first compare the client and server-side I/O related codes.

Service-Terminal

while((str_len = read(cknt_sock, message, BUF_SIZE)) != 0)
    write(clnt_sock, message, str_len);

client

write(sock, message, strlen(message))
str_len = read(sock, message, BUF_SIZE - 1);

Both the client and the server call the read and write functions. In fact, the echo client will accept 100% of the data it transmits, but there is a problem with the unit when receiving the data.

What the echo client transmits is a string, and it is sent once by calling the write function. Then it calls the read function and waits to receive the string it transmitted.

The problem here arises when the client receives all the string data, how long does it need to wait? Can the read be completed in one go by calling the read function after waiting?

Echo client problem resolution

Because the size of the received data can be determined in advance, this problem is not difficult to solve. If a 100-byte long string has been transmitted before, the read function is called in a loop to read the 100-byte class when receiving.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define BUF_SIZE 1024
void error_handling(char *message);

int main(int argc, char *argv[])
{
	int sock;
	char message[BUF_SIZE];
	int str_len, recv_len, recv_cnt;
	struct sockaddr_in serv_adr;

	if(argc!=3) {
		printf("Usage : %s <IP> <port>\n", argv[0]);
		exit(1);
	}
	
	sock=socket(PF_INET, SOCK_STREAM, 0);   
	if(sock==-1)
		error_handling("socket() error");
	
	memset(&serv_adr, 0, sizeof(serv_adr));
	serv_adr.sin_family=AF_INET;
	serv_adr.sin_addr.s_addr=inet_addr(argv[1]);
	serv_adr.sin_port=htons(atoi(argv[2]));
	
	if(connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)
		error_handling("connect() error!");
	else
		puts("Connected...........");
	
	while(1) 
	{
		fputs("Input message(Q to quit): ", stdout);
		fgets(message, BUF_SIZE, stdin);
		
		if(!strcmp(message,"q\n") || !strcmp(message,"Q\n"))
			break;

		str_len=write(sock, message, strlen(message));
		
		recv_len=0;
		while(recv_len<str_len)
		{
			recv_cnt=read(sock, &message[recv_len], BUF_SIZE-1);
			if(recv_cnt==-1)
				error_handling("read() error!");
			recv_len+=recv_cnt;
		}
		
		message[recv_len]=0;
		printf("Message from server: %s", message);
	}
	
	close(sock);
	return 0;
}

void error_handling(char *message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

In the previous example, the read function was called only once. The above example calls the read function in a loop in order to receive all transmitted data.

while(recv_len<str_len)
{
	recv_cnt=read(sock, &message[recv_len], BUF_SIZE-1);
	if(recv_cnt==-1)
		error_handling("read() error!");
	recv_len+=recv_cnt;
}

If you change the above code to:

while(recv_len != str_len)
{
	recv_cnt=read(sock, &message[recv_len], BUF_SIZE-1);
	if(recv_cnt==-1)
		error_handling("read() error!");
	recv_len+=recv_cnt;
}

The size of the received data should be the same as the transmitted one, so the data saved in recv_len is equal to the data saved in str_len, which ends the while loop. Readers must think that this loop writing method is more logical, but it may cause death due to some abnormal situation. Loop, so use while(recv_len<str_len) as much as possible, even if an exception occurs, it will not cause an infinite loop

TCP principle

I/O buffering in TCP sockets

TCP socket data sending and receiving is borderless. Even if the server calls the write function once to transmit 40 bytes of data, the client may read 10 bytes each time through four read function calls. However, the problem arises again. The server 40 bytes are transmitted at once, but the client can receive it slowly in batches. After the client receives 10 bytes, where are the remaining 30 bytes waiting?

In fact, the data is not transmitted immediately after the write function is called, and the data is not received immediately after the read function is called. To be more precise, the moment the write function is called, the data will be moved to the output buffer; the moment the read function is called, the data will be read from the input buffer.

Insert image description here

When the write function is called, the data will be moved to the output buffer and passed to the other party's input buffer at the appropriate time. At this time, the other party calls the read function to read the data from the input buffer.

I/O buffer characteristics are as follows

  • I/O buffering exists individually within each TCP socket
  • I/O buffering is automatically generated when the socket is created
  • Data left in the output buffer will continue to be delivered even if the socket is closed
  • Closing the socket will lose the data in the input buffer

TCP inner workings 1: Connection to the other party’s socket

The process of a TCP socket from creation to disappearance is divided into three steps:

1. Establish a connection with the other party’s socket

2.Exchange data with the other party’s socket

3. Disconnect from the other party’s socket

TCP will also go through three dialogue processes during the actual communication process, so this process is also called a three-way handshake.

Insert image description here

The socket works in full-duplex mode, which means that the socket can transfer data in both directions.

1. Host A requesting a connection passes the following information to host B:

[SYN] SEQ: 1000, ACK: -

The SEQ in this message is 1000, and the ACK is empty. The meaning of SEQ 1000 is as follows:

The serial number of the data packet being transmitted now is 100. If it is received correctly, please notify me to deliver data packet No. 1001 to you.

2. This is the message used when requesting a connection for the first time, also called SYN, which represents the synchronization message transmitted before sending and receiving data. Next, host B transmits the following message to A:

[SYN+ACK] SEQ: 2000, ACK: 1001

At this time, SEQ is 2000, ACK is 1001, and the meaning of SEQ 2000 is as follows:

The serial number of the data packet being transmitted now is 2000. If the reception is correct, please notify me to deliver the data packet No. 2001 to you.

The meaning of ACK 1001 is as follows:

The data packet with SEQ 1000 just transmitted was received correctly. Now please pass the data packet with SEQ 1001.

The data packet confirmation message (ACK 1001) for the first transmission of host A and the synchronization message (SEQ 200) to prepare for host B to transmit data are sent in a bundle, so this type of message is also called SYN + ACK

3. Before sending and receiving data, assign a sequence number to the data packet and notify the other party of the sequence number. This is all preparation to prevent data loss. By assigning sequence numbers to data packets and confirming them, lost data packets can be immediately viewed and retransmitted when data is lost, so TCP can ensure reliable data transmission. Finally, observe the message transmitted by host A to B:

[ACK] SEQ : 1001, ACK: 2001

When sending a data packet during a TCP connection, a sequence number needs to be assigned, which is +1 based on the previous sequence number of 100. At this time, the data packet delivers the following message:

The transmitted data packet with SEQ 2000 has been correctly received and the data packet with SEQ 2001 can now be transmitted.

TCP internal working principle 2: Data exchange with the other host

Through the first three-way handshake process, the data exchange preparation is completed, and then the formal sending and receiving of data begins.

Insert image description here

First, host A sends 100 bytes of data through 1 data packet. The SEQ of the data packet is 1200. To confirm this, host B sends an ACK1301 message to host A.

The ACK number at this time is 1301 instead of 1201. The reason is that the increment of the ACK number is the number of data bytes transmitted. Assuming that the number of bytes transmitted is not added to the ACK number each time, although the transmission of the data packet can be confirmed, it cannot It is clear that 100 bytes are not transmitted correctly or are lost, so the ACK message is transmitted according to the following formula:

ACK number - SEQ number + number of bytes transferred + 1

The same as the three-way handshake protocol, the last +1 is to inform the other party of the SEQ number to be transmitted next time

Let’s analyze the disappearance of data packets during transmission.

Insert image description here

The SEQ1301 data packet transmits 100 bytes of data to host B, but an error occurred in the middle and host B did not receive it. After a period of time, host A still did not receive the ACK confirmation for SEQ 1301, so the data packet was retransmitted. In order to complete the data The packet is retransmitted. The TCP socket starts the timer to wait for the ACK reply. If the corresponding timer times out, it will be retransmitted.

TCP inner workings 3: Disconnecting from the socket

First, socket A transmits a disconnection message to socket B. Socket B sends a confirmation message, and then transmits a disconnection message to socket A. Socket A also sends a confirmation. information

Insert image description here

The FIN in the data packet indicates disconnection. Both parties send a FIN message once and then disconnect. This process goes through four stages, so it is also called a four-way handshake.

Summarize

This is the third article in the "TCP/IP Network Programming" column. Readers are welcome to subscribe!

For more information, click to add a link description. Readers are welcome to go to Star

⭐Academic exchange group Q 754410389 is being updated~~~

Guess you like

Origin blog.csdn.net/m0_63743577/article/details/132778867