select的优点与使用方法

select用单线程的方法遍历所有待读写的I/O接口, 当有接口可用时就会返回. select可设置电脑阻塞或非阻塞.

特别注意: 每次select前都要重新初始化集合和相关的时间结构

使用的基本过程:

//创建要读写的集合,所有的读接口放一个集合,所有的写接口放另一个集合
fd_set fileset1;
fd_set fileset2; //初始化该集合
FD_ZERO(&fileset1);
FD_ZERO(&fileset2); //向集合中添加要监听的接口
FD_SET(fd1,&fileset1);
FD_SET(fd2,&fileset1);
... //开始监听
int ret=select(maxfd+1,&fileset1,&fileset2,NULL,NULL); //返回后开始处理
switch(ret){
case -1:
if(errno == EINTR)
continue;
err_quit("select");
case 0:
printf("time out\n");
continue;
default:
if(FD_ISSET(fd1,&fileset))
do_service1();
if(FD_ISSET(fd2,&fileset))
do_service2();
if(FD_ISSET(...)
break;
}

实例

只写了server端的,client端差不多

#include <unistd.h>
#include <netdb.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h> #define MAX(a,b) a>b?a:b; void err_quit(const char *s){
perror(s);
exit(1);
} void handler(int signo){
printf("program terminated\n");
exit(0);
} ssize_t readn(int fd,void *buff,size_t count){
char *buffp;
ssize_t nread;
size_t nleft; buffp=(char *)buff;
nleft=count;
while(nleft > 0){
if((nread = read(fd,buffp,nleft)) < 0){
if(errno == EINTR)
continue;
else
return -1;
}else if(nread == 0)
break;
nleft -= nread;
buffp += nread;
}
return count-nleft;
} ssize_t writen(int fd,const void *buff,size_t n){
size_t nleft;
ssize_t nwritten;
const char *ptr; ptr=buff;
nleft=n;
while(nleft > 0){
if((nwritten=write(fd,ptr,nleft)) < 0){
if(nwritten < 0 && errno == EINTR)
continue;
else
return -1;
}else if(nwritten == 0)
break;
nleft -= nwritten;
ptr += nwritten;
}
return n-nleft;
} ssize_t recv_peek(int fd,void *buf,size_t len){
ssize_t ret;
while(1){
ret=recv(fd,buf,len,MSG_PEEK);
if(ret == -1 && errno == EINTR)
continue;
return ret;
}
} ssize_t readline(int fd,void *buf,size_t maxline){
ssize_t ret;
size_t nread;
size_t nleft;
char *bufp; bufp=buf;
nleft=maxline;
while(1){
ret=recv_peek(fd,buf,nleft);
if(ret < 0)
return ret;
else if(ret == 0)
return ret; nread=ret;
int i;
for(i=0;i<nread;i++){
if(bufp[i] == '\n'){
ret=readn(fd,bufp,i+1);
if(ret != i+1)
err_quit("readn"); return ret;
}
} if(nread > nleft)
err_quit("readn"); nleft -= nread;
ret=readn(fd,bufp,nread);
if(ret != nread)
err_quit("readn"); bufp += nread;
} return -1;
} void recv_service(int fd){
char buf[1024]={0};
int ret=readline(fd,buf,sizeof(buf));
if(ret == -1)
err_quit("read");
else if(ret == 0){
printf("peer closed\n");
exit(0);
} fputs(buf,stdout);
} void send_service(int fd){
char buf[1024];
if(fgets(buf,sizeof(buf),stdin) != NULL){
writen(fd,buf,strlen(buf));
}
}
int main(int argc,char *argv[]){
int sockfd,connfd;
socklen_t len;
struct sockaddr_in addr,client; if((sockfd=socket(PF_INET,SOCK_STREAM,0)) < 0)
err_quit("sockfd"); bzero(&addr,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
addr.sin_port=htons(5566); int on=1;
if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) <0)
err_quit("setsockopt"); if(bind(sockfd,(struct sockaddr *)&addr,sizeof(addr))<0)
err_quit("bind"); if(listen(sockfd,10)<0)
err_quit("listen"); len=sizeof(client);
connfd=accept(sockfd,(struct sockaddr *)&client,&len);
if(connfd < 0)
err_quit("accept"); struct sockaddr_in peeraddr;
socklen_t lenth=sizeof(peeraddr);
if(getpeername(connfd,(struct sockaddr *)&peeraddr,&lenth) < 0)
err_quit("getpeername");
printf("peer addr=%s,peer port=%d\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port)); char buf[1024];
bzero(buf,sizeof(buf)); fd_set fileset;
while(1){
FD_ZERO(&fileset);
FD_SET(STDIN_FILENO,&fileset);
FD_SET(connfd,&fileset); int maxfd=MAX(STDIN_FILENO,connfd);
int ret=select(maxfd+1,&fileset,NULL,NULL,NULL);
switch(ret){
case -1:
if(errno == EINTR)
continue;
err_quit("select");
case 0:
printf("time out\n");
continue;
default:
if(FD_ISSET(connfd,&fileset))
recv_service(connfd);
if(FD_ISSET(STDIN_FILENO,&fileset))
send_service(connfd);
break;
}
}
exit(0);
}

最新文章

  1. js三级地区联动
  2. redis配置文件参数说明及命令操作
  3. Jmeter 分布式性能测试
  4. jframe去掉窗体
  5. 如何查看lib文件的导出函数
  6. 集群session的一致性
  7. ED/EP系列3《基本指令》
  8. 快速备份sqlserver2005以上版本数据库的方法-摘自网络
  9. TCP回射客户程序:main函数
  10. poj 3229 The Best Travel Design ( 图论+状态压缩 )
  11. linux操作数据库
  12. MYSQL内置MYSQL数据库中你可以得到的信息
  13. 廖雪峰Java8JUnit单元测试-2使用JUnit-3参数化测试
  14. .aspx、MasterPage、.ascx加载顺序
  15. caffe 笔记
  16. Ubuntu+Qt+OpenCV+FFMPEG环境搭建
  17. input file 图片上传展示重新上传
  18. JS 创建对象总结
  19. linux内核中的IS_ERR()、PTR_ERR()、ERR_PTR()
  20. Check if a user is in a group

热门文章

  1. weBDrriver API接口方法小记
  2. 解决mxGraph放大/缩小在非IE浏览器下overlay图标位置不变化的问题
  3. 返回与Table结构相同的DataTable副本
  4. HR面试总结
  5. 【问题解决方案】Linux中进入目录下文件夹
  6. mpvue中的 钩子函数
  7. 20180209-sys模块
  8. 洛谷P1446/BZOJ1004 Cards Burnside引理+01背包
  9. 解决Minikube start卡住的方法
  10. java this的应用