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函数来实现多路复 ...
随机推荐
- C++基础--智能指针
智能指针其实也不是完全的指针,应该说是像指针一样的类对象,智能指针通常有指针的功能,当然同时也包含了一些额外的功能.目前比较常见的智能指针有auto_ptr.unique_ptr和shared_ptr ...
- 使用Redux管理React数据流要点浅析
在图中,使用Redux管理React数据流的过程如图所示,Store作为唯一的state树,管理所有组件的state.组件所有的行为通过Actions来触发,然后Action更新Store中的stat ...
- Django——URL详解/Django中URL是如何与urls文件匹配的
URL标准语法 protocol://hostname[:port]/path/[:parameters][?query]#fragment https://i.cnblogs.com/EditPos ...
- DQL多表查询
DQL多表查询 一.多表查询实现多个表之间查询数据 1.交叉连接笛卡尔积:A表中的每一行匹配B表中的每一行基本结构:select [数据库名1.]表名1,属性名1,......, [数据库名.]表名. ...
- CTF -攻防世界-misc新手区
此题flag题目已经告诉格式,答案很简单. 将附件下载后,将光盘挂到虚拟机启动 使用 strings linux|grep flag会找到一个O7avZhikgKgbF/flag.txt然后root下 ...
- 《C Primer Plus》- 第二章 C语言概述
本笔记写于2020年1月27日. 本系列文章参考的是<C Primer Plus>(第六版),其中里面会有笔者自己的相关补充. 以下示例均运行于macOS Catalina 10.15.2 ...
- springBoot中的邮件发送
1. 添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...
- 游戏引擎UE4详解!
UE4 的全名是 Unreal Engine 4,中文译为“虚幻引擎4”.UE4 是一款由 Epic Games 公司开发的开源.商业收费.学习免费的游戏引擎.那你了解UE4吗?如果还不清楚,就一起来 ...
- cmd 进入指定文件夹
1.通常情况下,我们要进入其他盘符下的任意目录,需要在CMD窗口运行两次命令:第一次,进入盘符,第二次进入指定目录 #进入D盘 d: #进入D盘下的anaconda目录 cd anacond 2.通过 ...
- PAT Advanced 1079 Total Sales of Supply Chain (25) [DFS,BFS,树的遍历]
题目 A supply chain is a network of retailers(零售商), distributors(经销商), and suppliers(供应商)– everyone in ...