IO复用使得程序可以同一时候监听多个文件描写叙述符,比方client须要同一时候处理用户输入和网络连接,server端须要同一时候处理监听套接字和连接套接字,select系统调用可以使得我们监听自己感兴趣描写叙述符。可读,可写,异常等事件。select能处理的异常仅仅有带外数据。能同一时候处理描写叙述符的数量受限于FD_SETSIZE的大小(一般1024)。以下这个程序展示了它的一般使用方法。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <libgen.h> //basename
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <assert.h>
#include <errno.h> int main(int argc, char *argv[]){
int i, maxi;
char buf[1024];
fd_set read_fds, all_read_fds;
fd_set exception_fds, all_exception_fds;
int nready, connectfd[FD_SETSIZE];
int connfd,sockfd,maxfd; struct sockaddr_in client_address;
socklen_t client_addrlen = sizeof(client_address); if(argc <= 2){
printf("usage: %s ip_address port_number\n", basename(argv[0]));
return 1;
} const char *ip = argv[1];
int port = atoi(argv[2]); int ret = 0;
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
inet_pton(AF_INET, ip, &address.sin_addr);
address.sin_port = htons(port); int listenfd = socket(AF_INET, SOCK_STREAM, 0);
assert(listenfd >= 0);
ret = bind(listenfd, (struct sockaddr *)&address, sizeof(address));
assert(ret != -1);
ret = listen(listenfd, 5);
assert(ret != -1); maxfd = listenfd;
maxi = -1;
for(i= 0; i < FD_SETSIZE; i++)
connectfd[i] = -1;
FD_ZERO(&all_read_fds);
FD_ZERO(&all_exception_fds);
FD_SET(listenfd, &all_read_fds);
//do not care about the OOB of listen socket while(1){
read_fds = all_read_fds;
exception_fds = all_exception_fds;
memset(buf, 0, sizeof(buf));
nready = select(maxfd + 1, &read_fds, NULL, &exception_fds, NULL);
//new client connection coming
if(FD_ISSET(listenfd, &read_fds)){
connfd = accept(listenfd, (struct sockaddr *)&client_address, &client_addrlen);
if(connfd < 0){
perror("accept failed\n");
exit(-1);
} for(i=0; i < FD_SETSIZE; i++)
if(connectfd[i] < 0){
connectfd[i] = connfd;
break;
}
if( i == FD_SETSIZE){
printf("too many clients..\n");
exit(-1);
}
// add new descriptor to the read set and exception set
FD_SET(connfd, &all_read_fds);
FD_SET(connfd, &all_exception_fds);
if(connfd > maxfd)
maxfd = connfd;
if(i > maxi)
maxi = i;// update the max index in connectfd[]
//we complete the listen socktet processing
if(--nready <= 0)
continue;
}
for(i = 0; i <= maxi; i++){
//check all the connected clients for data
if((sockfd = connectfd[i]) < 0)
continue;
if(FD_ISSET(sockfd, &read_fds)){
ret = recv(sockfd, buf, sizeof(buf) - 1, 0);
if(ret <= 0)
break;//connection closed
// process logic
printf("get %d bytes of normal data:%s\n", ret, buf);
//we complete the listen socktet processing
if(--nready <= 0)
continue;
}
for(i = 0; i <= maxi; i++){
//check all the connected clients for data
if((sockfd = connectfd[i]) < 0)
continue;
if(FD_ISSET(sockfd, &read_fds)){
ret = recv(sockfd, buf, sizeof(buf) - 1, 0);
if(ret <= 0)
break;//connection closed
// process logic
printf("get %d bytes of normal data:%s\n", ret, buf);
}else if(FD_ISSET(sockfd, &exception_fds)){
//handle exceptions
//get out of band data
ret = recv(connfd, buf, sizeof(buf) - 1, MSG_OOB);
if(ret <= 0)
break;
printf("get %d bytes of OOB data: %s", ret, buf); }
FD_CLR(sockfd, &all_read_fds);
FD_CLR(sockfd, &all_exception_fds);
//after we deal with this client
close(sockfd);
if(--nready <= 0)
break;
}
} close(listenfd);
return 0;
}

參考:《高性能server编程》和《UNP》

高性能网络编程 - select系统调用的更多相关文章

  1. 一文读懂高性能网络编程中的I/O模型

    1.前言 随着互联网的发展,面对海量用户高并发业务,传统的阻塞式的服务端架构模式已经无能为力.本文(和下篇<高性能网络编程(六):一文读懂高性能网络编程中的线程模型>)旨在为大家提供有用的 ...

  2. 【原创】高性能网络编程(二):上一个10年,著名的C10K并发连接问题

    1.前言 对于高性能即时通讯技术(或者说互联网编程)比较关注的开发者,对C10K问题(即单机1万个并发连接问题)应该都有所了解."C10K"概念最早由Dan Kegel发布于其个人 ...

  3. 【网络】高性能网络编程--下一个10年,是时候考虑C10M并发问题了

    转载:http://www.52im.net/thread-568-1-1.html 1.前言 在本系列文章的上篇中我们回顾了过云的10年里,高性能网络编程领域著名的C10K问题及其成功的解决方案(上 ...

  4. 网络编程select函数

    select函数的作用: 在编程的过程中,经常会遇到许多阻塞的函数,好像read和网络编程时使用的recv, recvfrom函数都是阻塞的函数,当函数不能成功执行的时候,程序就会一直阻塞在这里,无法 ...

  5. 高性能网络编程(一)----accept建立连接

    编写服务器时,许多程序员习惯于使用高层次的组件.中间件(例如OO(面向对象)层层封装过的开源组件),相比于服务器的运行效率而言,他们更关注程序开发的效率,追求更快的完成项目功能点.希望应用代码完全不关 ...

  6. Linux之select系统调用_2

    在上一篇博文中,我们的程序中我们有3个客户端,因此也事先建立了3个管道,每个客户端分别使用一个管道向服务器发送消息.而在服务器端使用select系统调用,只要监测到某一管道有消息写入,服务器就将其re ...

  7. Linux之select系统调用_1

    SYNOPSIS /* According to POSIX.1-2001 */ #include <sys/select.h> /* According to earlier stand ...

  8. winsock编程select模型

    winsock编程select模型 网络服务端连接数量过多时,为每一个连接申请一个线程会让机器性能急剧下降(大多说是因为线程在用户态和内核态之间切换会占用大量的CPU时间片).为了解决多线程带来的性能 ...

  9. 高性能网络编程(1)—accept建立连接‍(转载,作者:陶辉)

    编 写服务器时,许多程序员习惯于使用高层次的组件.中间件(例如OO(面向对象)层层封装过的开源组件),相比于服务器的运行效率而言,他们更关注程序开发 的效率,追求更快的完成项目功能点.希望应用代码完全 ...

随机推荐

  1. Docker学习笔记(1)----认识Docker

    1. 什么Docker? Docker是一个能把开发的应用程序自动部署到容器的引擎,它使用go语言编写的开源引擎,它在github上面个的地址为:https://github.com/docker/d ...

  2. split方法切割数组

    指定的字符串按"o"截取 当一个base64需要剪去前面的部分的时候 var params={ "imgJustBase64":this.zheng.split ...

  3. Json相关内容

    一. 导入包:net.sf.json.JSONObject 代码 import net.sf.json.JSON; import net.sf.json.JSONArray; import net.s ...

  4. Docker和虚拟机的区别

    这是docker官网的图,可以看到虚拟化技术通过Hypervisor(虚拟机管理系统)为每个app启动一个Guest OS(客户机操作系统),也就是为每个app启动一个虚拟机.比较直观地说,vm通过H ...

  5. 国庆 day 3 上午

    a[问题描述] 你是能看到第一题的 friends 呢. ——hja 怎么快速记单词呢?也许把单词分类再记单词是个不错的选择.何大爷给 出了一种分单词的方法,何大爷认为两个单词是同一类的当这两个单词的 ...

  6. 更新 hadoop eclipse 插件

    卸载hadoop 1.1.2插件.并安装新版hadoop 2.2.0插件. 假设直接删除eclipse plugin文件夹下的hadoop 1.1.2插件,会导致hadoop 1.1.2插件残留在ec ...

  7. MapReduce 的类型与格式【编写最简单的mapreduce】(1)

    hadoop mapreduce 中的map 和reduce 函数遵循下面的形式 map: (K1, V1) → list(K2, V2) reduce: (K2, list(V2)) → list( ...

  8. linux程序设计——个人总结

    linux程序设计--个人总结 到今天为止,<linux程序设计>学习基本完毕了.从五月下旬開始接触linux,学习安装Ubuntu14.04,六月份開始学习<linux程序设计&g ...

  9. java匿名内部类的使用注意事项

    1.首先匿名内部类要继承自抽象基类或者实现基类接口 like this abstract class Seed{ int cnt; public Seed(int x){ cnt=x; } abstr ...

  10. angularjs --- ngResource 类似于 ajax发送请求。

    <!DOCTYPE HTML> <html ng-app="myApp"> <head> <meta http-equiv="C ...