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函数来实现多路复 ...
随机推荐
- Transaction Managament(事务管理二、Spring事务)
Transaction Managament(事务管理二.Spring事务) Spring事务框架的优势 Spring事务框架将开放过程中事务管理相关的关注点进行了分离,对这些关注点进行了抽象分离 ...
- C++命名规范——谷歌规范
1.文件命名规则 文件名全部小写,可以含下划线或连字符,按项目约定命名,且尽量保证文件名明确.比如: cmd_save_player_info_class.cc ,my_use_full_class. ...
- js事件函数中function(e){}
简单来说就是指向了当前发生的事件(click.mouseover等等),保存了当前事件的信息.如鼠标点击事件,有鼠标的坐标信息.其中,e是标准浏览器传递进去的事件参数,低版本IE不会传递,事件参数放置 ...
- 洛谷 P1968 美元汇率
题目传送门 解题思路: 一道很简单的DP AC代码: #include<iostream> #include<cstdio> using namespace std; int ...
- javascript的自定义对象/取消事件/事件兼容性/取消冒泡
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- Java执行js加密算法
Java执行js加密算法 今日需求:在后端执行一段加密算法,算法是js写的 明白需求以后疯狂百度.最后发现JDK提供了各种脚本的支持(怪笔者学艺不精,第一次见识到这个库,留下不学无术的泪水),正题开始 ...
- 用tkinter写一个记事本程序(未完成)
之前在看tkinter与python编程 ,后面学opengl就把那本书搁置了.几天没用tkinter,怕是基本的创建组件那些都忘记了,所以想着用tkinter试着写一下记事本程序.一开始的时候以为很 ...
- csv文件——简单读操作01
转载:https://www.py.cn/spider/advanced/14381.html import csv with open('C:\\Users\\del\\Desktop\\123.c ...
- java笔记3-手写
关于类的一些笔记
- MySQL--InnoDB 启动、关闭与恢复
在关闭时,参数 innodb_fast_shutdown 影响着表的存储引擎为 InnoDB 的行为.该参数可取值为 0.1.2,默认值为 1. 0:表示在 MySQL 数据库关闭时,InnoDB 需 ...