C programming under Linux: TCP/IP network communication

Today, I will talk about Socket communication under Linux, including client and server.

Customer service terminal

The idea of connecting the client to the server is as follows:

1. Establish Socket link,
2. Set the communication mode, IP and port of the server, and specifically set sockaddr_in, the structural parameter
3. Connect to the server, and the data can be sent and received after the connection is successful.
4. Send and receive data normally
5. Turn off socket communication

With ideas, you can write code, ha ha, come on!

socket(int af, int type, int protocol) is used to establish socket link; this function.

Parameter 1: af indicates IP type, AF_INET indicates IPV4 type, if af is to be used_ Inet6 indicates IPV6 type

Parameter 2: type indicates socket type, SOCK_STREAM, which means link oriented socket (i.e. TCP), if it is SOCK_DGRAM, which represents a socket (UDP) facing connectionless (datagram).

Parameter 3: protocol, indicating whether TCP communication or UDP communication. Generally, the front socket type can determine the communication mode, and the last parameter is generally set to 0.

Set sockaddr_in structure,

struct sockaddr_in
{
   short sin_family;            //Address type
   unsigned short sin_port;     //Connection port, need htons to convert to network data format
   struct in_addr sin_addr;     //IP address is also the network address format
   unsigned char sin_zero[8];   //*Same size as struct sockaddr has no practical significance, just to align with SOCKADDR structure in memory*/
 }

struct sockaddr_in ServerAddr;
struct hostent *Host;
Host = gethostbyname(ServerIP);
Sockfd = socket(AF_INET,SOCK_STREAM,0);

ServerAddr.sin_family  = AF_INET;
ServerAddr.sin_port    = htons(ServerPort);
ServerAddr.sin_addr    = *((struct in_addr *)Host->h_addr);         //Returns an IP address in network data format.
Sending of data

The sending of data is relatively simple. You can call the send function directly.

int send( SOCKET s, const char FAR buf, int len, int flags );

Parameter 1: socket communication link identifier
Parameter 2: send buffer
Parameter 3: bytes sent
Parameter 4: generally set to 0

send(Sockfd,SendBuff,ByteNum,0);

If the return value is - 1, there is a problem with the communication link. You need to close the connection (identifier);) and reconnect. ` ` ` `

Reception of data

The receiving of data is the same as the receiving of serial port data in the previous blog. You need to call the select function to monitor whether the socket identifier changes, that is, whether the data is received.

It is equivalent to calling recv function to receive data after triggering reception

int len = recv(Sockfd, RecBuff, MaxLength, 0);

Parameter 1: socket identifier
Parameter 2: receive buffer
Parameter 3: receive the maximum character length
Parameter 4: generally set to 0

fd_set rfds_Socket;
FD_ZERO(&rfds_Socket);
FD_SET(Sockfd, &rfds_Socket);
int retval=select(Sockfd + 1, &rfds_Socket, NULL, NULL, NULL);
							 //tv controls the selected time if no data is received within the specified time
							 //The rfds is not monitored. If NULL, wait until data is received
							 //Continue the program execution.
printf("retval=%d--rfds_Socket=%d\n",rfds_Socket);
if(retval==0)
{
	printf("select error\n");
	continue;
}
while(Sockfd!=-1)
{
	if(FD_ISSET(Sockfd, &rfds_Socket)) //Data received
	{
		bzero(RecBuff, MaxLength);
		int  len = recv(Sockfd, RecBuff, MaxLength, 0);
		strcpy(SendBuff,RecBuff);
		ByteNum=len;
		memset(RecBuff,0x00,sizeof(RecBuff));
	}
 }

The complete send and receive function code is as follows: call two threads for processing.

The method is to send back the data received by the server.

void *pthread_NetRecFun(void *arg)
{
	char ServerIP[50];
	char Port[50];
	while(*(int*)arg)
	{
		if(Sockfd==-1)
		{

			ConfigGetKey("NetConfig.dat", "net:server", "ServerIP", ServerIP);
			ConfigGetKey("NetConfig.dat", "net:server", "ServerPort", Port);

			printf("%s---",ServerIP);
			printf("%s\n",Port);

			//char *ServerIP = "192.168.0.100";
			int ServerPort = atoi(Port);

			struct sockaddr_in ServerAddr;
			struct hostent *Host;

			Host = gethostbyname(ServerIP);

			Sockfd = socket(AF_INET,SOCK_STREAM,0);

			if(Sockfd == -1)
			{
				printf("Socket established failed!\n");
				sleep(2);
				continue;
			}
			bzero(&ServerAddr,sizeof(ServerAddr));
			ServerAddr.sin_family = AF_INET;
			ServerAddr.sin_port = htons(ServerPort);
			ServerAddr.sin_addr = *((struct in_addr *)Host->h_addr);

			if(connect(Sockfd,(struct sockaddr*)&ServerAddr,sizeof(struct sockaddr))==-1)
			{
				close(Sockfd);
				Sockfd=-1;
				printf("Socket connected failed!\n");
				sleep(2);
				continue;
			}
		}
		printf("connect Successfully*******SocketRec_VST=%d\n",Sockfd);
		fd_set rfds_Socket;
		FD_ZERO(&rfds_Socket);
		FD_SET(Sockfd, &rfds_Socket);
		int retval=select(Sockfd + 1, &rfds_Socket, NULL, NULL, NULL);
									 //tv controls the selected time if no data is received within the specified time
									 //The rfds is not monitored. If NULL, wait until data is received
									 //Continue the program execution.
		printf("retval=%d--rfds_Socket=%d\n",rfds_Socket);
		if(retval==0)
		{
			printf("select error\n");
			continue;
		}
		while(Sockfd!=-1)
		{
			if(FD_ISSET(Sockfd, &rfds_Socket)) //Data received
			{
				bzero(RecBuff, MaxLength);
				int  len = recv(Sockfd, RecBuff, MaxLength, 0);
				strcpy(SendBuff,RecBuff);
				ByteNum=len;
				memset(RecBuff,0x00,sizeof(RecBuff));
			}
		 }
	 }
}
void *pthread_NetSendFun(void *arg)
{
	char ServerIP[50];
	char Port[50];
	while(*(int*)arg)
	{
		if(Sockfd==-1)
		{
			ConfigGetKey("NetConfig.dat", "net:server", "ServerIP", ServerIP);
			ConfigGetKey("NetConfig.dat", "net:server", "ServerPort", Port);

			printf("%s---",ServerIP);
			printf("%s\n",Port);

			//char *ServerIP = "192.168.0.100";
			int ServerPort = atoi(Port);

			struct sockaddr_in ServerAddr;
			struct hostent *Host;

			Host = gethostbyname(ServerIP);

			Sockfd = socket(AF_INET,SOCK_STREAM,0);

			if(Sockfd == -1)
			{
				printf("Socket established failed!\n");
				sleep(2);
				continue;
			}
			bzero(&ServerAddr,sizeof(ServerAddr));
			ServerAddr.sin_family = AF_INET;
			ServerAddr.sin_port = htons(ServerPort);
			ServerAddr.sin_addr = *((struct in_addr *)Host->h_addr);

			if(connect(Sockfd,(struct sockaddr*)&ServerAddr,sizeof(struct sockaddr))==-1)
			{
				close(Sockfd);
				Sockfd=-1;
				printf("Socket connected failed!\n");
				sleep(2);
				continue;
			}
		}
		if(strlen(SendBuff)>0)
		{
		    //When writing the socket program under linux, if the communication link is broken and the send function is called, the underlying layer will throw a SIGPIPE signal. The default processing method for this signal is to exit the process, but this is not what we expect. So we need to overload the signal processing method. Call the following code to shield SIGPIPE safely:
			signal(SIGPIPE, SIG_IGN);  
			int len = send(Sockfd,SendBuff,ByteNum,0);
			printf("len=%d---",len);
			if(len==-1)
			{
				printf("Failed to Send Message!\n");
				close(Sockfd);
				Sockfd=-1;
                continue;
			}
			printf("NET:%s--%d---%d\n",SendBuff,ByteNum,strlen(SendBuff));
			memset(SendBuff,0x00,sizeof(SendBuff));
			ByteNum=0;
		}
	}
}

The network assistant serves as the server and the Beagle Bone serves as the client. After the connection is successful, the Beagle Bone will receive the data from the network assistant and forward it back.

Beagle Bone IP:192.168.0.152
Network assistant server IP: 192.168.0.100 port: 51230, in the same LAN segment.

Server

The idea of monitoring the client connection on the server is as follows:

1. Establish socket communication link, determine communication mode (TCP/UDP) and communication address (IPV4 or IPV6)
2. Set the IP and port of the server, and specifically set sockaddr_in, the structural parameter
3. Bind the socket to the local address and port
4. Listen to the socket and save the connection information requested by the user.
5. Send and receive data normally.
6. Turn off socket communication

Set up the socket communication link, set the IP and port. The difference with the client is that the address can be set to any. The other parameters and order are the same.

serveraddr.sin_addr.s_addr = INADDR_ANY;

listenfd = socket(AF_INET, SOCK_STREAM, 0);
printf("listenfd=%d\n", listenfd);

//A structure variable servaddr is defined to record the given IP and port information and prepare for the bind function
struct sockaddr_in serveraddr;
bzero(&serveraddr, sizeof(serveraddr));

serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(PORT); //Convert port to network byte order, i.e. large end mode
serveraddr.sin_addr.s_addr = INADDR_ANY;
Bind socket

Parameter 1: socket communication identifier
Parameter 2: server address information, including IP and port
Parameter 3: data length

//Bind the "descriptor of local meaning" to an IP and Port, and then the socket has the ability of external connection
bind(listenfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
listening socket

Parameter 1: socket communication identifier
Parameter 2: Specifies the maximum number of listening connections

//Create a listening queue to save the user's request connection information (ip, port, protocol)
listen(listenfd, BACKLOG);
Waiting to receive client connection,

This function is blocking type. Wait until there is a client connection to execute this function.
Parameter 1: socket communication identifier
Parameter 2: client address information, including IP and port
Parameter 3: receive length

connfd = accept(listenfd, (struct sockaddr*)&peeraddr, &peer_len);

After the connection is completed, you can communicate with the client normally.
The complete code is as follows:

int ServerConnectSocket()
{
	int listenfd;

	//Create a socket descriptor, which is only a common file descriptor on the host
	listenfd = socket(AF_INET, SOCK_STREAM, 0);
	printf("listenfd=%d\n", listenfd);

	//A structure variable servaddr is defined to record the given IP and port information and prepare for the bind function
	struct sockaddr_in serveraddr;
	bzero(&serveraddr, sizeof(serveraddr));

	serveraddr.sin_family = AF_INET;
	serveraddr.sin_port = htons(PORT); //Convert port to network byte order, i.e. large end mode
	serveraddr.sin_addr.s_addr = INADDR_ANY;

	//Bind the "descriptor of local meaning" to an IP and Port, and then the socket has the ability of external connection
	bind(listenfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr));

	//Create a listening queue to save the user's request connection information (ip, port, protocol)
	listen(listenfd, BACKLOG);

	printf("======bind success,waiting for client's request!!!======\n");
	//Let the operating system backfill the connection information of the client (ip, port, protocol)


	return listenfd;
}
int main()
{
	TimerFunc();
	int connfd;
	int listenfd = ServerConnectSocket();
	while(1)
	{
		//The accept function takes a client connection request from the listening queue maintained by the listen function for processing
		struct sockaddr_in peeraddr;
		socklen_t peer_len = sizeof(peeraddr);
		printf("Port=%d\r\n",PORT);
		connfd = accept(listenfd, (struct sockaddr*)&peeraddr, &peer_len);
		printf("=====================Client Connect Successfully=====================\n");
		printf("IP = %s:PORT = %d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));

		char buf[MAXDATASIZE];

		fd_set rfds_Socket;
		FD_ZERO(&rfds_Socket);
		FD_SET(connfd, &rfds_Socket);
		int retval=select(connfd + 1, &rfds_Socket, NULL, NULL, NULL);
									 //tv controls the selected time if no data is received within the specified time
									 //The rfds is not monitored. If NULL, wait until data is received
									 //Continue the program execution.
		printf("retval=%d--rfds_Socket=%d\n",rfds_Socket);
		if(retval==0)
		{
			printf("select error\n");
			continue;
		}

		while(1)
		{
			if(FD_ISSET(connfd, &rfds_Socket)) //Data received
			{
				bzero(buf, MAXDATASIZE);
				int  len = recv(connfd, buf, MAXDATASIZE, 0);
				if(len<=0)
				{
					//close(connfd);
					printf("client has closed!\n");
					connfd=-1;
					break;
				}
				printf("%s***%d\n",buf,len);
				send(connfd, buf, len, 0);
				memset(buf, '\0', MAXDATASIZE/sizeof (char));
			}
		}
	}
	close(connfd);
	close(listenfd);
	return 0;
}

The network assistant serves as the client and the Beagle Bone serves as the server. After the assistant connects successfully, the Beagle Bone will receive the data from the network assistant and forward it back.

Assistant IP: 192.168.0.100 port: 53544
Server (Beagle Bone) IP: 192.168.0.152 port: 51230

Keywords: socket network Linux

Added by lemonpiesaregood on Wed, 24 Jun 2020 10:11:07 +0300