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=;//任务队列有多少个任务
uint32 qcapty=;//任务队列容量 /*
*
*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(-);
} void addSet(fd_set* set,char* p){
FD_ZERO(set);
int i=;
for(;i<qcapty;i++){//必须全部检索,因为队列fd不是顺序排列,可能有空位。
int tem=*(queue+i);
if(tem!=){
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,,sizeof(int)*n);
pthread_mutex_init(&lock,);
} void deleQueue(int* p){
free(p);
} int getMax(int* p,int num){//取得队列的最大描述符
pthread_mutex_lock(&lock);
int i=;
int tem=;
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)<<;
int* nice=(int*)malloc((*oldcapty)*sizeof(int));
memset(nice,,sizeof(int)*(*oldcapty));
memcpy(nice,*pqueue,sizeof(int)*old);
free(*pqueue);
*pqueue=nice;
} void addQueue(int value){
pthread_mutex_lock(&lock);
int i=;
if(qcapty-qcount<){
enlargeQueue(&queue,&qcapty);
printf("kong rong le have %d client , capty=%d\n",qcount,qcapty);
}
for(;i<qcapty;i++){
if(*(queue+i)==){
*(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-));
pthread_mutex_unlock(&lock);
return tem;
} void removeQueue(int value){
pthread_mutex_lock(&lock);
int i=;
for(;i<qcapty;i++){
if(*(queue+i)==value){
*(queue+i)=;
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();
sem_wait(&mlock.sem);
}
sem_post(&mlock.sem);
printf("sub before select\n");
while(){
addSet(&set,NULL);
struct timeval timeout={,};
int s=select(getMax(queue,qcapty)+,&set,NULL,NULL,&timeout);
if(s<){
printerror();
}else if(s==){
continue;
}else{
int i=;
for(;i<qcapty;i++){
int readfd=*(queue+i);
if(FD_ISSET(readfd,&set)){
char buff[]={};
printf("go read fd %d\n",readfd);
int rn=read(readfd,buff,sizeof(buff)-);
if(rn==){
struct sockaddr_in client;
memset(&client,,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==-){
printf("read fd error%d %d\n",readfd,rn);
printerror();
}else if(rn>){
int wr=write(STDOUT_FILENO,buff,rn);
}
}
}
}
}
} int initSocket(int port){
memset(&server,,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,);
if(sockfd==-){
printerror();
}
int res=bind(sockfd,(struct sockaddr*)&server,sizeof(struct sockaddr));
if(res==-){
printerror();
}
if(-==listen(sockfd,)){
printerror();
} sem_wait(&mlock.sem);
mlock.flag=;//通知子线程可以从队列取任务添加到select
sem_post(&mlock.sem); printf("main before accept\n");
while(){
int fd;
if((fd=accept(sockfd,NULL,NULL))==-){
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();
}
} pthread_t pid; int main(int argc,char** argv){
if(argc<){
puts("please input port\n");
exit(-);
}
int port=atoi(argv[]);
signal(SIGINT,sig_hand);
memset(&mlock,,sizeof(mlock));
sem_init(&mlock.sem,,);
mlock.flag=;
initQueue(&queue,qcapty);
pthread_create(&pid,NULL,th_hand,(void*));
pthread_detach(pid);
initSocket(port); }
linux select函数的更多相关文章
- linux select函数详解
linux select函数详解 在Linux中,我们可以使用select函数实现I/O端口的复用,传递给 select函数的参数会告诉内核: •我们所关心的文件描述符 •对每个描述符,我们所关心的状 ...
- linux select函数详解【转】
转自:http://www.cnblogs.com/ccsccs/articles/4224253.html 在Linux中,我们可以使用select函数实现I/O端口的复用,传递给 select函数 ...
- linux select函数:Linux下select函数的使用详解【转】
本文转载自;http://www.bkjia.com/article/28216.html Linux下select函数的使用 Linux下select函数的使用 一.Select 函数详细介绍 Se ...
- linux select函数 shutdown函数
#include<sys/select.h> #include<sys/time.h> int select(int maxfdp1,fd_set *readset,fd_se ...
- socket通信时如何判断当前连接是否断开--select函数,心跳线程,QsocketNotifier监控socket
client与server建立socket连接之后,如果突然关闭server,此时,如果不在客户端close(socket_fd),会有不好的影响: QsocketNotifier监控socket的槽 ...
- Linux下select函数的使用
一.Select 函数详细介绍 Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect. accept.recv ...
- linux c语言 select函数用法
linux c语言 select函数用法 表头文件 #i nclude<sys/time.h> #i nclude<sys/types.h> #i nclude<unis ...
- linux c语言 select函数使用方法
linux c语言 select函数使用方法 表头文件 #i nclude<sys/time.h> #i nclude<sys/types.h> #i nclude<un ...
- linux网络编程:select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET(转)
从别人的博客中转载过来了这一篇文章,经过重新编辑排版之后展现于此,做一个知识点保存与学习. select函数用于在非阻塞中,当一个套接字或一组套接字有信号时通知你,系统提供select函数来实现多路复 ...
随机推荐
- jQuery搜索框输入实时进行查询
在手机上,我们期望在搜索框中输入数据,能够实时更新查询出来的内容,不需要按回车. 实现方式为: $(".search").bind("input propertychan ...
- 利用kindlegen实现txt格式小说转换为mobi格式小说(C++实现)
一直以来喜欢在kindle上看小说,kindle不伤眼,也可以帮助控制玩手机的时间.但在kindle上看txt格式的网络小说就很头疼了,这类小说在kindle上是没有目录的,而且篇幅巨长.所以一直以来 ...
- URAL_1018 Binary Apple Tree 树形DP+背包
这个题目给定一棵树,以及树的每个树枝的苹果数量,要求在保留K个树枝的情况下最多能保留多少个苹果 一看就觉得是个树形DP,然后想出 dp[i][j]来表示第i个节点保留j个树枝的最大苹果数,但是在树形过 ...
- springboot-jar-web
预览 与springboot-jar的区别是: 1.pom.xml 将 <dependency> <groupId>org.springframework.boot</g ...
- 基于仿生算法的智能系统I
仿生算法仿生算法是什么? 什么是仿生? 蜜蜂会造房子,人类就学习蜜蜂盖房子的方法,之后便有了航空建造工程的蜂窝结构. 仿生是模仿生物系统的功能和行为,来建造技术系统的一种科学方法.生活仿生作品现代的飞 ...
- javascript语法规范和良好的变成习惯
1.1空白和多行书写 1.空白:空格键输入的空白.tab键输入的空白以及回车键输入的空白 2.多行书写,不能将引号内的字符串放到两行,不然容易报错. 1.2点语法 . 点语法表达式由对象开始,接着是一 ...
- POJ - 3977 Subset(二分+折半枚举)
题意:有一个N(N <= 35)个数的集合,每个数的绝对值小于等于1015,找一个非空子集,使该子集中所有元素的和的绝对值最小,若有多个,则输出个数最小的那个. 分析: 1.将集合中的元素分成两 ...
- 7.3 使用while 循环来处理列表和字典
# 7.3.1 在列表之间移动元素 # confirmed_users.py # 首先,创建一个待验证用户列表 # 和一个用于存储已验证用户的空列表 uncomfirmed_users = ['jam ...
- mybatis中foreach collection的三种用法
foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合. foreach元素的属性主要有 item,index,collection,open,separator,close. ...
- (转)ERROR : The processing instruction target matching "[xX][mM][lL]" is not allowed.
现象:ERROR : The processing instruction target matching "[xX][mM][lL]" is not allowed. 异常解 ...