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. Eclipse中的Web项目自动部署到Tomcat

    原因 很长时间没用Eclipse了,近期由于又要用它做个简单的JSP项目,又要重新学习了,虽然熟悉的很快,但记忆总是很模糊,偶尔犯错,以前很少写博客,现在感觉还是很有必要的,编程中每个人对于犯过的错误 ...

  2. 使用XmlHelper添加节点C#代码

    接着上一篇:http://keleyi.com/a/bjac/ttssua0f.htm在前篇文章中,给出了C# XML文件操作类XmlHelper的代码,以及使用该类的一个例子,即使用XmlHelpe ...

  3. go语言 类型:布尔类型

    Go语言中的布尔类型与其他语言基本一致,关键字也为bool,可赋值为预定义的true和false示例代码如下: var v1 bool v1 = true v2 := (1 == 2) // v2也会 ...

  4. [html5+java]文件异步读取及上传核心代码

    html5+java 文件异步读取及上传关键代码段 功能: 1.多文件文件拖拽上传,file input 多文件选择 2.html5 File Api 异步FormData,blob上传,图片显示 3 ...

  5. Sharepoint学习笔记—习题系列--70-576习题解析 -(Q36-Q39)

    Question 36 You are designing a SharePoint 2010 application. You need to design the application so t ...

  6. Android EditText输入最大值提示功能

    public class LengthFilter implements InputFilter { public LengthFilter(int max) { mMax = max; } @Ove ...

  7. 限制EditText 输入的字节数

    1.代码 name_tv = (EditText) findViewById( R.id.name_tv ); name_tv.addTextChangedListener(new TextWatch ...

  8. 2016最新CocoaPods安装和错误解决 + 自己的经验

    p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 20.0px Times; color: #333333; background-color: #fffff ...

  9. 你真的了解UIViewController生命周期吗?

    一:首先了解一下生命周期图 二:UIViewController 生命周期介绍 1.通过alloc init 分配内存,初始化controller. 2.loadView loadView方法默认实现 ...

  10. Java基础知识学习(三)

    面向对象部分 首先要了解面向对象的思想,与C#一致,都是面向对象的语言 访问修饰符 public 共有的,对所有类可见. protected 受保护的,对同一包内的类和所有子类可见. private ...