Linux为多路复用IO提供了较多的接口,有select(),pselect(),poll()的方式,继承自BSD和System V 两大派系。

  select模型比较简单,“轮询”检测fd_set的状态,然后再采取相应的措施。

  信号驱动模型有必要仔细研究一下,一般有如下步骤:

  1. 设置安装函数,信号是驱动信号是SIGIO(最好使用sigaction的方式,方便设置flag为SA_RESTART,因为client中读取终端的syscall可能会被中断,有必要重启。当然,使用signal()的方式然后再对errno进行判断是否为ETNTR,自行重启也是一种方法。但是signal()的可移植性问题,我强烈不建议使用)
  2. 设置fd的属主。F_SETOWN,要接受信号的进程,fcntl().
  3. 设置fd的异步标志。小细节,用'|'添加,要把之前的状态保留,也就是先F_GETFL再F_SETFL。(注意:在打开文件open()时设置标识O_ASYNC无实质效果)  

    On Linux, specifying the O_ASYNC
    flag when calling open() has no effect. To enable signal-driven I/O, we must
    instead set this flag using the fcntl() F_SETFL operation (Section 5.3).————《the linux programming interface》 4.3.1

  4. sigaction()安装

  具体进下文client例程。

  写了一个聊天程序的demo,把这两种技术都使用了。服务端采取多路复用的IO方式,代替多进(线)程的模型,客服端采取的是信号驱动,如下:

容易产生bug的地方都写注释里边了。

serv.c

 #include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <signal.h> void endServ(int sig)
{
printf("Server ended!\n");
exit(-);
} int main()
{
// signal
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_handler = endServ;
act.sa_flags = ;
sigaction(SIGINT,&act,);
printf("This server is started,enter CTRL+C to end. \n"); int servfd = socket(AF_INET,SOCK_STREAM,);
if(servfd == -) {
printf("something wrong with socket():%m\n");
exit(-);
} struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons();
inet_pton(AF_INET,"127.0.0.1",&addr.sin_addr); if (bind(servfd,(struct sockaddr*)&addr,sizeof(addr)) == -) {
printf("Some thing wrong with bind():%m\n");
exit(-);
}
printf("Bind success!\n"); listen(servfd,); int numbers=;//how many clients has accepted
fd_set fs;
FD_ZERO(&fs);
int client_fd[];
int i;
for(i=;i<;++i)
{
client_fd[i] = -;
} int maxfd=;
char buf[];
for(;;)
{
maxfd =;
FD_ZERO(&fs);
FD_SET(servfd,&fs);
maxfd = maxfd>servfd?maxfd:servfd;
for(i=;i<numbers;++i)
{
if(client_fd[i] != -) {
FD_SET(client_fd[i],&fs);
maxfd = maxfd>client_fd[i]?maxfd:client_fd[i];
}
} int res = select(maxfd+,&fs,,,);
if(res == -) {
printf("Something wrong with select():%m\n");
exit(-);
} if(FD_ISSET(servfd,&fs) && numbers < ) {
printf("New client!\n");
client_fd[numbers] = accept(servfd,,);
numbers++;
} for(i=;i<numbers;++i)
{
bzero(buf,sizeof(buf));
//judge if client_fd[i] equal -1 is necessary
//if a client quited,next time the program will
//have a segment default
//also it should be in the front.
if(client_fd[i] != - && FD_ISSET(client_fd[i],&fs))
{
res = recv(client_fd[i],buf,sizeof(buf),);
if(res == ) {
printf("A client quit\n");
close(client_fd[i]);
FD_CLR(client_fd[i],&fs);
client_fd[i] = -;
}
else if(res == -) {
printf("Something wrong with net.\n");
exit(-);
}
else {
int j;
for(j=;j<numbers;++j)
{
if(client_fd[j] != -)
send(client_fd[j],buf,sizeof(buf),);
}
}
}
}
}
}

client:

 #include <signal.h>
#include <unistd.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h> static int fd; void show(int sig)
{
char buf[] = {};
int n = read(fd,buf,sizeof(buf));
buf[n] = ;
write(,"MSG:",strlen("MSG:"));
write(,buf,strlen(buf));
} int main()
{
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_handler = show;
//This is necessary,in last loop read() counld be interrupt;
act.sa_flags = SA_RESTART;
sigaction(SIGIO,&act,); fd = socket(AF_INET,SOCK_STREAM,);
if(fd == -) {
printf("Cannot get socketfd!:%m\n");
exit(-);
} struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons();
inet_pton(AF_INET,"127.0.0.1",&addr.sin_addr); if(connect(fd,(struct sockaddr*)&addr,sizeof(addr)) != -)
printf("connect success!\n");
else
exit(-); int flag = fcntl(fd,F_GETFL);
flag |= O_ASYNC;
fcntl(fd,F_SETFL,flag);
fcntl(fd,F_SETOWN,getpid()); char buffer[]={};
for(;;)
{
int n = read(,buffer,sizeof(buffer));
if(n==-)
break;
send(fd,buffer,n,);
} write(,"Closed.",strlen("Closed."));
}

IO的多路复用和信号驱动的更多相关文章

  1. 《Linux/UNIX系统编程手册》第63章 IO多路复用、信号驱动IO以及epoll

    关键词:fasync_helper.kill_async.sigsuspend.sigaction.fcntl.F_SETOWN_EX.F_SETSIG.select().poll().poll_wa ...

  2. 【网络IO系列】IO的五种模型,BIO、NIO、AIO、IO多路复用、 信号驱动IO

    前言 在上一篇文章中,我们了解了操作系统中内核程序和用户程序之间的区别和联系,还提到了内核空间和用户空间,当我们需要读取一条数据的时候,首先需要发请求告诉内核,我需要什么数据,等内核准备好数据之后 , ...

  3. 【死磕NIO】— 阻塞IO,非阻塞IO,IO复用,信号驱动IO,异步IO,这你真的分的清楚吗?

    通过上篇文章([死磕NIO]- 阻塞.非阻塞.同步.异步,傻傻分不清楚),我想你应该能够区分了什么是阻塞.非阻塞.异步.非异步了,这篇文章我们来彻底弄清楚什么是阻塞IO,非阻塞IO,IO复用,信号驱动 ...

  4. IO模型浅析-阻塞、非阻塞、IO复用、信号驱动、异步IO、同步IO

    最近看到OVS用户态的代码,在接收内核态信息的时候,使用了Epoll多路复用机制,对其十分不解,于是从网上找了一些资料,学习了一下<UNIX网络变成卷1:套接字联网API>这本书对应的章节 ...

  5. Linux 网络编程的5种IO模型:信号驱动IO模型

    Linux 网络编程的5种IO模型:信号驱动IO模型 背景 上一讲 Linux 网络编程的5种IO模型:多路复用(select/poll/epoll) 我们讲解了多路复用等方面的知识,以及有关例程. ...

  6. 信号驱动IO

    [1]信号驱动IO 应用程序:1)应用程序要捕捉SIGIO信号           signal(SIGIO, handler); 2)应用程序要指定进程为文件的属主,设置当前的文件描述为当前的调用进 ...

  7. 🍛 餐厅吃饭版理解 IO 模型:阻塞 / 非阻塞 / IO 复用 / 信号驱动 / 异步

    IO 概念 一个基本的 IO,它会涉及到两个系统对象,一个是调用这个 IO 的进程对象,另一个就是系统内核 (kernel).当一个 read 操作发生时,它会经历两个阶段: 通过 read 系统调用 ...

  8. UDP信号驱动IO

    SIGIO信号 信号驱动式I/O不适用于TCP套接字, 因为产生的信号过于频繁且不能准确判断信号产生的原因. 设置信号驱动需把sockfd的非阻塞与信号驱动属性都打开 server sockfd单独提 ...

  9. Linux IO模式-阻塞io、非阻塞io、多路复用io

    一 概念说明 在进行解释之前,首先要说明几个概念: - 用户空间和内核空间 - 进程切换 - 进程的阻塞 - 文件描述符 - 缓存 I/O 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对3 ...

随机推荐

  1. 手机端Swiper 触屏滑动

    在线实例 默认 响应式 垂直 空间间隔 滚动 自动滚动 中心化 中心化自动 免费模式 多个滚动 水平滚动 grab-cursor 使用方法 <div class="swiper-con ...

  2. SQL Server数据类型转换

    在SQL Server日常的函数.存储过程和SQL语句中,经常会用到不同数据类型的转换.在SQL Server有两种数据转换类型:一种是显性数据转换:另一种是隐性数据转换.下面分别对这两种数据类型转换 ...

  3. 基于jPlayer的三分屏制作

    三分屏,这里的三分屏只是在一个播放器里同时播放三个视频,但是要求只有一个控制面板同时控制它们,要求它们共享一个时间轨道.这次只是简单的模拟了一下功能,并没有深入的研究. 首先,需要下载jPlayer, ...

  4. 通过gulp为requireJs引入的模块添加版本号

    由于项目用到requireJs,并且通过gulp来对项目进行统一的管理,为了防止浏览器对文件进行缓存,所以通过gulp为项目中的文件添加版本号. 1.分别安装gulp-rev.gulp-rev-col ...

  5. 定制Eclipse IDE之插件篇(一)

    上文回顾:定制Eclipse IDE之功能篇(二) 在这篇文章中,我会将我定制eclipse用到的其他插件罗列出来. 一.汉化插件 Eclipse本身是英文显示的,我们能够通过插件汉化.  1. 选择 ...

  6. 探究TCP

    OSI OSI是Open System Interconnection的缩写,意为开放式系统互联.国际标准化组织(ISO)制定了OSI模型,该模型定义了不同计算机互联的标准,是设计和描述计算机网络通信 ...

  7. SharePoint Error - The SharePoint server was moved to a different location.

    错误 The SharePoint server was moved to a different location. ( Error from SharePoint site: HttpStatus ...

  8. Excel数据导入到Sharepoint List

    这个功能是从XML中读取需要导入到Sharepoint List的列名字,然后把Excel中对应的数据导入到Sharepoint List中.基本原理,把Excel中数据临时放到Datatable中, ...

  9. Jquery分页功能

    Jquery代码 /// <reference path="jquery-1.9.1-vsdoc.js" />//锚点var anchor="#apage&q ...

  10. Android属性之build.prop生成过程分析

    Android的build.prop文件是在Android编译时刻收集的各种property(LCD density/语言/编译时间, etc.),编译完成之后,文件生成在out/target/pro ...