unix/linux下主要的I/O模型:
2013-08-17 15:33
211 查看
UNIX/LINUX下主要的4种i/o模型:
1,阻塞I/O:
最常用,最简单,效率最低
2,非阻塞I/O:
可防止进程阻塞在I/O操作上,需要轮询。
3,I/O多路复用:
允许同时对多个I/O进行控制
4,信号驱动I/O:
一种异步通信模型。
阻塞I/O模式:
阻塞I/O是最普遍使用的I/O模式,大部分的程序使用的都是阻塞I/O。
缺省的情况下,套按字建立以后所处于的模式就是阻塞I/O模式。
例如:读操作read,recv,recvfrom
写操作:write,send
其他操作:accept,connect
读阻塞:进程调用read函数从套接字中读取数据,当套接字中缓冲区中没有要读的数据,函数会阻塞。
它会一直阻塞下去,等待套接字的接收缓冲区中有数据可读
经过一段的时间后,缓冲区中接收到数据,于是内核便去唤醒该进程,通过read访问这些数据。
如果在进程阻塞过程中,对方发生故障,那这个进程将永远阻塞下去。
写阻塞:在写操作上发生阻塞的情况比较少,主要发生在要写入的缓冲区的大小小于要写入的的数据量的情况下。
这时,写操作不进行任何的拷贝工作,将发生阻塞,一旦缓冲区有足够的空间,内核将唤醒进程,将数据从用户缓冲 拷 贝到相应的发送缓冲区中
特例:UDPI不用等待用户的确认,没有实际的发送缓冲区,所以udp协议中不存在发送缓冲区满的情况,在UDP套接字上 执 行的写操作将永远不会阻塞。
非阻塞I/O:
于阻塞I/O相反,进程不会睡眠,立即返回一个错误的信息,这样需要不停的查询(polling),浪费CPU的资源操作。
多路复用I/O:
先构造一张有关的描述符表,然后调用一个函数。当这些文件描述符表中的一个或多个已准备好进行I/O时函数才返回。 函数返回时告诉进程那个描述符准备就绪了,可以进行I/O操作了。
信号驱动I/O:是一种异步通信模式,相当于中断。
多路复用I/O来实现并发服务器:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define N 64
typedef struct sockaddr SA;
int main(int argc, char *argv[])
{
int i, listenfd, connfd, maxfd;
char buf
;
fd_set rdfs,tempfs;
struct sockaddr_in myaddr;
if((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("fail to socket\n");
exit(-1);
}
bzero(&myaddr, sizeof(myaddr));
myaddr.sin_family = PF_INET;
myaddr.sin_port = htons(8001);
myaddr.sin_addr.s_addr = inet_addr("192.168.1.15");
if (bind(listenfd, (SA *)&myaddr, sizeof(myaddr)) < 0)
{
perror("fail to bind");
exit(-1);
}
listen(listenfd, 5);
maxfd = listenfd;
FD_ZERO(&rdfs);
FD_SET(listenfd, &rdfs);
//select的第一个参数为最大文件描述符加1,
while ( 1 )
{
//构造一个临时的变量,这样初始化的时候,就不用太麻烦,
//为什么每次都要初始化,因为这个函数是监控各个文件描述符的状态,
//函数返回的时候状态就发生的变化,需要重新初始化,也就是没有准备好进行多路复用I/O操作。
tempfs=rdfs;
if (select(maxfd+1, &tempfs, NULL, NULL, NULL) < 0)
{
perror("fail to select");
exit(-1);
}
for(i=0; i<=maxfd; i++)
{
if (FD_ISSET(i, &tempfs))
{
if (i == listenfd)
{
connfd = accept(listenfd, NULL, NULL);
printf("New Connection %d is coming\n", connfd);
FD_SET(connfd,&rdfs);
maxfd = maxfd> connfd ?maxfd: connfd;
}
else
{
if(recv(i,buf,N,0) ==0 ) //说明客户端已经已经关闭了socket即客户端的写端。
{
FD_CLR(i,&rdfs);
close(i);
}
else
{
send(i,buf,N,0);
}
}
}
} // end for
} // end while
return 0;
}
1,阻塞I/O:
最常用,最简单,效率最低
2,非阻塞I/O:
可防止进程阻塞在I/O操作上,需要轮询。
3,I/O多路复用:
允许同时对多个I/O进行控制
4,信号驱动I/O:
一种异步通信模型。
阻塞I/O模式:
阻塞I/O是最普遍使用的I/O模式,大部分的程序使用的都是阻塞I/O。
缺省的情况下,套按字建立以后所处于的模式就是阻塞I/O模式。
例如:读操作read,recv,recvfrom
写操作:write,send
其他操作:accept,connect
读阻塞:进程调用read函数从套接字中读取数据,当套接字中缓冲区中没有要读的数据,函数会阻塞。
它会一直阻塞下去,等待套接字的接收缓冲区中有数据可读
经过一段的时间后,缓冲区中接收到数据,于是内核便去唤醒该进程,通过read访问这些数据。
如果在进程阻塞过程中,对方发生故障,那这个进程将永远阻塞下去。
写阻塞:在写操作上发生阻塞的情况比较少,主要发生在要写入的缓冲区的大小小于要写入的的数据量的情况下。
这时,写操作不进行任何的拷贝工作,将发生阻塞,一旦缓冲区有足够的空间,内核将唤醒进程,将数据从用户缓冲 拷 贝到相应的发送缓冲区中
特例:UDPI不用等待用户的确认,没有实际的发送缓冲区,所以udp协议中不存在发送缓冲区满的情况,在UDP套接字上 执 行的写操作将永远不会阻塞。
非阻塞I/O:
于阻塞I/O相反,进程不会睡眠,立即返回一个错误的信息,这样需要不停的查询(polling),浪费CPU的资源操作。
多路复用I/O:
先构造一张有关的描述符表,然后调用一个函数。当这些文件描述符表中的一个或多个已准备好进行I/O时函数才返回。 函数返回时告诉进程那个描述符准备就绪了,可以进行I/O操作了。
信号驱动I/O:是一种异步通信模式,相当于中断。
多路复用I/O来实现并发服务器:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define N 64
typedef struct sockaddr SA;
int main(int argc, char *argv[])
{
int i, listenfd, connfd, maxfd;
char buf
;
fd_set rdfs,tempfs;
struct sockaddr_in myaddr;
if((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
{
perror("fail to socket\n");
exit(-1);
}
bzero(&myaddr, sizeof(myaddr));
myaddr.sin_family = PF_INET;
myaddr.sin_port = htons(8001);
myaddr.sin_addr.s_addr = inet_addr("192.168.1.15");
if (bind(listenfd, (SA *)&myaddr, sizeof(myaddr)) < 0)
{
perror("fail to bind");
exit(-1);
}
listen(listenfd, 5);
maxfd = listenfd;
FD_ZERO(&rdfs);
FD_SET(listenfd, &rdfs);
//select的第一个参数为最大文件描述符加1,
while ( 1 )
{
//构造一个临时的变量,这样初始化的时候,就不用太麻烦,
//为什么每次都要初始化,因为这个函数是监控各个文件描述符的状态,
//函数返回的时候状态就发生的变化,需要重新初始化,也就是没有准备好进行多路复用I/O操作。
tempfs=rdfs;
if (select(maxfd+1, &tempfs, NULL, NULL, NULL) < 0)
{
perror("fail to select");
exit(-1);
}
for(i=0; i<=maxfd; i++)
{
if (FD_ISSET(i, &tempfs))
{
if (i == listenfd)
{
connfd = accept(listenfd, NULL, NULL);
printf("New Connection %d is coming\n", connfd);
FD_SET(connfd,&rdfs);
maxfd = maxfd> connfd ?maxfd: connfd;
}
else
{
if(recv(i,buf,N,0) ==0 ) //说明客户端已经已经关闭了socket即客户端的写端。
{
FD_CLR(i,&rdfs);
close(i);
}
else
{
send(i,buf,N,0);
}
}
}
} // end for
} // end while
return 0;
}
相关文章推荐
- Unix-Linux 网络 IO 模型简介
- Unix-Linux 网络 IO 模型简介
- 转载:Unix/Linux 网络 IO 模型简介
- Unix-Linux 网络 IO 模型简介
- 深度理解Unix/linux系列中Select()模型[中英对照]
- Unix-Linux 网络 IO 模型简介
- 透彻Linux(Unix)五种IO模型
- 透彻 Linux (Unix) 五种 IO 模型
- linux下的五种模型https://www.ziwenxie.site/2017/01/02/unix-network-programming-asynchronous/?nsukey=u352Le
- Linux设备模型-1-主要概念
- UNIX/Linux的主要特色
- Unix/Linux下5种I/O模型
- uucp命令_Linux uucp 命令用法详解:UUCP为Unix系统之间,通过序列线来连线的协议。uucp使用UUCP协议,主要的功能为传送文件。
- 学习linux/unix编程方法的建议,学习Linux的四个步骤
- UNIX & Linux 将字符串转换成命令执行
- Linux 设备模型之(总线、设备和驱动程序)(三)
- Linux 在主要的搜索命令和视图的信息
- linux主要目录结构和系统文件解释
- 探索 Linux 内存模型
- 【Unix/Linux】【命令】【计划任务工具】crontab