linux select函数

/*
*两个线程一个负责监听客户端,一个负责读客户端请求。 服务器模型,
*主控线程负责accept监听链接的客户端,
*把客户端fd放入任务队列中(),分离子线程则从任务队列取出所有的
*客户端描述加入select并处理客户端读请求。
*13:06:22
*/



#include<stdio.h> #include<sys/socket.h> #include<sys/types.h> #include<stdlib.h> #include<unistd.h> #include<sys/select.h> #include<sys/time.h> #include<pthread.h> #include<memory.h> #include<errno.h> #include<arpa/inet.h> #include<netinet/in.h> #include<signal.h> #include<semaphore.h> #include<malloc.h> #include<fcntl.h> typedef unsigned int uint32; pthread_mutex_t lock;//同步主线程跟select线程操作任务队列 int* queue=NULL; uint32 qcount=0;//任务队列有多少个任务 uint32 qcapty=4;//任务队列容量 /* * *MYLOCK 用于同步accept select两个线程,如果select线程先主线程准备好 *socket启动,那么select 就会报段错误。所以必须在accept准备好后select *在启动,否则一直阻塞。 * */ typedef struct{ int flag;//如果select子线程先执行到select函数会报错,所以必须等到主控线程accept监听。当主线程执行到accept通知子线程否则子线程阻塞。信号灯 sem_t sem; }MYLOCK; struct sockaddr_in server; void deleQueue(int*); void printerror() { printf("%d:%s\n",errno,strerror(errno)); deleQueue(queue); exit(-1); } void addSet(fd_set* set,char* p){ FD_ZERO(set); int i=0; for(;i<qcapty;i++){//必须全部检索,因为队列fd不是顺序排列,可能有空位。 int tem=*(queue+i); if(tem!=0){ FD_SET(tem,set); // if(p==NULL) // printf("addset: fd=%d\n",tem); } } } void initQueue(int **p,int n){ *p=(int*)malloc(sizeof(int)*n); memset(*p,0,sizeof(int)*n); pthread_mutex_init(&lock,0); } void deleQueue(int* p){ free(p); } int getMax(int* p,int num){//取得队列的最大描述符 pthread_mutex_lock(&lock); int i=0; int tem=0; for(;i<num;i++){ if(tem<*(p+i)){ tem=*(p+i); } } pthread_mutex_unlock(&lock); return tem; } void enlargeQueue(int **pqueue,uint32* oldcapty){//当任务队列不能容下任务的话,要扩容,释放掉以前的队列,新建队列并考数据。初始16每次左移1位,扩大一倍。 uint32 old=*oldcapty; *oldcapty=(*oldcapty)<<1; int* nice=(int*)malloc((*oldcapty)*sizeof(int)); memset(nice,0,sizeof(int)*(*oldcapty)); memcpy(nice,*pqueue,sizeof(int)*old); free(*pqueue); *pqueue=nice; } void addQueue(int value){ pthread_mutex_lock(&lock); int i=0; if(qcapty-qcount<2){ enlargeQueue(&queue,&qcapty); printf("kong rong le have %d client , capty=%d\n",qcount,qcapty); } for(;i<qcapty;i++){ if(*(queue+i)==0){ *(queue+i)=value; qcount++; // printf("have fd num = %u\n",qcount); break; } } pthread_mutex_unlock(&lock); } int getQueue(int dex){ pthread_mutex_lock(&lock); int tem= *(queue+(dex-1)); pthread_mutex_unlock(&lock); return tem; } void removeQueue(int value){ pthread_mutex_lock(&lock); int i=0; for(;i<qcapty;i++){ if(*(queue+i)==value){ *(queue+i)=0; qcount--; } } pthread_mutex_unlock(&lock); } fd_set set; MYLOCK mlock; void* th_hand(void* p){ sem_wait(&mlock.sem); while(!mlock.flag){//等主控线程执行到accept并通知子线程执行。 sem_post(&mlock.sem); sleep(1); sem_wait(&mlock.sem); } sem_post(&mlock.sem); printf("sub before select\n"); while(1){ addSet(&set,NULL); struct timeval timeout={1,0}; int s=select(getMax(queue,qcapty)+1,&set,NULL,NULL,&timeout); if(s<0){ printerror(); }else if(s==0){ continue; }else{ int i=0; for(;i<qcapty;i++){ int readfd=*(queue+i); if(FD_ISSET(readfd,&set)){ char buff[40]={0}; printf("go read fd %d\n",readfd); int rn=read(readfd,buff,sizeof(buff)-1); if(rn==0){ struct sockaddr_in client; memset(&client,0,sizeof(client)); int len=sizeof(client); getpeername(readfd,(struct sockaddr*)&client,&len); // printf("%s is closed\n",inet_ntoa(client.sin_addr)); removeQueue(readfd); // printf("move fd %d\n",readfd); /* int i=0; for(;i<qcapty;i++){ int tem=*(queue+i); printf("close : fd=%d\n",tem); } */ close(readfd); }else if(rn==-1){ printf("read fd error%d %d\n",readfd,rn); printerror(); }else if(rn>0){ int wr=write(STDOUT_FILENO,buff,rn); } } } } } } int initSocket(int port){ memset(&server,0,sizeof(server)); server.sin_family=AF_INET; server.sin_addr.s_addr=htonl(INADDR_ANY); server.sin_port=htons(port); int sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd==-1){ printerror(); } int res=bind(sockfd,(struct sockaddr*)&server,sizeof(struct sockaddr)); if(res==-1){ printerror(); } if(-1==listen(sockfd,10)){ printerror(); } sem_wait(&mlock.sem); mlock.flag=1;//通知子线程可以从队列取任务添加到select sem_post(&mlock.sem); printf("main before accept\n"); while(1){ int fd; if((fd=accept(sockfd,NULL,NULL))==-1){ printerror(); } printf("%d non is unblock\n",O_NONBLOCK); addQueue(fd);//当有客户端连接,加入到任务队列中。 } } void sig_hand(int signo){ if(signo==SIGINT){ printf("have %d client\n",qcount); deleQueue(queue); exit(0); } } pthread_t pid; int main(int argc,char** argv){ if(argc<2){ puts("please input port\n"); exit(-1); } int port=atoi(argv[1]); signal(SIGINT,sig_hand); memset(&mlock,0,sizeof(mlock)); sem_init(&mlock.sem,0,1); mlock.flag=0; initQueue(&queue,qcapty); pthread_create(&pid,NULL,th_hand,(void*)0); pthread_detach(pid); initSocket(port); }

 

posted @ 2019-02-28 13:00  ForMeDream  阅读(893)  评论(0编辑  收藏  举报