1. 阻塞socket
  2. --阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。
  3. --对于文件操作 read,fread函数调用会将线程阻塞(平常使用read感觉不出来阻塞,
    因为以前的程序read都是从本机上读取数据,所以速度很快,无法感觉出来,但是从网络上读取就会有阻塞现象)。
  4. --对于socket来讲,acceptrecvrecvfrom函数调用会将线程阻塞。
  5. --为了避免整个进程被阻塞后挂起,所以在阻塞模式下,往往需要采用多线程技术。
  6. --一个进程中可并发的线程总数是有限的,在处理大量客户端socket连接(比如上万个client socket),通过线程并发处理socket处理socket并不方便,效率也不高。
  1. 非阻塞socket
  2. --非阻塞调用是指调用立刻返回。
  3. --在非阻塞模式下,acceptrecvrecvfrom函数调用会立刻返回。
  4. --在nonblocking状态下调用accept函数,如果没有客户端socket连接请求,那么accept函数返回-,同时errno值为EAGAIN或者EWOULDBLOCK,这两个宏定义都为整数11.
  5. --在nonblocking状态下调用recvrecvfrom函数,如果没有数据,函数返回-,同时errno值为11EINPROGRESS)。如果socket已经关闭,函数返回0.
  6. --在nonblocking状态下对一个已经关闭的socket调用send函数,将引发一个SIGPIPE信号,进程必须捕捉这个信号,因为SIGPIPE系统默认的处理方式是关闭进程。
  1. fcntl函数调用
  2. fcntl函数可以将文件或者socket描述符设置为阻塞或者非阻塞状态
  3. int fcntl(int fd,int cmd,.../*arg*/);
  4. 参数fd为要设置的文件描述符或者socket
  5. 参数cmdF_GETFL为得到目前状态,F_SETFL为设置状态。
  6. 宏定义O_NONBLOCK代表非阻塞,0代表阻塞。
  7. 成功返回值为描述符当前状态,失败返回-1,并且设置errno
  1. //fcntl函数调用设置非阻塞socket
  2. int opts=fcntl(st,F_GETFL);
  3. if(opts<)
  4. {
  5. printf("fcntl failed ! error message :%s\n",strerror(errno));
  6. return -;
  7. }
  8. opts=opts | O_NONBLOCK;
  9. if(fcntl(st,F_SETFL,opts)<)
  10. {
  11. printf("fcntl failed ! error message :%s\n",strerror(errno));
  12. return -;
  13. }
  1. //fcntl函数调用设置阻塞socket
  2. if(fcntl(st,F_SETFL,)<)
  3. {
  4. printf("fcntl failed ! error message :%s\n",strerror(errno));
  5. return -;
  6. }
  1. 场景解释:现在将服务器端的st和客户端传到服务器端的client_socket都设置为非阻塞,
    但是这种设置针对的是服务器,所以在服务器端设置客户端client_socket非阻塞,并不会影响客户端的socket,客户端的socket还是阻塞的。
  1. epoll的系统调用函数
  2. --epoll_create epoll_create用来创建一个epoll文件描述符。
  3. --epoll_ctl epoll_clt用来添加|修改|删除需要侦听的文件描述符及其事件
  4. --epoll_wait epoll_wait接收发生在被侦听的描述符上的,用户感兴趣的IO事件
  5. --epoll文件描述符用完后,需要用close关闭
  6. --每次添加|修改|删除文件描述符都需要调用epoll_ctl,所以要尽量少的调用epoll_ctl
  7. --epoll只适用与Linux 内核 2.6版本或者其以上的版本,并不适用于Unixwindow
  1. epoll_create
  2. --int epoll_create(int size);
  3. --epool_create创建一个epoll句柄
  4. --参数size指定epoll所支持的最大句柄数
  5. --函数成功会返回一个新的epoll句柄,之后的所有操作将通过这个句柄来进行操作,函数失败返回-1,并且设置errno
  6. --在用完句柄之后,需要用close()来关闭着创建出来的epoll句柄。
  1. epoll_ctl:
  2. --int epoll_ctl(int epfd,int op,int fd,struct epoll_event *event);
  3. --参数epfdepoll_create()的返回值
  4. --参数op表示动作,用三个宏来表示
  5. EPOLL_CTL_ADD:注册新的fdepfd
  6. EPOLL_CTL_MOD:修改已经注册的fd的监听事件
  7. EPOLL_CTL_DEL:从epfd中删除一个fd
  8. --参数fd是需要监听的socket描述符
  9. --参数event通知内核需要监听什么事件
  1. epoll_ctl()函数的第四个参数可以是一个临时变量,epoll似乎会拷贝这个参数而不是直接使用
  1. //union epoll_data共用体
  2. typedef union epoll_data
  3. {
  4. void *ptr;
  5. int fd;
  6. _uint32_t u32;
  7. _uint64_t u64;
  8. }epoll_data_t;
  9.  
  10. //struct epoll_event结构
  11. struct epoll_event
  12. {
  13. _uint32_t events;/*Epoll events*/
  14. epoll_data_t data;/*User data variable */
  15. };
  1. events定义
  2. --EPOLLIN 表示对应的文件描述符可以读(包括对端SOCKET正常关闭)
  3. --EPOLLOUT 表示对应的文件描述符可以写
  4. --EPOLLPRI 表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来)
  5. --EPOLLERR 表示对应的文件描述符发生错误;
  6. --EPOLLHUP 表示对应的文件描述符被挂断
  7. --EPOLLET EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的
  8. --EPOLLONESHOT 只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里
  1. 关于ETLT两种工作模式
  2. LTlevel triggered)是缺省的工作方式,并且同时支持blockno-block socket
  3. --在LT模式中,内核通知一个文件描述符是否就绪了,然后可以对这个就绪的fd进行IO操作
  4. --如果你不作任何操作,内核还是会继续通知你的,所以这种模式编程出错误可能性要小一点。
  5.  
  6. ETedge-triggered)是高速工作方式,只支持no-block socket
  7. --在ET模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。
  8. --ET模式会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,知道你做了某些操作导致那个文件描述符不再为就绪状态了
  9. --如果一直不对这个fdIO操作(从而导致它再次变成未就绪),内核不会发送更多的通知。
  10.  
  11. ETLT的区别:
  12. --LT事件不会丢弃,而是只要读buffer里面有数据可以让用户读,则不断的通知你
  13. --ET则只在事件发生之时通知。可以简单理解为LT是水平触发,而ET则为边缘触发。
  1. epoll_wait
  2. --int epoll_wait(int epfd,struct epoll_event *events,int maxevents,int timeout);
  3. --参数epfdepoll_create()的返回值。
  4. --参数events是一个epoll_event*指针,一般是一个事件数组,当epoll_wait这个函数操作成功之后,epoll_events里面将存储所有的读写事件。
  5. --参数maxevents是当前需要监听的所有socket句柄数。
  6. --参数timeoutepoll_wait的超时,为0的时候表示马上返回,为-1的时候表示一致等下去,直到有事件返回,正整数表示等这么长的时间。
  7. --一般如果网络主循环是单独的线程的话,可以用-1来等,这样可以保证一些效率,如果是和主逻辑在同一线程的话,则可以用0来保证主循环的效率。
  8. --函数成功返回值是有消息的socket的数目,失败返回-1,并且设置errno
  1. epoll_wait返回之后应该是一个循环,遍历所有的事件。
  2. epoll所能容纳的文件描述符无上限,但是pollselect所容纳的文件描述符最大只能是1024
  1. select
  2. --int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct tomeval *timeout);
  3. --参数nfds为最大socket的值加1,(socket都是int类型)
  4. --参数readfds是读事件的socket集合
  5. --参数writefds是写事件的socket集合
  6. --参数exceptfds是出错事件的socket集合
  7. --每个事件数组都支持1024个文件描述符
  8. --参数timeout如果为NULL,表示永远阻塞,如果是一个具体的时间类型,表示等待的事件。
  9. --select也是阻塞的,只要放入readfds池中的socket有事件发生或者放入writefds池中的socket有事件发生
  10. 或者放入exceptfds池中的socket有事件发生,select函数都会立刻返回。readfdsepoll_wait中的事件数组很相似
  11. 不关心的事件数组可以设置为NULL
  12. --当readfdswritefdsexceptfds都设置为NULL,并且参数timeout设置了时间,那么select函数的效果就会等同于sleep()函数
  13. sleep()函数有一定延迟,但是selectsleep()更加精确,并且设置的时间范围更加广泛,可以精确到微秒。
  14. --select最大支持1024个文件描述符
  15. --void FD_ZERO(fd_set *set); 初始化(清空)一个select事件数组,不可以使用memset()
  16. --void FD_SET(int fd,fd_set *set); select事件数组里添加一个文件描述符,添加重复的socket对事件数组没有影响
  17. --void FD_CLR(int fd,fd_set *set); select事件数组中删除一个文件描述符
  18. --void FD_ISSET(int fd,fd_set *set); 判断一个文件描述符是否在select的某个事件数组中
  19. --函数成功返回有消息的socket的数目,失败返回-,并且设置errno
  1. epollselect使用场景:客户端连接量大,但是每个客户端发送的数据量少,并且向服务器发送消息的次数很少
  2. 多线程使用场景:客户端连接量小,每个客户端发送的数据量大,且长时间连接发送消息

Linux 网络编程七(非阻塞socket:epoll--select)的更多相关文章

  1. 网络编程之非阻塞connect编写

    一.connect非阻塞编写 TCP连接的建立涉及到一个三次握手的过程,且socket中connect函数需要一直等到客户接收到对于自己的SYN的ACK为止才返回, 这意味着每 个connect函数总 ...

  2. linux c编程:非阻塞I/O

    通常来说,从普通文件读数据,无论你是采用 fscanf,fgets 也好,read 也好,一定会在有限的时间内返回.但是如果你从设备,比如终端(标准输入设备)读数据,只要没有遇到换行符(‘\n’),r ...

  3. 第5章 Linux网络编程基础

    第5章 Linux网络编程基础 5.1 socket地址与API 一.理解字节序 主机字节序一般为小端字节序.网络字节序一般为大端字节序.当格式化的数据在两台使用了不同字节序的主机之间直接传递时,接收 ...

  4. Linux网络编程一步一步学【转】

    转自:http://blog.chinaunix.net/uid-10747583-id-297982.html Linux网络编程一步一步学+基础  原文地址:http://blogold.chin ...

  5. Linux网络编程(五)

    /*Linux网络编程(五)——多路IO复用之select() 网络编程中,使用IO复用的典型场合: 1.当客户处理多个描述字时(交互式输入以及网络接口),必须使用IO复用. 2.一个客户同时处理多个 ...

  6. linux网络编程模型

    1.编程模型 Linux网络编程模型是基于socket的编程模型

  7. Linux网络编程学习路线

    转载自:https://blog.csdn.net/lianghe_work/article 一.网络应用层编程   1.Linux网络编程01——网络协议入门 2.Linux网络编程02——无连接和 ...

  8. linux网络编程中阻塞和非阻塞socket的区别

    读操作 对于阻塞的socket,当socket的接收缓冲区中没有数据时,read调用会一直阻塞住,直到有数据到来才返 回.当socket缓冲区中的数据量小于期望读取的数据量时,返回实际读取的字节数.当 ...

  9. Linux - 非阻塞socket编程处理EAGAIN错误

            在linux进行非阻塞的socket接收数据时经常出现Resource temporarily unavailable,errno代码为11(EAGAIN),这表明你在非阻塞模式下调用 ...

随机推荐

  1. OC中的复合

    #import <Foundation/Foundation.h> #import "Car.h" int main(int argc, const char * ar ...

  2. Cocos2d入门--1--初涉相关属性或代码

    Cocos2d vision:  cocos2d-x-3.8.1 万丈高楼,起于累土.对于一个游戏框架的学习,其实在于框架功能的使用积累,学会了如何在cocos2d游戏引擎的基础上使用它提供的各种功能 ...

  3. JIRA系统部署推进上线流程

    JIRA介绍: JIRA是集项目计划.任务分配.需求管理.问题跟踪于一体的商业软件.JIRA创建的问题类型包括New Feature.Bug.Task和Improvement四种(可以自己定义),所以 ...

  4. Html 的实体字符大全

    HTML特殊符号对照表.常用的字符实体 最常用的字符实体 显示结果 描述 实体名称 实体编号   空格     < 小于号 < < > 大于号 > > & ...

  5. MFC分类

    屏幕截图(带光标) MFC Button控件自绘 WM_CTLCOLOR消息 MFC窗口创建.销毁消息流程 DDX_Control.SubclassWindow和SubclassDlgItem 隐藏系 ...

  6. Python语言100例

    Python版本:python 3.2.2 电脑系统:win7旗舰 实例来源:python菜鸟教程100例 #!/usr/bin/python # -*- coding: UTF-8 -*- impo ...

  7. UEditor For ASP.Net Core Use Qiniu

    UEditor For ASP.Net Core Use Qiniu 此项目为UEditor提供文件管理; 后端服务使用 ASP.Net Core; 使用七牛提供的云存储; 项目地址 https:// ...

  8. [麦先生]如何使用AJAX实现按需加载

    按需加载的优势:在实际调查中发现,很多的网民在游览网站时具有明确的指向性,往往在进入主页后直接搜索进入自己需要的商品列表内,如果在客户进入主页时将主页信息全部加载完毕后展示给顾客,会极大的浪费网站资源 ...

  9. 2016开发一个app需要多少钱?app开发需要哪些成本-app开发问题汇总-广州达到信息

    作为一个APP开发从业者,被外行的朋友们问及最多的问题是,"做一个网站需要多少钱?"或者"开发一个APP需要多少钱?".作为开发过完整网站项目和手机APP的人, ...

  10. uva 10305 ordering tasks(超级烂题)——yhx

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABHIAAAHDCAYAAABI5T2bAAAgAElEQVR4nOydPY7svLW1awQGNABHCm