select在socket中的使用示例

本文介绍了一个基于Select机制的Socket服务器实现案例,通过非阻塞方式处理多个客户端连接请求及数据收发,有效实现了I/O多路复用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在socket通信中,使用select能够达到I/O Multiplexing的效果。理论总是有点让人摸不清头脑,还是看例子好理解。

程序实现功能比较简单,就是“多客户端向服务器发送信息”。

先看实验结果:

启动服务器


启动客户端一


可见客户端一的套接字描述符是4


启动客户端二


可见客户端二的套接字描述符是5


客户端一发送“hello”到服务器




客户端二发送“world”到服务器




关闭客户端一


关闭客户端二


服务器程序如下:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

#define  SERVER_PORT  3456
#define  DEBUG        0			//debug macro
#define  TRUE   	  1
#define  FALSE 		  0



int
main(int argc,char **argv){
	int listen_sfd,max_sfd,new_sfd;
	int on=1,rv,ready_sfd_num,i,connection_close=FALSE,server_end=FALSE;
	fd_set master_set,working_set;
	struct sockaddr_in sockaddr;
	struct timeval timeout;
	char buf[100];

	/*
	 * create a AF_INET SOCKET_STREAM socket
	 * */
	listen_sfd=socket(AF_INET,SOCK_STREAM,0);
	if(listen_sfd < 0){
		perror("server socket ");
		exit(EXIT_FAILURE);
	}

#if DEBUG
	printf("listen_sfd=%d\n",listen_sfd);
#endif

	/*
	 * set socket to SO_REUSEADDR
	 * */
	rv=setsockopt(listen_sfd,SOL_SOCKET,SO_REUSEADDR,(void *)&on,sizeof(on));
	if(rv < 0){
		perror("server setsockopt");
		close(listen_sfd);
		exit(EXIT_FAILURE);
	}

	/*
	 * set socket to non-blocking
	 * */
	rv=fcntl(listen_sfd,F_SETFL,O_NONBLOCK);
	if(rv<0){
		perror("server fcntl ");
		close(listen_sfd);
		exit(EXIT_FAILURE);
	}

	/*
	 * bind socket to localhost interface
	 * */
	memset(&sockaddr,0,sizeof(sockaddr));
	sockaddr.sin_family     =AF_INET;
	sockaddr.sin_port		=htons(SERVER_PORT);
	sockaddr.sin_addr.s_addr=htonl(INADDR_ANY);
	rv=bind(listen_sfd,(struct sockaddr *)&sockaddr,sizeof(sockaddr));
	if(rv<0){
		perror("server bind ");
		close(listen_sfd);
		exit(EXIT_FAILURE);
	}

	/*
	 * set back log to 10
	 * */
	rv=listen(listen_sfd,10);
	if(rv<0){
		perror("server listen ");
		close(listen_sfd);
		exit(EXIT_FAILURE);
	}

	/*
	 * file descriptors set operations
	 * */
	FD_ZERO(&master_set);
	FD_ZERO(&working_set);
	max_sfd=listen_sfd;
	FD_SET(listen_sfd,&master_set);

	/*
	 * infinite loop of select
	 * */
	while(1){
		memcpy(&working_set,&master_set,sizeof(master_set));

		/*
		 * set timeout value to 2 minutes
		 * */
		timeout.tv_sec =2*60;
		timeout.tv_usec=0;

		ready_sfd_num=select(max_sfd+1,&working_set,NULL,NULL,&timeout);
		/*
		 * select return value has three conditions:
		 * 1.<0 ---error
		 * 2.==0---timeout value expires
		 * 3.>0 ---successful
		 * */
		if(ready_sfd_num<0){
			perror("server select ");
			break;
		}

		if(ready_sfd_num==0){
			printf("Time Out,End Program!\n");
			break;
		}

		/*
		 * when select function is invoked successfully,there exists two conditions:
		 * 1.new connections
		 * 2.new data
		 * */
		for(i=0;i<=max_sfd && ready_sfd_num>0;++i){

			if(FD_ISSET(i,&working_set)){
				ready_sfd_num--;
				/*
				 * new connection coming ,accept all incoming connections in queue list
				 * */
				if(i==listen_sfd){
					while(1){
						new_sfd=accept(listen_sfd,NULL,NULL);

						if(new_sfd <0){
							if(errno != EWOULDBLOCK){
								perror("server accept");
								server_end=TRUE;
							}
							break;
						}

						if(new_sfd >0){
							/*
							 * set new_sfd to non-blocking
							 * */
							rv=fcntl(new_sfd,F_SETFL,O_NONBLOCK);
							if(rv<0){
								perror("server fcntl ");
								close(new_sfd);
								break;
							}

							FD_SET(new_sfd,&master_set);
							if(new_sfd>max_sfd)
								max_sfd=new_sfd;
							printf("new connection created,socket---%d\n",new_sfd);


						}
					}
				}

				/*
				 * new data coming on connected socket
				 * */
				else{
					while(1){
						rv=recv(i,buf,sizeof(buf),0);
						if(rv<0){
							if(errno != EWOULDBLOCK ){
								perror("servre recv");
								connection_close=TRUE;
							}
							break;
						}

						if(rv==0){
							connection_close=TRUE;
							break;
						}

						printf("server receive:%s,from socket---%d\n",buf,i);
					}
				}
				if(connection_close){
					close(i);
					printf("%d socket closed!\n",i);
					FD_CLR(i,&master_set);
					if(i==max_sfd){
						while(FD_ISSET(max_sfd,&master_set)==FALSE)
							max_sfd--;
					}
				}
			}
		}//end of ready sfd loop

	/*determine whether end server or not*/
		if(server_end)
			break;
	}//end of select

	/*
	 * cleanup
	 * */
	while(max_sfd>=0){
		if(FD_ISSET(max_sfd,&master_set))//which one :working_set or master_set!!!!master_set
			close(max_sfd);
		max_sfd--;
	}

	return 0;
}//end of main


客户端程序如下:

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

#define SERVER_PORT  3456

int
main (int argc, char *argv[]){
   int    len, rc;
   int    sockfd;
   char   send_buf[80];
   struct sockaddr_in   addr;

   sockfd = socket(AF_INET, SOCK_STREAM, 0);
   if (sockfd < 0){
      perror("socket");
      exit(-1);
   }

   memset(&addr, 0, sizeof(addr));
   addr.sin_family      = AF_INET;
   addr.sin_addr.s_addr = htonl(INADDR_ANY);
   addr.sin_port        = htons(SERVER_PORT);

   rc = connect(sockfd,
                (struct sockaddr *)&addr,
                sizeof(struct sockaddr_in));
   if (rc < 0){
      perror("connect");
      close(sockfd);
      exit(-1);
   }

   while(1){
	  printf("Enter message to be sent:\n");
	  memset(send_buf,0,sizeof(send_buf));
	  scanf("%s",send_buf);
	//  printf("%d\n",strlen(send_buf));
	  len = send(sockfd, send_buf, strlen(send_buf) + 1, 0);
	  if (len != strlen(send_buf) + 1){
		 perror("send");
		 close(sockfd);
		 exit(-1);
	  }
	  printf("%d bytes sent\n", len);
   }
   close(sockfd);

   return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coffee_baba

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值