Detailed explanation of TCP communication process (matching code, case)

Keywords: Linux udp TCP/IP

The location is different, and the ip address is different
Network protocol is the collection of a group of network rules, which is the agreement or standard we abide by together. Common protocols
TCP:
UDP:
HTTP:
Port number: uniquely identifies an application (process) on a host
Why layering:
The data link layer solves the transmission between adjacent nodes in the network
The port number resolves inter process communication at the transport layer
The network layer solves the network communication (IP) between two non adjacent nodes
Tcp connection oriented reliable streaming service
udp connectionless unreliable data flow service

Tcp communication flow

1, Establish socket

1. Socket definition

Socket is a handle to the transmission provider (handle: a special smart pointer, the ID of each specific object. According to this ID, the operating system can send messages to the specified object). In the network programming of Linux system, the handle is operated to realize network communication and management.

2. Socket classification

Sockets are divided into three categories: original socket (SOCK_RAM), socket_stream and packet socket (SOCK_DGRAM)
(1) Raw socket: it enables program developers to control the underlying network transmission mechanism. The data received under the raw socket contains IP headers.
(2) Streaming socket: it provides two-way, orderly and reliable data transmission. This kind of socket requires both parties to establish a connection before communication. TCP protocol uses this kind of socket.
(3) Packet socket: it provides two-way data flow, but it can not ensure the reliability, order and non repeatability of data transmission. UDP protocol uses this socket.
These three socket classifications are used in the socket creation function, for example:
1> If you are creating a TCP/IP protocol, you should use SOCKET_STREAM,sockfd=socket(AF_INET,SOCK_STREAM,0);
2> If you are creating a UDP protocol, you should use SOCK_DGRAM,sockfd=socket(AF_INET,SOCK_DGRAM,0);

3. Socket related structures

(1)struct sockaddr

#include <netinet/in.h>
struct sockaddr
{
	unsigned short  sa_family;/*Address family, 2 bytes, AF_xxx*/
	char  sa_data[14];/*14 Byte Protocol address*/
}

(2)struct sockaddr_in

#include <netinet/in.h>
struct  sockaddr_in
{
	short int sin_famliy;/*Address family, 2 bytes*/
	unsigned short  sin_port;/*Port number, 2 bytes. When this parameter is filled with 0, it means that the system randomly selects an unused port number*/
	struct in_addr  sin_addr;/*IP Address, 32 bits, 4 bytes, this byte is filled in INADDR_ANY means to fill in the local address*/
	unsigned char sin_zero[8];/*Fill 8 bytes 0 to keep the same size as struct sockaddr*/
}

be careful:
1>sin_ The port number filled in by port should be set to 1024, because 0 ~ 1024 is the reserved port number (for example, 110119120 is dedicated).
2> When using this structure, sin_port,sin_addr cannot directly fill in the value. It needs to be converted into network byte priority (i.e. large end storage).
(3) Network byte priority
On the Internet, data is transmitted on the network in the order of high byte priority. Therefore, for machines that store data internally in the way of low byte priority, conversion shall be carried out when transmitting data on the Internet, otherwise data inconsistency will occur.
In socket network programming, there are two basic attributes that must be mastered: network byte order (NBO) and host network order (HBO).
Network byte order, NBO is the data format specified in the transmission of network data, which is stored in order from high to low, that is, the low byte is stored in the high address and the high byte is stored in the low address; Namely "big end mode". Network byte order can avoid the difference of byte order between different hosts.
Host byte order, HBO is related to the machine CPU, and the storage order of data is determined by the CPU.
The following is a few byte order conversion functions under Linux system

#include <arpa/inet.h>
uint32_t	htonl(unit32_t hostlong);		//The htonl() function converts 32-bit values from host byte order to network byte order
uint16_t 	htons(uint16_t hostshort);		//htons converts 16 bit values from host byte order to network byte order
uint32_t 	ntohl(uint32_t netlong);		//Converts 32-bit values from network order to host byte order
uint16_t	ntohs(uint16 netshort);			//Convert 16 bit values from network byte order to host byte order
in_addr_t 	inet_addr("xxx.xxx.xxx.xxx");	//Converts a string IP address to an integer in 32-bit network byte order
char 		*inet_ntoa(struct in_addr in);	//Convert a 32-bit network byte order binary IP address into the corresponding dotted decimal IP address string

(4)struct sockaddr_ How to use in

#include <arpa/inet.h>
#include <netinet/in.h>
Local_addr.sin_family = AF_INET;
Local_addr.sin_addr.s_addr =  htonl(INADDR_ANY);	//Fill in the local IP address
/*Note: if you need to fill in another IP address, such as 192.168.2.88, INET is required_ Addr to convert the string into an integer value of 32-bit network bytes*/
/*Local_addr.sin_addr.s_addr =  inet_addr("192.168.2.88")*/
Local_addr.sin_port = htons(50001);
bzero(&(Local_addr.sin_zero),8);

(5)struct sockaddr and struct SOCKADDR_ The difference and relation of in
common ground:
1> The space size is the same, all 16 bytes
2> All have family attribute
3> SOCKADDR and sockadddr_in contains the same data
difference:
1> sockaddr represents SA in 14 bytes except family_ Data, and sockaddr_in splits 14 bytes into sin_port,sin_addr and sin_zero. Indicates port and ip address respectively. sin_zero is used to fill in bytes to make sockaddr_in and sockaddr remain the same size.
2> Programmers should not operate SOCKADDR. SOCKADDR is for the operating system. Programmers should use sockaddr_in to represent the address, sockaddr_in distinguishes the address and port, which is more convenient to use.

Specific usage: programmers fill sockaddr with type, ip address and port_ The in structure is then cast into sockaddr and passed to the calling function as a parameter.
give an example:

int sockfd;
struct sockaddr_in servaddr;
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
/* Fill struct sockaddr_in */
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
/* Cast to struct sockaddr */
connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));

4. Socket creation function socket

Whether TCP or UDP communication, whether as a client or server, the first part of establishing communication is to create a socket first.
(1) Function: to create a socket, this function returns a handle similar to a file descriptor.
(2) Header file:
#include<sys/types>
#include<sys/socket.h>

(3) Function prototype: int socket (int soman,int type,int protocol)

(4) Function parameters:
1> Domain represents the protocol family used, usually AF_INET, and represents the internet protocol family (TCP/IP protocol family)
2> Type to specify the type of socket:
SOCKET_STREAM
SOCK_DGRAM (packet socket)
SOCK_RAW (raw socket)
3> Protocol, commonly used are IPPROTO_TCP, IPPTOTO_UDP and 0, which respectively represent TCP transmission protocol, UDP transmission protocol and automatic deduction.

(5)protocol: Generally speaking, you can create a socket with two parameters: domain and type. If you fill in 0, the operating system will automatically deduce the protocol type. The method of filling in 0 is also mostly used in programming. Unless you encounter such a situation: there are two different protocols that support the same address type and data transmission type. If we don't specify which protocol to use, the operating system won't work It can be deduced automatically.
1> If the value of the parameter domain is AF_INET and the type is SOCK_STREAM, the only protocol meeting these two conditions is TCP, so the following two methods are equivalent:
int tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //IPPROTO_TCP indicates TCP protocol
int tcp_socket = socket(AF_INET, SOCK_STREAM, 0); //0 indicates the protocol corresponding to automatic deduction

2> The value of parameter domain is AF_INET, type, select SOCK_DGRAM, the only protocol meeting these two conditions is UDP, so the following two methods are equivalent:
int udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); //IPPROTO_UDP means UDP protocol
int udp_socket = socket(AF_INET, SOCK_DGRAM, 0); //0 indicates the protocol corresponding to automatic deduction
(6) Return value: an int type socket descriptor. After the socket is created, this value is generally greater than 2, which will be called by subsequent functions operating on the socket- 1: Creation failed, and the returned value is 0,1,2, which basically belongs to the standard I / O socket ID. Usually, this problem does not occur when users create sockets themselves.

Socket descriptor: a pointer to the internal data structure. It points to the descriptor table entry. When the socket function is called, the socket execution body will create a socket, that is, allocate storage space for a socket data structure.

5.perror function

perror function: perror(s) is used to output the cause of the error in the previous function to the standard device (stderr).
The string indicated by parameter s will be printed first, followed by the error reason string. The cause of this error determines the string to be output according to the value of the global variable errno. There is an errno variable in the library function, and each errno value corresponds to the error type represented by a string. When you make an error when calling "some" functions, the function has reset the value of errno. The perror function just outputs some information you entered together with the error corresponding to the current errno.
Use examples of perror function:

		#include<stdio.h>
		int main(void)
		{
		    FILE *fp;
		    fp=fopen("/root/noexitfile","r+");
		    if(NULL==fp)
		    {
		        perror("/root/noexitfile");
		    }
		    return 0;
		}

2, Bind socket bind

In particular, the bind function is only used by the TCP server, and the client does not need to bind a socket. After a socket descriptor is returned through the socket() function call, the socket must be bound before receiving the client connection request, that is, the socket must be associated with the local IP address and port, and then the listening service can be carried out under the port.

(1) Header file:
#include <sys/types.h>
#include <sys/socket.h>

(2) The function assigns a local IP address and port number to a socket

(3) Function prototype: int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen)

(4) Function parameters:
① sockfd, socket descriptor returned by calling socket() function
② my_addr, a pointer to sockaddr containing the local IP address and port number. Usually, sockaddr_ The in type is forcibly converted to the sockaddr type
③ addrlen,socklen_t is similar to int, 4 bytes. This parameter represents the length of struct sockaddr, that is, sizeof(struct sockaddr);

(5) Return value: 0 is returned if the binding is successful; If an error occurs, return - 1 and set errno to the corresponding error number, that is, the error message can be printed out by the perror function.

3, Establish a connection connect function (used by the client)

The connection oriented client uses the connect function to configure the socket and establish a TCP connection with the remote server. By implication, the client uses the connect function.
The connect function is a blocking function that establishes a connection to the server through the TCP triple handshake. The client actively connects to the server, establishes the connection mode, and notifies the Linux kernel to automatically complete the TCP triple handshake connection through TCP triple handshake. If the connection is successful, it is 0. If the connection fails, the return value is - 1. Generally, the connect function of the client defaults to blocking behavior until the three handshake stages are successful.
The function of the connect() function on the client is that the client actively connects to the server. The connection is established through three handshakes, and the connection process is completed by the kernel, not this function. The function is only to notify the Linux kernel and let the Linux kernel automatically complete the TCP three handshake connection.

(1) Header file:
#include <sys/types.h>
#include <sys/socket.h>

(2) Function function: used to establish a connection with the specified socket and connect to the server (notify the Linux kernel to automatically complete the TCP handshake three times).

(3) Function prototype: int connect(int sockfd, const struct sockaddr * serv_addr, int serv_addrlen);

(4) Function parameters:
① sockfd, socket descriptor returned by calling socket() function
② serv_addr, a pointer containing the IP address and port number of the remote server
③ serv_addr, the length of the pointer containing the IP address and port number of the remote server, that is, sizeof(struct sockaddr)

(5) Return values: 0: success, - 1: failure. Save the error code to errno and print it with the perror function.
4, Listen mode listen function
This function puts the socket in passive listening mode, establishes an input data queue for the socket, and saves the reached service requests in the queue until the program processes them.
For servers, it is passively connected. For example, in life, usually, the mobile customer service (equivalent to the server) is waiting for the arrival of the customer (equivalent to the client) call. In this process, you need to call the listen() function.
If a server calls socket() and bind(), it will call listen() to listen to the socket. If the client calls connect() to make a connection request, the server will receive the request.
In TCP server programming, the listen function changes the process into a server and specifies that the corresponding socket becomes a passive connection.

(1) Header file:
#include <sys/types.h>
#include <sys/socket.h>

(2) The function changes the process into a server and specifies that the corresponding socket becomes a passive connection.

(3) Function prototype: int listen(int sockfd, int backlog);

(4) Function parameters:
① sockfd, socket descriptor returned by calling socket() function
② backlog, which tells the kernel the length of the connection queue. Detailed introduction reference https://blog.csdn.net/kongxian2007/article/details/49153801

(5) Return values: 0: success, - 1: failure. Save the error code to errno and print it with the perror function.
Note: the listen() function will not block. Its main task is to tell the Linux kernel the socket and the corresponding connection queue length of the socket, and then the listen() function ends. In this way, when a client actively connects (connect()), the Linux kernel automatically completes the TCP handshake three times, and automatically stores the established link in the queue. Repeat this. Therefore, as long as the TCP server calls listen (), the client can establish a connection with the server through connect(), and the connection process is completed by the kernel.

Example:
The server:

		#include <stdio.h>
		#include <stdlib.h>
		#include <string.h>						
		#include <unistd.h>
		#include <sys/socket.h>
		#include <netinet/in.h>
		#include <arpa/inet.h>				
		int main(int argc, char *argv[])
		{
			unsigned short port = 8000;
			int sockfd;
			sockfd = socket(AF_INET, SOCK_STREAM, 0);// Create communication endpoint: socket
			if(sockfd < 0)
			{
				perror("socket");
				exit(-1);
			}
			struct sockaddr_in my_addr;
			bzero(&my_addr, sizeof(my_addr));	     
			my_addr.sin_family = AF_INET;
			my_addr.sin_port   = htons(port);
			my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
			int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));
			if( err_log != 0)
			{
				perror("binding");
				close(sockfd);		
				exit(-1);
			}
			err_log = listen(sockfd, 10);
			if(err_log != 0)
			{
				perror("listen");
				close(sockfd);		
				exit(-1);
			}	
			printf("listen client @port=%d...\n",port);
			sleep(10);	// Delay 10s
			system("netstat -an | grep 8000");	// View connection status
			return 0;
		}

client

		#include <stdio.h>
		#include <unistd.h>
		#include <string.h>
		#include <stdlib.h>
		#include <arpa/inet.h>
		#include <sys/socket.h>
		#include <netinet/in.h>
		int main(int argc, char *argv[])
		{
			unsigned short port = 8000;        		// Port number of the server
			char *server_ip = "10.221.20.12";    	// server ip address 
			int sockfd;
			sockfd = socket(AF_INET, SOCK_STREAM, 0);// Create communication endpoint: socket
			if(sockfd < 0)
			{
				perror("socket");
				exit(-1);
			}
			struct sockaddr_in server_addr;
			bzero(&server_addr,sizeof(server_addr)); // Initialize server address
			server_addr.sin_family = AF_INET;
			server_addr.sin_port = htons(port);
			inet_pton(AF_INET, server_ip, &server_addr.sin_addr);
			int err_log = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));      // Actively connect to the server
			if(err_log != 0)
			{
				perror("connect");
				close(sockfd);
				exit(-1);
			}
			system("netstat -an | grep 8000");	// View connection status
			while(1);
			return 0;
		}

5, Receive request accept function (used by server)

The accept function lets the server receive the connection request from the client. After the connection queue is established, the server calls the accept function, then sleeps and waits for the connection request from the client.
The accept() function will block: take out the completed connection from the queue in the established state (that is, after three handshakes have been completed). When the connection is not completed in the queue, a block will be formed until the user connection that has completed the connection in the queue is taken out.

(1) Header file:
#include <sys/types.h>
#include <sys/socket.h>

(2) Function: used to receive connection requests from clients.

(3) Function prototype: int accpt(int sockfd, const struct sockaddr * client_addr, int client_addrlen);

(4) Function parameters:
① sockfd, socket descriptor returned by calling socket() function
② client_addr, a pointer containing the IP address and port number of the remote client
③ client_addr, the length of the pointer containing the IP address and port number of the remote client, that is, sizeof(struct sockaddr)

(5) Return value:
① - 1: failed, and save the error code to errno, which can be printed by perror function.
② Non negative number: the return value is a new socket descriptor, which represents a new connection with the client. It can be understood as a socket of the client
Example:

		int	acceptedfd;
		unsigned char buf[256];
		acceptedfd = accept(socketfd,(struct sockaddr *)&client_address, (int *)&fromlen);	//Receive client connection request
		recv(acceptedfd ,buf,256,0);	//Receive data sent by client

6, Data transmission (send, recv, close)

size_t it has different definitions on different platforms:
/* sparc 64 bit /
typedef unsigned long __kernel_size_t;
typedef long __kernel_ssize_t;
/ sparc 32 bit */
typedef unsigned int __kernel_size_t;
typedef int __kernel_ssize_t;

1.send() function

The send function sends data to a connected socket. If there is no error, the return value is the total number of data sent. Otherwise, it returns SOCKET_ERROR.
Both client and server applications use the send function to send data to the other end of the TCP connection. The client program usually uses the send function to send a request to the server, while the server usually uses the send function to send a reply to the client program.

(1) Header file:
#include <sys/types.h>
#include <sys/socket.h>

(2) Function: send data to a connected socket.

(3) Function prototype: ssize_t(int sockfd, const void *buf, size_t len, int flag);

(4) Function parameters:
① sockfd, socket descriptor returned by calling socket() function
② const void *buf, a pointer to the data to be sent
③ len is the length of data in bytes
④ flag, 0: it is the same as write(). In general, fill in 0, and in special cases, fill in the following three cases
MSG_ Donroute: tell the kernel that the target host is in the local network and do not check the routing table
MSG_ Donwait: sets a single I / O operation to non blocking mode
MSG_OOB: indicates that out of band information is sent

(5) Return value:
① - 1: failed, and save the error code to errno, which can be printed by perror function.
② Greater than 0 indicates the number of bytes actually sent

Note: the send function returns the number of bytes actually sent, which may be less than the data the user wants to send. In the program, the return value of the send function should be compared with the number of bytes (len) to be sent. When the return value of the send function is inconsistent with the length of len, this situation should be handled.

2.recv() function

Both client and server applications use the recv function to receive data sent from the other end of the TCP connection.

(1) Header file:
#include <sys/types.h>
#include <sys/socket.h>

(2) Function: receive data sent from the other end of TCP.

(3) Function prototype: ssize_t recv(int sockfd, const void *buff, size_t nbytes, int flags);

(4) Function parameters:
① sockfd, socket descriptor returned by calling socket() function
② const void *buf, a pointer to the receive data buffer
③ len, the length of the buffer. The length of the buffer is generally defined as large to prevent the received data from being too large and missing data.
④ flag,
0: the same as read(), except that after reading the data in the buffer, the read function will delete the data in the buffer, while recv will not
MSG_ Donwait: sets a single I / O operation to non blocking mode
MSG_OOB: indicates that out of band information is sent
MSG_PEEK: you can view readable information and will not lose the data after receiving it
MSG_WAITALL: tells the kernel not to return until the requested number of data bytes is read.

(5) Return value:
① - 1: failed, and save the error code to errno, which can be printed by perror function.
② Greater than 0 indicates the number of bytes actually received
Note: recv reception is divided into two cases, one is the client and the other is the server. Examples:

		/*client*/
		int rr_1;
		if ( (socketfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )	//Create socket
		{	
			perror("Error  to build socket\n");
			return ;
		}
		rr_1 = connect(socketfd,(struct sockaddr *)&serv_addr,sizeof(struct sockaddr));		//Connect to the server
		if ( rr_1  == -1 )	
		{	
			perror("Error connecting to socket\n");
			return ;
		}	
		RecvLen = recv(socketfd, RecvBuf,MAXDATASIZE,0);	//receive data 
			
		/*Server side*/
			socketfd = socket(AF_INET, SOCK_STREAM, 0); 	//Create socket
			bind(socketfd, (struct sockaddr *)&serv_addr, address_len);	//Bind socket
			acceptedfd = accept(socketfd,(struct sockaddr *)&client_address, (int *)&fromlen);	//Receive connection requests from clients
			RecvLen=recv(acceptedfd, RecvBuf,MAXDATASIZE,0);	//Receive data sent by the client

3.close() function

After the data operation is completed, you can call the close() function to release the socket, so as to stop any data operation on the socket.
(1) Header file: #include < unistd. H >
(2) Function prototype: int close(int sockfd);
(3) Function parameter: sockfd, socket descriptor to be released

4.shutdown() function

This function also closes the socket, but unlike close, it allows data transmission in one direction to be stopped while data transmission in the other direction continues.

(1) Header file: #include < sys / socket. H >

(2) Function prototype: int shutdown(int sockfd,int how)

(3) Function parameters:
① sockfd, socket descriptor to close
② how, the following methods can be selected for closing operation:
0: continue receiving data is not allowed
1: Sending data is not allowed
2: Sending and receiving data is not allowed
If none of the above behaviors are allowed, you can call the close function directly.

(4) Return values: 0: success, - 1: failure, and set the corresponding errno value

7, TCP communication flow

1. Server side

1. Create socket()
2. Configure the server sockaddr_in structure
3. Bind socket ()
4. In the listening mode, notify the Linux kernel to shake hands three times
5. Wait for the client to connect and call the client_fd = accep()
6. Receive client information, client_fd=accept(sockfd,NULL,NULL)
7. Send a message to the client, (send(client_fd,sendbuf,strlen(sendbuf),0)

2. Client

1. Create socket()
2. Fill in the sockaddr_in structure of the server to be connected
3. Initiate the link to the server and call connect()
4. Send a message to the server, send(sockfd,buf,strlen(buf),0)
5. Receive the message from the server, recv(sockfd,buf,BUFFER_SIZE,0)

8, TCP communication example

1. Server side

		///server.c
		#include <sys/types.h>
		#include <sys/socket.h>
		#include <stdio.h>
		#include <stdlib.h>
		#include <errno.h>
		#include <string.h>
		#include <unistd.h>
		#include <netinet/in.h>
		#define PORT 4321
		#define BUFFER_SIZE 1024
		#define MAX 5
		#include <pthread.h>
		int main()
		{
		    struct sockaddr_in servaddr;
		    int sockfd,client_fd;
		    char buf[BUFFER_SIZE];
			char sendbuf[] = "received data";
			/*Establish socket connection*/
		    if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
		    {
		        perror("socket");
		        exit(1);
		    }
		
		    printf("socket id=%d\n",sockfd);
			/*Set relevant parameters in sockaddr_in structure*/
		    bzero(&servaddr,sizeof(servaddr));
		    servaddr.sin_family=AF_INET;
		    servaddr.sin_port=htons(PORT);
		    servaddr.sin_addr.s_addr=INADDR_ANY;
		    int i=1;  /*This address can be reused to bind with socket*/
		    setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(i));
			
			/*Binding function bind()*/
		    if(bind(sockfd,(struct sockaddr *) &servaddr,sizeof(servaddr))==-1)
		    {
		        perror("bind");
		        exit(1);
		    }
		    printf("Bind success!\n");
			/*Call the listen function to create a queue of unprocessed requests*/
		    if(listen(sockfd,MAX)==-1)
		    {
		        perror("listen");
		        exit(1);
		    }
		
		    printf("Listen...\n");
		
			/*Call the accept function and wait for the client to connect*/
		    if((client_fd=accept(sockfd,NULL,NULL))==-1)
		    {
		        perror("accept");
		        exit(0);
		    }
		    
			while(1)
			{
				if(recv(client_fd,buf,BUFFER_SIZE,0)==-1)
				{
				    perror("recv");
				    exit(0);
				}
				else
				{	
					printf("Received a message:%s\n",buf);
					memset(buf,0,sizeof(buf));
					if(send(client_fd,sendbuf,strlen(sendbuf),0)==-1)
					{
						perror("send");
						exit(-1);
					}
					memset(buf,0,sizeof(buf));
				}
			}
		    close(sockfd);
		    exit(0);
		}


2. Client

		///client.c
		#include <stdio.h>
		#include <stdlib.h>
		#include <errno.h>
		#include <string.h>
		#include <netdb.h>
		#include <sys/types.h>
		#include <sys/socket.h>
		#include<arpa/inet.h>
		#define BUFFER_SIZE 100
		
		int main(int argc,char *argv[])
		{
		    int sockfd,client_fd;
			int len;
		    char buf[BUFFER_SIZE];
		    struct sockaddr_in servaddr;
		
		    if(argc<3)
		    {
		        printf("USAGE=%s <serv_in> <serv_port>\n",argv[0]);
		        exit(-1);
		    }

			/*Create socket*/
		    if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
		    {
		        perror("socket");
		        exit(-1);
		    }
			else
			{
				printf("socket build success\r\n");
			}
		  
			/*Create sockaddr_in structure related parameters*/
		    bzero(&servaddr,sizeof(servaddr));
		    servaddr.sin_family=AF_INET;
		    servaddr.sin_port=htons(atoi(argv[2]));
		    servaddr.sin_addr.s_addr= inet_addr(argv[1]);
			
			/*Call the connect function to initiate the link to the server actively*/
		    if(connect(sockfd,(struct sockaddr *) &servaddr,sizeof(servaddr))==-1)
		    {
		        perror("connect");
		        exit(-1);
		    }
		    
			/*Send message to server*/
			while(1)
			{
				printf("please input string:\r\n");					
				scanf("%s",buf);
				len = sizeof(buf);
				printf("len = %d\r\n",len);
				buf[len] = 0;
				if(send(sockfd,buf,strlen(buf),0)==-1)
				{
				    perror("send");
				    exit(-1);
				}
				memset(buf,0,sizeof(buf));
				if(recv(sockfd,buf,BUFFER_SIZE,0)==-1)
				{
				    perror("recv");
				    exit(0);
				}
				printf("Received a message:%s\n",buf);
				memset(buf,0,sizeof(buf));
			}
		    close(sockfd);
		    exit(0);
		}

Operation results:
Run the server first, and then the client. The client enters the IP address of the server (note that 10.144.42.88 I filled in here is the IP address of my virtual machine. You can use the ifcong command to view your IP address) and port number. After entering, enter the string you want to send to the server, and click enter. After sending successfully, the server will reply to the message of receive data, Indicates successful reception.

This article is reproduced in: https://blog.csdn.net/qq_37733540/article/details/95046565.

Posted by stilgar on Sun, 07 Nov 2021 21:16:34 -0800