Linux c/c++ 基于socket select 复用技术,使用一个int 数组记录服务端连接的socket 信息,在本文中采用一个固定大小数组来管理socket信息,避免连接增多数组长度无限制增长。
#define MAXSIZE 1024
int maxindex=0; //最大socket_fd 数组
int allfds[MAXSIZE]; //保存socket_fd 数组
int maxfd = -1;
fd_set rfds;
int main()
{
for(int y = 0;y<MAXSIZE;y++)
allfds[y] = -1;
int ss = socket(AF_INET,SOCK_STREAM,0);
server_sockaddr.sin_family = AF_INET;
server_sockaddr.sin_port = htons(6666);
server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
int flag =1;
int result = setsockopt(ss, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
if(bind(ss,(struct sockaddr*)&server_sockaddr,sizeof(server_sockaddr)) == -1)
{
printf("bind error\n");
exit(1);
}
if(listen(ss,20) == -1)
{
...
}
maxfd = ss;
allfds[maxindex] = ss;
while(1)
{
FD_ZERO(&rfds);
for(int i = 0;i<MAXSIZE;i++)
{
if(allfds[i]!= -1)
FD_SET(allfds[i],&rfds);
}
int retval;
retval = select(maxfd+1, &rfds, NULL, NULL,NULL);
if(retval == -1){
printf("seleect error\n");
break;
}
else if(retval == 0)
{
// printf("server no input\n");
continue;
}
else{
for(int i =0;i<MAXSIZE;i++)
{
if(retval == 0)
break;
}
if(!FD_ISSET(allfds[i],&rfds))
{
continue;
}
if(allfds[i] == ss)
{
retval--;
struct sockaddr_in client_addr;
socklen_t length = sizeof(client_addr);
int conn = accept(ss,(struct sockaddr*)&client_addr,&length);
if(conn < 0)
{
printf("accept error\n");
}
else{
printf("Client[%d], welcome!\n",conn);
}
for(int n=0;n<MAXSIZE;n++) //找为-1的空位,如果大于最大sockfd ,更新最大值和下标
{
if(allfds[n] == -1)
{
allfds[n] = conn;
if(maxfd < conn)
{
maxfd = conn;
maxindex = n;
}
break;
}
}
}
else{
char msg[MAXSIZE] = {0x0};
int nrecvSize;
if((nrecvSize = read(allfds[i],msg,MAXSIZE))< 0)
{
continue;
}
else if(nrecvSize == 0 )
{
printf("client has disconnected!\n");
close(allfds[i]);
FD_CLR(allfds[i], &rfds);
allfds[i] = -1; //释放对应下标元素
if(i == maxindex)
{
int maxnum = -1;
for (int maxsearch = 0 ;maxsearch < MAXSIZE;maxsearch++)//重新遍历找最大值
{
if(allfds[maxsearch] > maxnum)
{
maxnum = allfds[maxsearch];
maxindex = maxsearch;
}
}
maxfd = maxnum;
}
}
else{
printf("msg is %s\n",msg);
}
}
}