IO的多路复用和信号驱动
Linux为多路复用IO提供了较多的接口,有select(),pselect(),poll()的方式,继承自BSD和System V 两大派系。
select模型比较简单,“轮询”检测fd_set的状态,然后再采取相应的措施。
信号驱动模型有必要仔细研究一下,一般有如下步骤:
- 设置安装函数,信号是驱动信号是SIGIO(最好使用sigaction的方式,方便设置flag为SA_RESTART,因为client中读取终端的syscall可能会被中断,有必要重启。当然,使用signal()的方式然后再对errno进行判断是否为ETNTR,自行重启也是一种方法。但是signal()的可移植性问题,我强烈不建议使用)
- 设置fd的属主。F_SETOWN,要接受信号的进程,fcntl().
- 设置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 - 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的多路复用和信号驱动的更多相关文章
- 《Linux/UNIX系统编程手册》第63章 IO多路复用、信号驱动IO以及epoll
关键词:fasync_helper.kill_async.sigsuspend.sigaction.fcntl.F_SETOWN_EX.F_SETSIG.select().poll().poll_wa ...
- 【网络IO系列】IO的五种模型,BIO、NIO、AIO、IO多路复用、 信号驱动IO
前言 在上一篇文章中,我们了解了操作系统中内核程序和用户程序之间的区别和联系,还提到了内核空间和用户空间,当我们需要读取一条数据的时候,首先需要发请求告诉内核,我需要什么数据,等内核准备好数据之后 , ...
- 【死磕NIO】— 阻塞IO,非阻塞IO,IO复用,信号驱动IO,异步IO,这你真的分的清楚吗?
通过上篇文章([死磕NIO]- 阻塞.非阻塞.同步.异步,傻傻分不清楚),我想你应该能够区分了什么是阻塞.非阻塞.异步.非异步了,这篇文章我们来彻底弄清楚什么是阻塞IO,非阻塞IO,IO复用,信号驱动 ...
- IO模型浅析-阻塞、非阻塞、IO复用、信号驱动、异步IO、同步IO
最近看到OVS用户态的代码,在接收内核态信息的时候,使用了Epoll多路复用机制,对其十分不解,于是从网上找了一些资料,学习了一下<UNIX网络变成卷1:套接字联网API>这本书对应的章节 ...
- Linux 网络编程的5种IO模型:信号驱动IO模型
Linux 网络编程的5种IO模型:信号驱动IO模型 背景 上一讲 Linux 网络编程的5种IO模型:多路复用(select/poll/epoll) 我们讲解了多路复用等方面的知识,以及有关例程. ...
- 信号驱动IO
[1]信号驱动IO 应用程序:1)应用程序要捕捉SIGIO信号 signal(SIGIO, handler); 2)应用程序要指定进程为文件的属主,设置当前的文件描述为当前的调用进 ...
- 🍛 餐厅吃饭版理解 IO 模型:阻塞 / 非阻塞 / IO 复用 / 信号驱动 / 异步
IO 概念 一个基本的 IO,它会涉及到两个系统对象,一个是调用这个 IO 的进程对象,另一个就是系统内核 (kernel).当一个 read 操作发生时,它会经历两个阶段: 通过 read 系统调用 ...
- UDP信号驱动IO
SIGIO信号 信号驱动式I/O不适用于TCP套接字, 因为产生的信号过于频繁且不能准确判断信号产生的原因. 设置信号驱动需把sockfd的非阻塞与信号驱动属性都打开 server sockfd单独提 ...
- Linux IO模式-阻塞io、非阻塞io、多路复用io
一 概念说明 在进行解释之前,首先要说明几个概念: - 用户空间和内核空间 - 进程切换 - 进程的阻塞 - 文件描述符 - 缓存 I/O 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对3 ...
随机推荐
- servletcontext监听器的启动位置以及tomcat和eclipse的目录结构
情景: 想在应用启动的时候就加载spring容器 在ServletContextListener.contextInitialized()中加载spring容器 ApplicationContext ...
- FROONT – 超棒的可视化响应式网页设计工具
FROONT 是一个基于 Web 的设计工具,在浏览器中运行,使得各类可视化设计的人员都能进行响应式的网页设计,即使是那些没有任何编码技能的设计师.FROONT 使得响应式网页设计能够可视化操作,能够 ...
- sublime text3 之snippet编写代码片段
sublime text 3 中有个强大的功能就是可以编写各种文件类型的snippet代码片段,可以节省大量的时间. 文件名为:jekyll-top.sublime-snippet(.sublime- ...
- swift学习笔记之-访问控制
//访问控制 import UIKit /*访问控制(Access Control) 1.访问控制可以限定其他源文件或模块中的代码对你的代码的访问级别.这个特性可以让我们隐藏代码的一些实现细节,并且可 ...
- bootstrapcss3触屏滑块轮播图
插件描述:bootslider响应bootstrapcss3触屏滑块轮播图 小海已经好久没分享技术性文章了,这个基于bootstrap的触屏版轮播图绝对满足大家的胃口,并且支持移动端触摸滑动.功能上, ...
- C#开源项目汇总
Discuz nt: 一个开源的论坛项目.估计你现在逛过大大小小的论坛没有成百上千,也有几十个吧,其中是个论坛6个以上都是Discuz(以前大部分都是php版的),现 在官方也早就放出了DotNet( ...
- javascript --- 事件冒泡与事件捕获
事件冒泡与事件捕获 事件冒泡和事件捕获分别由微软和网景公司提出,这两个概念都是为了解决页面中事件流(事件发生顺序)的问题.考虑下面这段代码,就不写html->head,body之类的代码了,自行 ...
- UITableViewDataSource协议
前言: 在iOS开发中,表视图UITableView 是我们做UI界面设计时的重要视图. 那么,使用表视图UITableView 需要遵守哪些协议呢? <UITableViewDataSourc ...
- 调用CRM自己的Dialogue
var DialogOption = new Xrm.DialogOptions; DialogOption.width = document.body.clientWidth * 0.9; Dial ...
- [Android]AndroidBucket增加碎片SubLayout功能及AISubLayout的注解支持
以下内容为原创,转载请注明: 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/3709957.html 之前写过一篇博客,是使用Fragment来实现T ...