select函数就一socket文件描述符监测函数,可以监测读和写。没有read和write时候将阻塞在那儿,相比于多进程和多线程处理,它更加节省资源。废话不多说 上demo
#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <pthread.h>
#include <string.h>
#include <stdlib.h>
#define TCP_PORT 9999
#define SOCK_NUM 1024
int main()
{
fd_set allset,rest;
int socket_ser,socket_accept;
int socketfd[SOCK_NUM];
struct sockaddr_in addr,addr_c;
int maxfd;
char recfub[1500];
socket_ser = socket(AF_INET,SOCK_STREAM,0);
bzero(&addr,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(TCP_PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(socket_ser,(struct sockaddr *)&addr,sizeof(addr));
listen(socket_ser,128);
//首先监听socket_ser
FD_ZERO(&allset);
FD_SET(socket_ser,&allset);
memset(socketfd,-1, sizeof(socketfd));
maxfd = socket_ser;
while (1)
{
rest = allset;
//监听maxfd+1个文件描叙符的读
int num = select(maxfd+1,&rest,NULL,NULL,NULL);
if(num<0)
{
printf("服务器挂了\n");
}
//select的返回只有有读入的文件描述符是1
if(FD_ISSET(socket_ser,&rest))
{
int i;
for ( i = 0; i < SOCK_NUM; ++i) {
if (socketfd[i] == -1)
break;
}
if (SOCK_NUM == i)
{
printf("满了,挂了\n");
exit(1);
}
//保存新的socket
bzero(&addr_c,sizeof(addr_c));
int len = sizeof(addr_c);
socketfd[i] = accept(socket_ser,(struct sockaddr*)&addr_c,(socklen_t *)&len);
//加入到select监控
FD_SET(socketfd[i],&allset);
//更新下监测的文件描述符序号
if(socketfd[i]>maxfd)
{
maxfd = socketfd[i];
}
char recip[16];
printf("Ip is %s,Port is %d\n",inet_ntop(AF_INET,&addr_c.sin_addr,recip,ntohs(addr_c.sin_port)));
num--;
}
if(num>0)
{
while(num)
{
for (int i = 0; i <SOCK_NUM ; ++i) {
if(socketfd[i]>0 && FD_ISSET(socketfd[i],&rest))
{
bzero(&recfub,sizeof(recfub));
int n=0;
if (0 == (n=read(socketfd[i],recfub,sizeof(recfub))))
{
FD_CLR(socketfd[i],&allset);
printf("socket: %d关闭连接\n", socketfd[i]);
close(socketfd[i]);
if (socketfd[i] >= maxfd)
{
maxfd --;
}
socketfd[i]=-1;
break;
} else
{
printf("%s\n",recfub);
write(socketfd[i],recfub,strlen(recfub));
}
}
num --;
break;
//处理完一个文件描述符继续下一个
}
}
}
}
close(socket_ser);
return 0;
}