前言
Linux Socket 编程领域,为了处理大量连接请求场景,需要使用非阻塞 I/O 和复用。select、poll 和 epoll 是 Linux API 提供的 I/O 复用方式,自从 Linux 2.6 中加入了 epoll 之后,高性能服务器领域得到广泛的应用,现在比较出名的 Nginx 就是使用 epoll 来实现 I/O 复用支持高并发,目前在高并发的场景下,Nginx 越来越收到欢迎。
据 w3techs 在 2015 年 8 月 10 日的统计数据表明,在全球 Top 1000 的网站中,有 43.7% 的网站在使用 Nginx,这使得 Nginx 超越了 Apache,成为了高流量网站最信任的 Web 服务器足足有两年时间。已经确定在使用 Nginx 的站点有:Wikipedia,WordPress,Reddit,Tumblr,Pinterest,Dropbox,Slideshare,Stackexchange 等,可以持续罗列好几个小时,他们太多了。

下图是统计数据:

select 模型

下面是 select 函数接口:

int select (int n, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);

<br>
select 函数监视的文件描述符分 3 类,分别是 writefds、readfds 和 exceptfds。调用后 select 函数会阻塞,直到有描述符就绪(有数据 可读、可写、或者有 except),或者超时(timeout 指定等待时间,如果立即返回设为 null 即可)。当 select 函数返回后,通过遍历 fd_set,来找到就绪的描述符。
select 目前几乎在所有的平台上支持,其良好跨平台支持是它的一大优点。select 的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在 Linux 上一般为 1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但是这样也会造成效率的降低。

poll 模型

int poll (struct pollfd *fds, unsigned int nfds, int timeout);

<br>
不同于 select 使用三个位图来表示三个 fdset 的方式,poll 使用一个 pollfd 的指针实现。

struct pollfd {int fd; /* file descriptor */short events; /* requested events to watch */short revents; /* returned events witnessed */
};

<br>
pollfd 结构包含了要监视的 event 和发生的 event,不再使用 select “参数-值”传递的方式。同时,pollfd 并没有最大数量限制(但是数量过大后性能也是会下降)。和 select 函数一样,poll 返回后,需要轮询 pollfd 来获取就绪的描述符。
从上面看,select 和 poll 都需要在返回后,通过遍历文件描述符来获取已经就绪的 socket。事实上,同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降。

epoll 模型

epoll 的接口如下:

int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);typedef union epoll_data {void *ptr;int fd;__uint32_t u32;__uint64_t u64;} epoll_data_t;struct epoll_event {__uint32_t events;      /* Epoll events */epoll_data_t data;      /* User data variable */};int epoll_wait(int epfd, struct epoll_event * events,int maxevents, int timeout);

<br>
主要是 epoll_create,epoll_ctl 和 epoll_wait 三个函数。epoll_create 函数创建 epoll 文件描述符,参数 size 并不是限制了 epoll 所能监听的描述符最大个数,只是对内核初始分配内部数据结构的一个建议。epoll_ctl 完成对指定描述符 fd 执行 op 操作控制,event 是与 fd 关联的监听事件。op 操作有三种:添加 EPOLL_CTL_ADD,删除 EPOLL_CTL_DEL,修改 EPOLL_CTL_MOD。分别添加、删除和修改对 fd 的监听事件。epoll_wait 等待 epfd 上的 IO 事件,最多返回 maxevents 个事件。
在 select/poll 中,进程只有在调用一定的方法后,内核才对所有监视的文件描述符进行扫描,而 epoll 事先通过 epoll_ctl() 来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似 callback 的回调机制,迅速激活这个文件描述符,当进程调用 epoll_wait 时便得到通知。
epoll 的优点主要是一下几个方面:
1. 监视的描述符数量不受限制,它所支持的 fd 上限是最大可以打开文件的数目,这个数字一般远大于 2048, 举个例子, 在 1GB 内存的机器上大约是 10 万左右,具体数目可以 cat /proc/sys/fs/file-max 察看, 一般来说这个数目和系统内存关系很大。select 的最大缺点就是进程打开的 fd 是有数量限制的。这对于连接数量比较大的服务器来说根本不能满足。虽然也可以选择多进程的解决方案( Apache 就是这样实现的),不过虽然 linux 上面创建进程的代价比较小,但仍旧是不可忽视的,加上进程间数据同步远比不上线程间同步的高效,所以也不是一种完美的方案。
2.IO 的效率不会随着监视 fd 的数量的增长而下降。epoll 不同于 select 和 poll 轮询的方式,而是通过每个 fd 定义的回调函数来实现的。只有就绪的 fd 才会执行回调函数。
支持水平触发和边沿触发两种模式:
3. 水平触发模式,文件描述符状态发生变化后,如果没有采取行动,它将后面反复通知,这种情况下编程相对简单,libevent 等开源库很多都是使用的这种模式。
4. 边沿触发模式,只告诉进程哪些文件描述符刚刚变为就绪状态,只说一遍,如果没有采取行动,那么它将不会再次告知。理论上边缘触发的性能要更高一些,但是代码实现相当复杂(Nginx 使用的边缘触发)。
mmap 加速内核与用户空间的信息传递。epoll 是通过内核与用户空间 mmap 同一块内存,避免了无谓的内存拷贝。

<br>
<br>

转载于:https://www.cnblogs.com/sunhongleibibi/p/9190541.html

Socket 编程概述相关推荐

  1. Socket编程原理概述

    1 问题的引入  UNIX系统的I/O命令集,是从Maltics和早期系统中的命令演变出来的,其模式为打开一读/写一关闭(open-write-read-close).在一个用户进程进行I/O操作时, ...

  2. C# Socket编程(5)使用TCP Socket

    TCP 协议(Transmission Control Protocol,传输控制协议)是TCP/IP体系中面向连接(connection oriented)的传输层(transport layer) ...

  3. socket编程缓冲区大小对send()的影响

    1. 概述 Socket编程中,使用send()传送数据时,返回结果受到以下几个因素的影响: • Blocking模式或non-blocking模式 • 发送缓冲区的大小 • 接收窗口大小 本文档介绍 ...

  4. Android应用开发提高篇(4)-----Socket编程(多线程、双向通信)(转载)

    转自:http://www.cnblogs.com/lknlfy/archive/2012/03/04/2379628.html 一.概述 关于Socket编程的基本方法在基础篇里已经讲过,今天把它给 ...

  5. Socket编程(C语言实现)——UDP协议(进程间通信AF_UNIX)的流式(SOCK_STREAM)+报式(SOCK_DGRAM)传输【循环监听】

    Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...

  6. Socket编程(C语言实现)——TCP协议(网络间通信AF_INET)的流式(SOCK_STREAM)+报式(SOCK_DGRAM)传输【多线程+循环监听】

    Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...

  7. 【Android】Android网络编程概述

    Android网络编程概述 原文来自:http://blog.csdn.net/kieven2008/article/details/8210737 首先,应该了解的几个问题: 1)Android平台 ...

  8. Android Socket编程(多线程、双向通信)

    原帖地址:http://www.cnblogs.com/lknlfy/archive/2012/03/04/2379628.html 一.概述 关于Socket编程的基本方法在基础篇里已经讲过,今天把 ...

  9. Linux 系统应用编程——网络编程(socket编程)

    二.网络编程基础 1.套接字概述 套接字就是网络编程的ID.网络通信,归根到底还是进程间的通信(不同计算机上的进程间的通信).在网络中,每一个节点(计算机或路由器)都有一个网络地址,也就是IP地址,两 ...

最新文章

  1. PXE安装CentOS
  2. 2020年python工资一般多少钱-2020年Python发展前景如何呢?
  3. Vue中使用uuidv1根据时间戳和MAC地址生成唯一标识
  4. 打造极致体验:字节跳动亿级 DAU 背后的音视频技术最佳实践
  5. SDUT 3347 数据结构实验之数组三:快速转置
  6. 为什么移动卡上到手机上显示无服务器,移动手机卡加密失败然后就没有服务器无聊的时候给手机卡加密因为不知? 爱问知识人...
  7. windows10 计算文件的HASH(SHA256\MD5等)
  8. mysql业务数据库回退_理解MySQL数据库事务-隔离性
  9. 新手程序员不知道的小技巧!
  10. STM32编程中枚举和结构体的结合
  11. C#轻量级通通讯组件StriveEngine —— C/S通信开源demo(2) —— 使用二进制协议 (附源码)...
  12. Gitlab分支保护
  13. 数据库事务 写偏斜write-skew
  14. UDP包导致大量ARP报文的问题处理
  15. 爱了爱了!ALIENWAER外星人AW410K机械键盘Cherry茶轴RGB灯光全键无冲!免费包邮送到家!...
  16. 捣鼓openwrt不死bootloader (1)
  17. 兔子繁殖问题(递归解决)
  18. std::tr1::function and std::tr1::bind
  19. 【剑指offer】BN层详解
  20. uni-app - 苹果安卓系统监听物理返回按键(手机左滑返回监听)

热门文章

  1. Hadoop JobHistory
  2. ifconfig没有命令 kali_kali学习笔记之——端口扫描工具
  3. Dockerfile多阶段构建
  4. Win64 驱动内核编程-21.DKOM隐藏和保护进程
  5. POJ1422 最小路径覆盖
  6. 【Linux 内核 内存管理】Linux 内核堆内存管理 ③ ( CPU 计数器瓶颈 | per-CPU 计数器 | Linux 内核 percpu_counter 结构体源码 )
  7. 【Android 逆向】Android 进程注入工具开发 ( Visual Studio 开发 Android NDK 应用 | Visual Studio 中 SDK 和 NDK 安装位置 )
  8. 【错误记录】Android 文件查看错误 ( Error opening contents of device file ““: Cannot create directory )
  9. 【Netty】使用 Netty 开发 HTTP 服务器 ( HTTP 请求过滤 )
  10. 【Flutter】Flutter 开发环境搭建 ( Android Studio 下 Flutter / Dart 插件安装 | Flutter SDK 安装 | 环境变量配置 | 开发环境检查 )