The usage of I/Of multiplexing select in network programming

Keywords: socket network Programming Linux

The usage of select in network programming


Note: This paper does not explain the select function, related parameters and structure

select use flow chart

Create with Rapha ë l 2.2.0 define select related variable define the related data of select related variable initiate call select to monitor whether there are new links in the read event new link descriptors put into array and descriptor set batch read link descriptors yesno

Note: socket process is not written

Lines of code to be added in network programming and their significance

1. Define select related variables

	int listenfd,connfd,i;
	/*Socket descriptor / link descriptor (input phase) / variable*/	

	int nread,maxfd,maxi,sockfd;
	/*Ready number / maximum link descriptor / used to record the current maximum used subscript of the link descriptor array, reducing useless traversal/
		Link descriptor (the difference is that it is used for I/O multiplexing traversal)*/
	
	int client[FD_SETSIZE];
	/*Store the entered link descriptor*/
	
	fd_set allest,rset;
	/*File set descriptor: all sets / readable sets*/

2.select the related data initialization of related variables

	maxfd = listenfd; 
	/*Initialize the maximum link descriptor,*/
	maxi = -1;
	for (i = 0; i < FD_SETSIZE; i++) client[i] = -1;
	FD_ZERO(&allest);
	/*Empty allset descriptor set*/
	FD_SET(listenfd, &allest);
	 /*Add listening descriptor to allset*/

3.select to monitor readable events

	rset = allest;
	nread = select(maxfd+1, &rset, NULL, NULL, NULL);
		/*Call select to monitor readable events*/

4. Put new link descriptors into array and descriptor set

	if (FD_ISSET(listenfd, &rset))
	/*Determine whether there is a change in the server socket (whether there is a new link)*/
	{
		cliaddr_lin = sizeof(cliaddr);
		connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_lin);
		for (i = 0; i < FD_SETSIZE; i++)
		{
			if (client[i] < 0)
			{
				client[i] = connfd;
/				/*New link descriptor in array*/
				break;
			}
		}
		FD_SET(connfd, &allest);
		 /* Join connfd from customer to descriptor set */
		if (connfd > maxfd) maxfd = connfd;
		/*New link descriptor*/
		if (i > maxi) maxi = i;
		if (--nread == 0) continue;
	}

5. Batch read link descriptor

for (i = 0; i <= maxi; i++)
{
	if ((sockfd = client[i]) < 0) continue;
	if (FD_ISSET(sockfd, &rset))
	{
		if ((n = read (sockfd, buf, MAXLIN)) == 0)
		{
			close(sockfd);
			FD_CLR(sockfd, &allest);
			client[i] = -1;
		}else
		{
			if (n < 0) perror("read:");
			if (n > 0) write(sockfd, buf, n);
		}
	if (--nread == 0) break;
	}
}

routine

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

#define LINK_NUMBER 20
#define SERV_PORT 8000
#define MAXLIN 100

int main(int argc, char const *argv[])
{
	int listenfd,connfd,i;
	int nread,maxfd,maxi,sockfd;
	int client[FD_SETSIZE];
	ssize_t n;
	fd_set allest,rset;
	socklen_t cliaddr_lin;
	struct sockaddr_in servaddr,cliaddr;
	char buf[MAXLIN],str[INET_ADDRSTRLEN];

	listenfd = socket(AF_INET,SOCK_STREAM,0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(SERV_PORT);

	bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

	listen(listenfd,LINK_NUMBER);

	maxfd = listenfd;
	maxi = -1;
	for (i = 0; i < FD_SETSIZE; i++) client[i] = -1;
	FD_ZERO(&allest);
	FD_SET(listenfd, &allest);

	while(1)
	{
		rset = allest;
		nread = select(maxfd+1, &rset, NULL, NULL, NULL);
		if (nread < 0)
		{
			perror("select error:");
			break;
		}

		if (FD_ISSET(listenfd, &rset))
		{
			cliaddr_lin = sizeof(cliaddr);
			connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_lin);

			printf("received from %s at PORT %d\n",
			       inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
			       ntohs(cliaddr.sin_port));

			for (i = 0; i < FD_SETSIZE; i++)
			{
				if (client[i] < 0)
				{
					client[i] = connfd;
					break;
				}
			}
			if (i == FD_SETSIZE)
			{
				perror("too many clients");
				exit(1);
			}
			FD_SET(connfd, &allest);
			if (connfd > maxfd) maxfd = connfd;
			if (i > maxi) maxi = i;
			if (--nread == 0) continue;	
		}

		for (i = 0; i <= maxi; i++)
		{
			if ((sockfd = client[i]) < 0) continue;

			if (FD_ISSET(sockfd, &rset))
			{
				if ((n = read (sockfd, buf, MAXLIN)) == 0)
				{
					close(sockfd);
					FD_CLR(sockfd, &allest);
					client[i] = -1;
				}else
				{
					if (n < 0)
					{
						perror("read:");
					}
					if (n > 0)
					{
						write(sockfd, buf, n);
					}
	
				}
			
				if (--nread == 0) break;
			}
		}
		/*socket*/
		/*while(1)
		{
			if((n = read(connfd,buf,MAXLIN)) <= 0) 
			{
				printf("err" );
				break;
			}

			printf("received from %s at PORT %d::%s\n",
			       inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
			       ntohs(cliaddr.sin_port),buf);

			write(connfd,buf,n);
		}
		close(connfd);*/
	}

	return 0;
}

References and blogs

Linux chat room project – ChatRome (select Implementation)
Detailed explanation of select function of Linux I/O reuse
The second edition of unix network programming

Posted by hdpt00 on Fri, 20 Dec 2019 07:11:20 -0800