Network programming 06-server programming non-blocking IO, multiplexing

Table of contents

1. Four high-performance IO models in server programming

1. Block IO

2. Non-blocking IO

3. Multiplexing

4. Signal drive

2. Blocking IO

3. Non-blocking IO

1. The difference between blocking IO and non-blocking IO

2. How to set the non-blocking attribute to the file descriptor----fcntl() ----- man 2 fcntl

4. Multiplexing

1. Monitor multiple socket IO ports at the same time

2. What is multiplexing

3. Features

4. Multiplexed function interface -------select -----man 2 select

Client.c

1. Four high-performance IO models in server programming

 

1. Block IO

1)read(fd,buf) ; recv(fd) ; recvfrom(fd)
These functions themselves do not have blocking attributes, but the blocking attribute of the file descriptor itself causes the execution of this function to be blocked.
2) By default, the socket sockets established under Linux are blocked.

2. Non-blocking IO

1) Add non-blocking attribute to file descriptor
2) Because of the non-blocking property, the socket is constantly asked if data arrives

3. Multiplexing

1) Operate on multiple IO ports at the same time (that is, listen to several sockets at the same time)
2) It can detect whether the data arrives within the specified time

4. Signal drive

1) It belongs to asynchronous communication mode
2) When data arrives in the socket, notify the user by sending a signal

2. Blocking IO

Read blocking: When there is no data to read in the data buffer, calling read/recv/recvfrom will block infinitely.
Write blocking: When the remaining size of the buffer is less than the amount of data written, write blocking will occur until the data in the buffer is read

3. Non-blocking IO

1. The difference between blocking IO and non-blocking IO

 

2. How to set the non-blocking attribute to the file descriptor----fcntl() ----- man 2 fcntl

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
parameter
fd : Which file do you want to set, pass in the file descriptor of this file
cmd: command word to request control
arg: Whether or not to fill in this parameter depends on the second parameter
The second parameter:

 

for example:

int fd = open("xxx");
int status = fcntl(fd, F_GETFL ); //get the status of the file descriptor
status |= O_NONBLOCK ;//Add non-blocking properties on the basis of the original
fcntl(fd, F_SETFL,status); //Set the state of the variable status to the file descriptor

 

return value
        F_GETFL Value of file status flags.
        F_SETFL
Returns 0 successfully
Returns -1 on failure
Example 1: Set a non-blocking attribute to a socket to see if the socket will still block waiting for client connections?

 

Example 2: Using TCP communication Modify it to be non-blocking

1 #include<stdio.h>
2 #include <sys/socket.h>
3 #include <sys/types.h> /* See NOTES */
4 #include <netinet/in.h>
5 #include <arpa/inet.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <fcntl.h>
9 #define OWNADDR "192.168.14.3" //My own computer's ip address
10 #define OWNPORT 20000 //The port number of this program on my own computer
12 int main()
13 {
printf("current server IP:%s Port:%u\n",OWNADDR,OWNPORT); 14
//1. Buy a mobile phone (build a socket) 15
int socketfd = socket(AF_INET, SOCK_STREAM, 0); 16
if(socketfd == -1) 17
{ 18
printf("No money....,fail\n"); 19
return -1; 20
} 21
//Because the port number will not be released in time after the server exits immediately
//At this time, if the server runs again immediately, the port number will be occupied, causing the server to fail to assign the port number and the connection to fail. 23
//So setting the port number can reuse 24
int optval = 1; 25
setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR,&optval, sizeof(optval)); 26
27
//2. Bind your own phone number (bind your own IP address and port number) 28
//Define an IPV4 structure variable, initialize your own IP address and port number 29
struct sockaddr_in ownAddr; 30
ownAddr.sin_family = AF_INET;/*Address family IPV4*/ 31
ownAddr.sin_port = htons(OWNPORT); //htons converts the local port number to the network port number 32
ownAddr.sin_addr.s_addr = inet_addr(OWNADDR); //Convert local IP address to network IP address 33
34
bind(socketfd, (struct sockaddr *)&ownAddr,sizeof(struct sockaddr_in)); 35
36
//3. Set the ringtone (listen) listen 37
listen(socketfd,5); 38
39
//4. Waiting for the call (blocking the connection of the receiving client) 40
printf("waiting for client to connect.......\n"); 41
//Define an IPV4 structure variable to store the IP address and port number of the connected client 42
struct sockaddr_in clientAddr; 43
//If you want to get the IP address and port number of the other party, the third parameter must pass in the size of the structure 44
int len = sizeof(struct sockaddr_in); 45
46
//Set the non-blocking attribute to socketfd 47
int status = fcntl(socketfd,F_GETFL);//get the attributes of this socket file descriptor 48
//Set one of the attributes of the resulting file descriptor to non-blocking 49
status |= O_NONBLOCK; 50
int ret = fcntl(socketfd,F_SETFL,status);//Set the state of the variable status to the file descriptor 51
if(ret == -1) 52
{ 53
printf("fcntl error\n"); 54
55
} 56
while(1) 57
{ 58
//At this point, it is non-blocking and will continue to loop 59
int newClientFd = accept(socketfd,(struct sockaddr*)&clientAddr,&len); 60
if(newClientFd != -1) 61
{
//printf("A client is connected.......\n"); 63
//Print the IP address and port number of the connected client, and convert the network byte order to the local byte order 64
printf("connected client IP:%s port
 No:%u\n",inet_ntoa(clientAddr.sin_addr),ntohs(clientAddr.sin_port));
65
} 66
//printf("11111111111\n"); 67
} 68
69
//5. Close 70
close(socketfd); 71
//close(newClientFd); 72
73
return 0; 74
75 }

 

Example 1: Write a server that can accept up to 1000 client connections and can accept connections at any time.
As long as the client connected to the server has data arriving, the data is printed out. Requires non-blocking IO implementation. Can't open thread
Idea: Accept up to 20 client connections
---> User connected successfully ---> Judgment full --> connection refused --> disconnect this user 2
---> User connected successfully ---> underage --> save socket to array 3
4
5 struct ciient{
int clifd[1000]; //Socket 6 for connected user
int count; //Total number of connected users 7
8 }
9
10
 non-blocking IO: Keep asking these connected users and if anyone else is connecting!  11
while(1) 12
{ 13
int clifd[20]; ??? Is there any data coming?  14
}
1 #include<stdio.h>
2 #include<stdio.h>
3 #include <sys/types.h> /* See NOTES */
4 #include <sys/socket.h>
5 #include <sys/socket.h>
6 #include <arpa/inet.h>
7 #include <unistd.h>
8 #include<stdlib.h>
9 #include <string.h>
10 #include <errno.h>
11 #include <signal.h>
12 #include <sys/wait.h>
13 #include <fcntl.h>
14
15 //#include <pthread.h>
16
17 #define SERVER_PORT 9999
18
19
20 struct client{
int clientFd_Array[1000] ;//Store socket file descriptors for all connected clients 21
int clientCount; //Total number of connected clients 22
23 };
24
25
26 void sys_err(const char*err)
27 {
fprintf(stderr,"%s\n",strerror(errno)); 28
exit(0); 29
30 }
31
32
33 int main()
34 {
int ret; 35
struct sockaddr_in clientAddr;//Store the IP address and port number of the connected client 36
int len = sizeof(struct sockaddr_in); 37
struct client clientManager; //Client Struct Management Variables 38
39
//initialize struct 40
clientManager.clientCount = 0; 41
42
printf("server Port:%d PID:%d \n",SERVER_PORT,getpid()); 43
44
//1. Create a socket 45
int socketFd = socket(AF_INET,SOCK_STREAM, 0); 46
if(socketFd == -1){ 47
sys_err("socket error"); 48
} 49
//Port multiplexing 50
int optval = 1; 51
setsockopt(socketFd,SOL_SOCKET,SO_REUSEADDR,&optval, sizeof(optval)); 52
53
//2. Bind your own IP address and port number 54
struct sockaddr_in serverAddr; 55
serverAddr.sin_family = AF_INET; 56
serverAddr.sin_port = htons(SERVER_PORT);//short 57
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); 58
59
ret = bind(socketFd,(struct sockaddr*)&serverAddr,sizeof(struct sockaddr_in)); 60
if(ret == -1){ 61
sys_err("bind error"); 62
} 63
64
//3. Setting monitoring 65
listen(socketFd,128); 66
67
//Set the listening socket to non-blocking attribute 68
//The first step is to get the original attributes of the original socket 69
int state = fcntl(socketFd,F_GETFL); 70
//The second step is to add a non-blocking attribute on the basis of the original 71
state |= O_NONBLOCK; // state = state | O_NONBLOCK 72
//The third step is to set the new attribute back to the file descriptor 73
fcntl(socketFd,F_SETFL,state); 74
75
while(1){ 76
//4. Receive new client connections.... 77
int newClientFd = accept(socketFd, (struct sockaddr*)&clientAddr,&len); 78
if(newClientFd > 0) //Indicates that a client is connected 79
{ 80
printf("A new client is connected IP:%s Port:%hu newClientFd:%d\n", 81
inet_ntoa(clientAddr.sin_addr), 82
ntohs(clientAddr.sin_port), 83
newClientFd); 84
85
//Set the attribute of the client file descriptor to non-blocking attribute 86
//The first step is to get the original attributes of the original socket 87
int state = fcntl(newClientFd,F_GETFL); 88
//The second step is to add a non-blocking attribute on the basis of the original 89
state |= O_NONBLOCK; // state = state | O_NONBLOCK 90
//The third step is to set the new attribute back to the file descriptor 91
fcntl(newClientFd,F_SETFL,state); 92
93
94
//Store each connected client in a struct variable 95
clientManager.clientFd_Array[clientManager.clientCount] =
newClientFd;
96
clientManager.clientCount++; 97
} 98
99
//Poll one by one to see if the connected client has data reaching 100
for(int i=0; i<clientManager.clientCount; i++){ 101
char buf[1024] = {0}; 102
int ret = recv(clientManager.clientFd_Array[i],buf, sizeof(buf),
0);
103
if(ret == 0) //Client disconnected 104
{ 105
//printf("Client exited....\n"); 106
//sleep(1); 107
break; 108
} 109
else if(ret > 0) //There is data coming, you can print 110
{ 111
printf("recv:%s\n",buf); 112
} 113
} 114
115
116
} 117
118
//close 119
close(socketFd);
return 0; 123
124 }

4. Multiplexing

1. Monitor multiple socket IO ports at the same time

Blocking IO ----> can only listen to one socket at the same time
Non-blocking IO--->Always polling to ask if there is data arriving at the IO port, which is a waste of CPU resources

2. What is multiplexing

It is to add the file descriptors that need to be monitored to a set in advance, and then wait for a specified time or an infinite time. If there is no data change in the file descriptor in the set within the specified time, it means that the reception is overtime, and the next specified time is entered to wait again. Once the file descriptors in the set have data changes, other file descriptors without data changes will be excluded from the set and enter the next waiting state again.

3. Features

Monitor multiple IO ports at the same time.

4. Multiplexed function interface -------select -----man 2 select

#include <sys/select.h>
2 #include <sys/time.h>
3 #include <sys/types.h>
4 #include <unistd.h>
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct
timeval *timeout); //poll epoll
parameter:
nfds: The value of the largest file descriptor in the three sets + 1, because this parameter will tell the kernel how many file descriptors are detected before the state
readfds: Monitors the arrival of read data to the file descriptor set, incoming and outgoing parameters
writefds: monitor write data arriving at the file descriptor set, incoming and outgoing parameters
exceptfds: Monitor the occurrence of exceptions to the file descriptor set, such as out-of-band data arrival exceptions, incoming and outgoing parameters
timeout: set blocking waiting time, 3 cases
1. Set NULL, wait forever, this function is blocking (wait infinitely until the state of the file descriptor changes)
2. Set timeval and wait for a fixed time
3. Set the time in timeval to 0, return immediately after checking the description word, and poll
      ---> If this parameter is filled with NULL, it means that this function is blocking (waiting indefinitely until there is a file descriptor status)
state changes)
struct timeval {
2 long tv_sec; /* seconds second*/
3 long tv_usec; /* microseconds microseconds*/
4 };
5
void FD_CLR(int fd, fd_set *set); //Clear fd in the file descriptor set to 0 6
int FD_ISSET(int fd, fd_set *set); //Test whether the fd in the file descriptor set is set to 1 7
void FD_SET(int fd, fd_set *set); //Put the fd position 1 8 in the file descriptor set
void FD_ZERO(fd_set *set); //Clear all bits in the file descriptor set to 0
return value:
success
 data arrives ---->The total number of file descriptors whose state has changed
 No data arrived, timeout-->0
 fail -1
 Notice:
1,select The number of file descriptors that can be monitored is limited by FD_SETSIZE,Generally 1024, simply change the file descriptor opened by the process
 The number cannot be changed select Monitor the number of files
2,Used when solving clients below 1024 select is fine, but if there are too many linked clients, select polling mode
 type, will greatly reduce the server response efficiency
3,Can be cross-platform
/*4_accept Non-blocking IO polling server*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
/*socket*/
#include <sys/types.h>			/* See NOTES */  //man 2 socket
/*inet_addr*/        
#include <sys/socket.h>  //man 3 inet_addr
#include <netinet/in.h>
#include <arpa/inet.h>
/*fcntl*/
#include <fcntl.h>  //man 2 fcntl

#define SERVER_IP	"192.168.11.2"
#define SERVER_PORT	60000

int main(int argc,char **argv)
{
	//create socket
	int socket_fd = socket(AF_INET,SOCK_STREAM,0);
	if(socket_fd < 0)
	{
		perror("socket fail");
		return -1;
	}

	//So setting the port number can be reused, these two statements are placed before bind bind
	int optval = 1;
	setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR,&optval, sizeof(optval));

	//bind
	struct sockaddr_in server_addr;
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(SERVER_PORT);
	server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
	bind(socket_fd,(struct sockaddr *)&server_addr,sizeof(server_addr));
		
	//monitor
	listen(socket_fd,20);

	//Add non-blocking attribute to socket_fd socket
	int status = fcntl(socket_fd, F_GETFL); //Get the status of the file descriptor --> F_GETFL
	status |= O_NONBLOCK ;//Add non-blocking properties on the basis of the original
	fcntl(socket_fd, F_SETFL,status); //Set the state of the variable status to the file descriptor
	
	//take over
	int socket_client;
	int client_cnt[20],cnt=0,j=0;
	//Initialize the client's socket
	for(j=0;j<20;j++)
	{
		client_cnt[j] = -1;
	}	
	
	struct sockaddr_in client_addr;
	socklen_t addrlen = sizeof(client_addr);
	
	int ret;
	char buf[1024] = {0};
	
	//Can accept multiple clients at the same time without opening processes and threads
	while(1)
	{

		//Because the socket_fd socket has the blocking attribute, the accept function is blocked
		socket_client = accept(socket_fd,(struct sockaddr *)&client_addr,&addrlen);
		if(socket_client != -1)
		{
			char *ip = inet_ntoa(client_addr.sin_addr);
			int port = ntohs(client_addr.sin_port);
			printf("A new client is online [ip:%s port:%d]\n",ip,port);
			
			//Set socket_client as a non-blocking attribute and store it in an array
			int status = fcntl(socket_client, F_GETFL); //Get the status of the file descriptor --> F_GETFL
			status |= O_NONBLOCK ;//Add non-blocking properties on the basis of the original
			fcntl(socket_client, F_SETFL,status); //Set the state of the variable status to the file descriptor
			
			//Store all client sockets in an array
			client_cnt[cnt++] = socket_client;	
			//cnt represents the valid client sockets in the array
			//printf("cnt = %d\n",cnt);
		}
		
		#if 0 //View all client sockets in the array (for debugging)
		for(j=0;j<20;j++)
		{
			printf("%d ",client_cnt[j]);	
		}
		printf("\n");
		
		printf("waiting for connection....\n");
		sleep(1);	
		#endif
		
		//Traverse all sockets in the array (loop to receive data from each client)
		for(j=0;j<cnt;j++) //cnt is a valid socket in the array
		{
			memset(buf,0,sizeof(buf));

			//By default, the recv function is a blocking attribute, but now recv is non-blocking
			ret = recv(client_cnt[j],buf,sizeof(buf),0);
			if(ret > 0) //print only valid data
				printf("buf:%s ret:%d\n",buf,ret);
			
		}
	}
	
	//close the socket
	close(socket_fd);
}




/*5_accept Non-blocking IO polling server ip and port*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
/*socket*/
#include <sys/types.h>			/* See NOTES */  //man 2 socket
/*inet_addr*/        
#include <sys/socket.h>  //man 3 inet_addr
#include <netinet/in.h>
#include <arpa/inet.h>
/*fcntl*/
#include <fcntl.h>  //man 2 fcntl

#define SERVER_IP	"192.168.11.2"
#define SERVER_PORT	60000

struct  client_info
{
	int cli_socket;
	struct sockaddr_in cli_addr;
};

int main(int argc,char **argv)
{
	//create socket
	int socket_fd = socket(AF_INET,SOCK_STREAM,0);
	if(socket_fd < 0)
	{
		perror("socket fail");
		return -1;
	}

	//So setting the port number can be reused, these two statements are placed before bind bind
	int optval = 1;
	setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR,&optval, sizeof(optval));

	//bind
	struct sockaddr_in server_addr;
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(SERVER_PORT);
	server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
	bind(socket_fd,(struct sockaddr *)&server_addr,sizeof(server_addr));
		
	//monitor
	listen(socket_fd,20);

	//Add non-blocking attribute to socket_fd socket
	int status = fcntl(socket_fd, F_GETFL); //Get the status of the file descriptor --> F_GETFL
	status |= O_NONBLOCK ;//Add non-blocking properties on the basis of the original
	fcntl(socket_fd, F_SETFL,status); //Set the state of the variable status to the file descriptor
	
	//Initialize the client's socket
	int cnt = 0,j=0;
	struct  client_info info[100];
	for(j=0;j<100;j++)
		info[j].cli_socket = -1;
	
	struct sockaddr_in client_addr;
	socklen_t addrlen = sizeof(client_addr);

	//take over
	int socket_client;	
	int ret;
	char buf[1024] = {0};
	//Can accept multiple clients at the same time without opening processes and threads
	while(1)
	{

		//Because the socket_fd socket has the blocking attribute, the accept function is blocked
		socket_client = accept(socket_fd,(struct sockaddr *)&client_addr,&addrlen);
		if(socket_client != -1)
		{
			char *ip = inet_ntoa(client_addr.sin_addr);
			int port = ntohs(client_addr.sin_port);
			printf("A new client is online [ip:%s port:%d]\n",ip,port);
			
			//Set socket_client as a non-blocking attribute and store it in an array
			int status = fcntl(socket_client, F_GETFL); //Get the status of the file descriptor --> F_GETFL
			status |= O_NONBLOCK ;//Add non-blocking properties on the basis of the original
			fcntl(socket_client, F_SETFL,status); //Set the state of the variable status to the file descriptor
			
			//Store all client sockets in an array
			//cnt represents the valid client sockets in the array
			info[cnt].cli_socket = socket_client;
			info[cnt].cli_addr = client_addr;
			cnt++;
		}
		
		#if 0 //View all client sockets in the array (for debugging)
		for(j=0;j<20;j++)
		{
			printf("%d ",info[j].cli_socket);	
		}
		printf("\n");
		
		printf("waiting for connection....\n");
		sleep(1);	
		#endif
		
		//Traverse all sockets in the array (loop to receive data from each client)
		for(j=0;j<cnt;j++) //cnt is a valid socket in the array
		{
			memset(buf,0,sizeof(buf));

			//By default, the recv function is a blocking attribute, but now recv is non-blocking
/* 			ret = recv(client_cnt[j],buf,sizeof(buf),0);
			if(ret > 0) //print only valid data
				printf("buf:%s ret:%d\n",buf,ret); */
				
			ret = recv(info[j].cli_socket,buf,sizeof(buf),0);	
			if(ret > 0) //print only valid data
				printf("[ip:%s port:%d]buf:%s ret:%d\n",
				inet_ntoa(info[j].cli_addr.sin_addr),
				ntohs(info[j].cli_addr.sin_port),
				buf,ret); 
		}
	}
	
	//close the socket
	close(socket_fd);
}





/*6_Implementing a TCP server using multiplexed select*/
#include<stdio.h>
#include<stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include<stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#define SERVER_IP "192.168.11.2"
#define SERVER_PORT	60000

void sys_err(const char*err)
{
	fprintf(stderr,"%s\n",strerror(errno));
	exit(0);
}

int main()
{
	int ret,max_fd,i=0,imax=0;
	int client[FD_SETSIZE]; //Store the file descriptors of all clients//The macro system has been defined The total number of file descriptors is 1024
	
	struct sockaddr_in clientAddr;//Store the IP address and port number of the connected client
	int len = sizeof(struct sockaddr_in);
	
	printf("server Port:%d PID:%d \n",SERVER_PORT,getpid());
	
	//1. Create a socket (listen socket)
	int socket_fd = socket(AF_INET,SOCK_STREAM, 0);
	if(socket_fd == -1)
	{
		sys_err("socket error");
		//perror("bind"); //The release of the two error bars is the same
	}
	//Port multiplexing
	int optval = 1;
	setsockopt(socket_fd,SOL_SOCKET,SO_REUSEADDR,&optval, sizeof(optval));

	//2. Bind your own IP address and port number
	struct sockaddr_in server_addr;
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(SERVER_PORT);//short
	//server_addr.sin_addr.s_addr = htonl(INADDR_ANY); //Indicates any IP address of the machine
	server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
	
	ret = bind(socket_fd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr_in));
	if(ret == -1)
	{
		sys_err("bind error");
	}
	
	//3. Set up monitoring
	listen(socket_fd,128);
	
	//Define a set of file descriptors
	fd_set rset,allset;
	//empty collection
	FD_ZERO(&allset);
	
	FD_SET(socket_fd, &allset); //Add the listening socket to the collection
	//The largest file descriptor, before no client comes in, the largest file descriptor value is socket_fd
	max_fd = socket_fd;
	
	//Initialize to -1 to initialize the array holding client sockets
	for(int k=0; k<FD_SETSIZE; k++)
	{
		client[k] = -1;
	}
	
	//set blocking time
	struct timeval t;
	t.tv_sec = 5;
	t.tv_usec = 0;
	
	while(1)
	{
		rset = allset; //Every time you loop, you need to reset the select collection
		//Multiplexing, listening to the status of multiple socket file descriptors at the same time -- blocking listening
		//nready represents the total number of file descriptors whose status has changed, (not how many descriptors are stored in it)
		int nready = select(max_fd+1,&rset, NULL,NULL, NULL);
		if(nready == -1)
		{
			perror("select error");
			break;
		}
		
		//The program comes here, indicating that the state of the file descriptors in the collection must have changed
	
		//If the file descriptor of the listening socket has changed, it means that a new client must be connected.
		if(FD_ISSET(socket_fd, &rset))
		{
			//Receive new clients
			int new_clientfd = accept(socket_fd, (struct sockaddr*)&clientAddr,&len);
			
			printf("A new client is connected  IP:%s Port:%hu new_clientfd:%d\n",
					inet_ntoa(clientAddr.sin_addr),
					ntohs(clientAddr.sin_port),
					new_clientfd);
					
			//Add the new client file descriptor to the set 
			FD_SET(new_clientfd, &allset);
			//update file descriptor max
			if(new_clientfd > max_fd)
				max_fd = new_clientfd;
			
			//Add the connected client file descriptor to the array
			for(i=0; i<FD_SETSIZE; i++)
			{
				if(client[i] <0 )
				{
					client[i] = new_clientfd;
					break;
				}
			}
			
			//imax = i;//Store the largest subscript value in the client socket array (you can use this value to record the number of your clients)
			
			//Indicates that only the listening socket file descriptor changes in the set
			if(--nready == 0)
				continue;
		}	
		
		//The program goes here, indicating that there is a client sending data
		for(i=0; i<FD_SETSIZE; i++)
		{
			if(client[i] <0)
				continue;
			
			//Indicates that the client has sent data,
			//The state of the client socket changes, the sentence if(FD_ISSET(client[i], &rset)) is established
			if(FD_ISSET(client[i], &rset))
			{
				char buf[1024] = {0};
				int ret = read(client[i],buf,sizeof(buf));
				if(ret == 0) //The client is disconnected
				{
					printf("A client is disconnected.....\n");
					close(client[i]);//close file descriptor
					
					FD_CLR(client[i],&allset);//remove this client from the file collection
					client[i] = -1;  //The array position corresponding to the file descriptor is set to -1
				}
				
				printf("recv:%s\n",buf);
				//Indicates that all changed file descriptors have been processed by us, then exit
				if(--nready == 0)
					break;
			}		
		}	
	}
	
	//closure
	close(socket_fd);		
	
	return 0;
}

Client.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/*socket*/
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
/*ip*/
#include <netinet/in.h> //man 3 inet_addr
#include <arpa/inet.h>

//IP address of the server
#define SERVER_IP	"192.168.11.2"
#define SERVER_PORT	60000

int main(int argc,char **argv)
{
	//Create a socket --socket
	int socket_fd;
	//AF_INET-->ipv4  SOCK_STREAM-->tcp
	socket_fd = socket(AF_INET,SOCK_STREAM,0);
	if(socket_fd < 0)
	{
		perror("socket fail");
		return -1;
	}
	printf("socket_fd = %d\n",socket_fd);
	
	//Fill IP address (server) -- new structure
	struct sockaddr_in server_addr;
	server_addr.sin_family = AF_INET; //ipv4
	server_addr.sin_port = htons(SERVER_PORT);//host to net (local port number to network port number)
	server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);//Convert local IP to network IP
	
	//connect to the server
	int ret;
	ret = connect(socket_fd,(struct sockaddr *)&server_addr,sizeof(server_addr));
	if(ret < 0)
	{
		printf("connect fail\n");
		return -1;
	}
	
	//send data to server
	char buf[1024] = {0};
	while(1)
	{	
		memset(buf,0,sizeof(buf));
		scanf("%s",buf);
		ret = send(socket_fd,buf,strlen(buf),0);
		printf("send success ret:%d\n",ret);
	}
	
	//close the socket
	close(socket_fd);
	return 0;
}

Tags: Linux network socket server

Posted by vornn on Wed, 09 Nov 2022 03:11:14 +0300