Linux 网络编程七(非阻塞socket:epoll--select)
阻塞socket
--阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。
--对于文件操作 read,fread函数调用会将线程阻塞(平常使用read感觉不出来阻塞,
因为以前的程序read都是从本机上读取数据,所以速度很快,无法感觉出来,但是从网络上读取就会有阻塞现象)。
--对于socket来讲,accept与recv、recvfrom函数调用会将线程阻塞。
--为了避免整个进程被阻塞后挂起,所以在阻塞模式下,往往需要采用多线程技术。
--一个进程中可并发的线程总数是有限的,在处理大量客户端socket连接(比如上万个client socket),通过线程并发处理socket处理socket并不方便,效率也不高。
非阻塞socket
--非阻塞调用是指调用立刻返回。
--在非阻塞模式下,accept与recv、recvfrom函数调用会立刻返回。
--在nonblocking状态下调用accept函数,如果没有客户端socket连接请求,那么accept函数返回-,同时errno值为EAGAIN或者EWOULDBLOCK,这两个宏定义都为整数11.
--在nonblocking状态下调用recv、recvfrom函数,如果没有数据,函数返回-,同时errno值为11(EINPROGRESS)。如果socket已经关闭,函数返回0.
--在nonblocking状态下对一个已经关闭的socket调用send函数,将引发一个SIGPIPE信号,进程必须捕捉这个信号,因为SIGPIPE系统默认的处理方式是关闭进程。
fcntl函数调用
fcntl函数可以将文件或者socket描述符设置为阻塞或者非阻塞状态
int fcntl(int fd,int cmd,.../*arg*/);
参数fd为要设置的文件描述符或者socket。
参数cmd,F_GETFL为得到目前状态,F_SETFL为设置状态。
宏定义O_NONBLOCK代表非阻塞,0代表阻塞。
成功返回值为描述符当前状态,失败返回-1,并且设置errno。
//fcntl函数调用设置非阻塞socket
int opts=fcntl(st,F_GETFL);
if(opts<)
{
printf("fcntl failed ! error message :%s\n",strerror(errno));
return -;
}
opts=opts | O_NONBLOCK;
if(fcntl(st,F_SETFL,opts)<)
{
printf("fcntl failed ! error message :%s\n",strerror(errno));
return -;
}
//fcntl函数调用设置阻塞socket
if(fcntl(st,F_SETFL,)<)
{
printf("fcntl failed ! error message :%s\n",strerror(errno));
return -;
}
场景解释:现在将服务器端的st和客户端传到服务器端的client_socket都设置为非阻塞,
但是这种设置针对的是服务器,所以在服务器端设置客户端client_socket非阻塞,并不会影响客户端的socket,客户端的socket还是阻塞的。
epoll的系统调用函数
--epoll_create epoll_create用来创建一个epoll文件描述符。
--epoll_ctl epoll_clt用来添加|修改|删除需要侦听的文件描述符及其事件
--epoll_wait epoll_wait接收发生在被侦听的描述符上的,用户感兴趣的IO事件
--epoll文件描述符用完后,需要用close关闭
--每次添加|修改|删除文件描述符都需要调用epoll_ctl,所以要尽量少的调用epoll_ctl
--epoll只适用与Linux 内核 2.6版本或者其以上的版本,并不适用于Unix和window
epoll_create
--int epoll_create(int size);
--epool_create创建一个epoll句柄
--参数size指定epoll所支持的最大句柄数
--函数成功会返回一个新的epoll句柄,之后的所有操作将通过这个句柄来进行操作,函数失败返回-1,并且设置errno。
--在用完句柄之后,需要用close()来关闭着创建出来的epoll句柄。
epoll_ctl:
--int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event);
--参数epfd是epoll_create()的返回值
--参数op表示动作,用三个宏来表示
EPOLL_CTL_ADD:注册新的fd到epfd中
EPOLL_CTL_MOD:修改已经注册的fd的监听事件
EPOLL_CTL_DEL:从epfd中删除一个fd
--参数fd是需要监听的socket描述符
--参数event通知内核需要监听什么事件
epoll_ctl()函数的第四个参数可以是一个临时变量,epoll似乎会拷贝这个参数而不是直接使用
//union epoll_data共用体
typedef union epoll_data
{
void *ptr;
int fd;
_uint32_t u32;
_uint64_t u64;
}epoll_data_t; //struct epoll_event结构
struct epoll_event
{
_uint32_t events;/*Epoll events*/
epoll_data_t data;/*User data variable */
};
events定义
--EPOLLIN 表示对应的文件描述符可以读(包括对端SOCKET正常关闭)
--EPOLLOUT 表示对应的文件描述符可以写
--EPOLLPRI 表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来)
--EPOLLERR 表示对应的文件描述符发生错误;
--EPOLLHUP 表示对应的文件描述符被挂断
--EPOLLET 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的
--EPOLLONESHOT 只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里
关于ET、LT两种工作模式
LT(level triggered)是缺省的工作方式,并且同时支持block和no-block socket
--在LT模式中,内核通知一个文件描述符是否就绪了,然后可以对这个就绪的fd进行IO操作
--如果你不作任何操作,内核还是会继续通知你的,所以这种模式编程出错误可能性要小一点。 ET(edge-triggered)是高速工作方式,只支持no-block socket
--在ET模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。
--ET模式会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,知道你做了某些操作导致那个文件描述符不再为就绪状态了
--如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知。 ET和LT的区别:
--LT事件不会丢弃,而是只要读buffer里面有数据可以让用户读,则不断的通知你
--ET则只在事件发生之时通知。可以简单理解为LT是水平触发,而ET则为边缘触发。
epoll_wait
--int epoll_wait(int epfd,struct epoll_event *events,int maxevents,int timeout);
--参数epfd是epoll_create()的返回值。
--参数events是一个epoll_event*指针,一般是一个事件数组,当epoll_wait这个函数操作成功之后,epoll_events里面将存储所有的读写事件。
--参数maxevents是当前需要监听的所有socket句柄数。
--参数timeout是epoll_wait的超时,为0的时候表示马上返回,为-1的时候表示一致等下去,直到有事件返回,正整数表示等这么长的时间。
--一般如果网络主循环是单独的线程的话,可以用-1来等,这样可以保证一些效率,如果是和主逻辑在同一线程的话,则可以用0来保证主循环的效率。
--函数成功返回值是有消息的socket的数目,失败返回-1,并且设置errno。
epoll_wait返回之后应该是一个循环,遍历所有的事件。
epoll所能容纳的文件描述符无上限,但是poll和select所容纳的文件描述符最大只能是1024
select
--int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct tomeval *timeout);
--参数nfds为最大socket的值加1,(socket都是int类型)
--参数readfds是读事件的socket集合
--参数writefds是写事件的socket集合
--参数exceptfds是出错事件的socket集合
--每个事件数组都支持1024个文件描述符
--参数timeout如果为NULL,表示永远阻塞,如果是一个具体的时间类型,表示等待的事件。
--select也是阻塞的,只要放入readfds池中的socket有事件发生或者放入writefds池中的socket有事件发生
或者放入exceptfds池中的socket有事件发生,select函数都会立刻返回。readfds和epoll_wait中的事件数组很相似
不关心的事件数组可以设置为NULL
--当readfds、writefds、exceptfds都设置为NULL,并且参数timeout设置了时间,那么select函数的效果就会等同于sleep()函数
sleep()函数有一定延迟,但是select比sleep()更加精确,并且设置的时间范围更加广泛,可以精确到微秒。
--select最大支持1024个文件描述符
--void FD_ZERO(fd_set *set); 初始化(清空)一个select事件数组,不可以使用memset()
--void FD_SET(int fd,fd_set *set); 在select事件数组里添加一个文件描述符,添加重复的socket对事件数组没有影响
--void FD_CLR(int fd,fd_set *set); 从select事件数组中删除一个文件描述符
--void FD_ISSET(int fd,fd_set *set); 判断一个文件描述符是否在select的某个事件数组中
--函数成功返回有消息的socket的数目,失败返回-,并且设置errno
epoll和select使用场景:客户端连接量大,但是每个客户端发送的数据量少,并且向服务器发送消息的次数很少
多线程使用场景:客户端连接量小,每个客户端发送的数据量大,且长时间连接发送消息
Linux 网络编程七(非阻塞socket:epoll--select)的更多相关文章
- 网络编程之非阻塞connect编写
一.connect非阻塞编写 TCP连接的建立涉及到一个三次握手的过程,且socket中connect函数需要一直等到客户接收到对于自己的SYN的ACK为止才返回, 这意味着每 个connect函数总 ...
- linux c编程:非阻塞I/O
通常来说,从普通文件读数据,无论你是采用 fscanf,fgets 也好,read 也好,一定会在有限的时间内返回.但是如果你从设备,比如终端(标准输入设备)读数据,只要没有遇到换行符(‘\n’),r ...
- 第5章 Linux网络编程基础
第5章 Linux网络编程基础 5.1 socket地址与API 一.理解字节序 主机字节序一般为小端字节序.网络字节序一般为大端字节序.当格式化的数据在两台使用了不同字节序的主机之间直接传递时,接收 ...
- Linux网络编程一步一步学【转】
转自:http://blog.chinaunix.net/uid-10747583-id-297982.html Linux网络编程一步一步学+基础 原文地址:http://blogold.chin ...
- Linux网络编程(五)
/*Linux网络编程(五)——多路IO复用之select() 网络编程中,使用IO复用的典型场合: 1.当客户处理多个描述字时(交互式输入以及网络接口),必须使用IO复用. 2.一个客户同时处理多个 ...
- linux网络编程模型
1.编程模型 Linux网络编程模型是基于socket的编程模型
- Linux网络编程学习路线
转载自:https://blog.csdn.net/lianghe_work/article 一.网络应用层编程 1.Linux网络编程01——网络协议入门 2.Linux网络编程02——无连接和 ...
- linux网络编程中阻塞和非阻塞socket的区别
读操作 对于阻塞的socket,当socket的接收缓冲区中没有数据时,read调用会一直阻塞住,直到有数据到来才返 回.当socket缓冲区中的数据量小于期望读取的数据量时,返回实际读取的字节数.当 ...
- Linux - 非阻塞socket编程处理EAGAIN错误
在linux进行非阻塞的socket接收数据时经常出现Resource temporarily unavailable,errno代码为11(EAGAIN),这表明你在非阻塞模式下调用 ...
随机推荐
- windows下vagrant使用及工作环境配置
环境搭建记录(2014-08-01) 操作系统: Win7旗舰版 Vagrant版本: 1.6 搭建过程 安装vagrant 右键打开安装包按照提示安装即可 安装后会自动把vagrant添加到环境变量 ...
- bootstrap3 兼容IE8浏览器
近期在使用bootstrap这个优秀的前端框架,这个框架非常强大,框架里面有下拉菜单.按钮组.按钮下拉菜单.导航.导航条.面包屑.分页.排版.缩略图.警告对话框.进度条.媒体对象等,bootstrap ...
- Visual Studio发布Web项目报错:Unable to add 'xxx' to the Web site. Unable to add file 'xxx'. The specified file could not be encrypted.
背景 Visual Studio下的Web项目 现象 发布时遇到Unable to add 'xxx' to the Web site. Unable to add file 'xxx'. The ...
- Remoting和Webservice的区别
其实现的原理并没有本质的区别,在应用开发层面上有以下区别:1.Remoting可以灵活的定义其所基于的协议,如果定义为HTTP,则与Web Service就没有什么区别了,一般都喜欢定义为TCP,这样 ...
- 使用backbone.js、zepto.js和trigger.io开发HTML5 App
为了力求运行速度快.响应迅即,我们推荐使用backbone.js和zepto.js. 为了让这个过程更有意思,我们开发了一个小小的示例项目,使用CSS重置样式.Backbone.js和带转场效果的几个 ...
- Myeclipse6.0 在线安装svn插件
一.官网地址 1.SVN 官方网站:http://subversion.apache.org/ 二.安装步骤 1. 打开Myeclipse,在菜单栏中选择Help→Software Updates→F ...
- (五) openwrt打包过程
标签(空格分隔): Makefile 本周是成胖子每周一博第六周,更好地阅读体验,请点击这里 前言 前面我们已经讲了openwrt编译的大部分过程,包括大致的编译步骤,ipk的编译等.今天是我这个系列 ...
- Linux学习之二——档案与目录的属性和权限
一.属性和权限的基本概念 Linux一般将档案可存取的身份分为三个类别,分别是 owner/group/others,这三种身份各有 read/write/execute 等权限. 所有的系统上的账号 ...
- [学习嵌入式开发板]iTOP-4412实现NFS网络文件系统
本文转自迅为:http://www.topeetboard.com 学习平台:iTOP-4412开发板 本文讲解如何在 iTOP-4412 开发板上实现 NFS 网络文件系统. 我们使用的软硬件环境是 ...
- SSIS XML source demo
以下是一个使用xml作为source的SSIS package示例: 自动生成的xsd.把两个结点merge join成一条记录. 示例XML如下: <?xml version="1. ...