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. tomcat更改日志路径

    共有2个地方需要更改. 1.   tomcat/conf/logging.properties 步骤1--查找:grep logs logging.properties 步骤2--替换:sed -i ...

  2. IIFE 萌新学习笔记

    立即执行函数表达式(IIFE) IIFE:Immediately-Invoked Function Expression(立即执行函数表达式) 一 常用写法: //经常使用的写法(function() ...

  3. luogu P2252 取石子游戏(威佐夫博弈)

    题意 题解 对于像我这种不知道威佐夫博弈的人来说,拿到题就开始打表了. 然而打完后并没有发现什么. 然后才知道是威佐夫博弈. 结论是当(int)((b-a)*((sqrt(5.0)+1.0)/2.0) ...

  4. C语言变量名转字符串的方法

    C语言中将变量名转换成字符串使用的是#符号,来看下边两个宏定义: #define name2str(name) (#name) #define print_val(x) printf(#x" ...

  5. java实现文件的上传与下载

    (一)文件的上传:在这一部分,我要将execl文件的内容上传到数据库中,完成这一功能.需要分为两步: 1:将文件上传到tomcat下 文件格式如下: 2:读取execl表中的内容到数据库中 首先:下载 ...

  6. ScrollView反弹效果的实现

    发现非常多APP的界面都能够滑动,QQ.微信等等,自己琢磨了下.效果例如以下: 代码:ScrollView package com.wsj.wsjdemo; import android.conten ...

  7. HDU 5319

    Painter Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Su ...

  8. orale 中创建定时任务

    --添加变量 variable job1 number; --创建JOB begin   dbms_job.submit(:job1,'testjob;',sysdate, 'TRUNC(sysdat ...

  9. mac鼠标滚动方向自然问题

    mac使用鼠标的时候滚轮方向和Windows是相反的.假设不勾选滚动方向自然,那么触摸板使用不爽. 解决的方法: 1.打开http://pilotmoon.com/scrollreverser/,下载 ...

  10. 2014 百度之星 1003 题解 Xor Sum

    Xor Sum Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包括了N个正整数,随后 Prometheu ...