Socket 编程发展

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);
主要是 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>

Socket 编程介绍的更多相关文章

  1. socket编程介绍

    Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供了标准的 BSD Sockets API. 第二个是 SocketServer, 它提供了服务器中心类,可以简化网络 ...

  2. 基于Socket的UDP和TCP编程介绍

    一.概述 TCP(传输控制协议)和UDP(用户数据报协议是网络体系结构TCP/IP模型中传输层一层中的两个不同的通信协议. TCP:传输控制协议,一种面向连接的协议,给用户进程提供可靠的全双工的字节流 ...

  3. <转>Socket编程——基础介绍

    最近系统的看了下unix网络编程的一些内容,对socket的理解有了进一步的加深,在看APUE的时候,那会儿看socket上面介绍的比较少,只是模糊的懂了如何去写一个简单的TCP服务端和客户端,对其中 ...

  4. 《Linux/UNIX系统编程手册》第56章 SOCKET:介绍

    关键词: 1. socket基础 一个典型的客户端/服务器场景中,应用程序使用socket进行通信的方式如下: 各个应用程序创建一个socket.socket是一个允许通信的设备,两个应用程序都需要用 ...

  5. python socket编程详细介绍

    Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供了标准的 BSD Sockets API. 第二个是 SocketServer, 它提供了服务器中心类,可以简化网络 ...

  6. 转:python socket编程详细介绍

    Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供了标准的 BSD Sockets API. 第二个是 SocketServer, 它提供了服务器中心类,可以简化网络 ...

  7. Windows Socket的UDP和TCP编程介绍

    1:网络中进程之间如何通信 为了实现进程之间通信,首要解决的问题是如何唯一标识一个进程,在本地可以通过进程PID来唯一标识一个进程,但是在网络中则是行不通的,其实TCP/IP协议族已经帮我们解决了这个 ...

  8. Python Socket 编程详细介绍(转)

    Python 提供了两个基本的 socket 模块: Socket 它提供了标准的BSD Socket API. SocketServer 它提供了服务器重心,可以简化网络服务器的开发. 下面讲解下 ...

  9. Python 006- python socket编程详细介绍

    转自https://blog.csdn.net/rebelqsp/article/details/22109925 Python 提供了两个基本的 socket 模块. 第一个是 Socket,它提供 ...

随机推荐

  1. 聊聊 Spring 的 XML Schema 扩展机制的使用方式

    前言 在当前Java生态,Spring算的上是最核心的框架,所有的开发组件想要得到大范围更便捷的使用,都要和Spring进行整合,比如我们熟知的Mybatis.Dubbo等,以及内部封装的各类组件包括 ...

  2. 企业微信三种token

    http://www.upwqy.com/doc/28.html 基本配置介绍 区分三种类型access_token 服务商的token 说明:以corpid(服务商CorpID).provider_ ...

  3. 五:.net core(.NET 6)使用Autofac实现依赖注入

    Autofac的简单使用: 由于将来可能引用很多包,为了保持统一队形,我们再新建一个类库项目Wsk.Core.Package,当做包的引用集合: 删掉Class1,把Wsk.Core.Wsk.Core ...

  4. [ Java面试题 ]Java 开发岗面试知识点解析

    如背景中介绍,作者在一年之内参加过多场面试,应聘岗位均为 Java 开发方向. 在不断的面试中,分类总结了 Java 开发岗位面试中的一些知识点. 主要包括以下几个部分: Java 基础知识点 Jav ...

  5. 出现 关于UTF-8 序列的字节 2 无效的异常

    学习mybatis中碰到了 Caused by: org.apache.ibatis.builder.BuilderException: Error creating document instanc ...

  6. Xilinx FPGA全局介绍

    Xilinx FPGA全局介绍 现场可编程门阵列 (FPGA) 具有诸多特性,无论是单独使用,抑或采用多样化架构,皆可作为宝贵的计算资产:许多设计人员并不熟悉 FPGA,亦不清楚如何将这类器件整合到设 ...

  7. 快速人体姿态估计:CVPR2019论文阅读

    快速人体姿态估计:CVPR2019论文阅读 Fast Human Pose Estimation 论文链接: http://openaccess.thecvf.com/content_CVPR_201 ...

  8. 旷视MegEngine网络搭建

    旷视MegEngine网络搭建 在 基本概念 中,介绍了计算图.张量和算子,神经网络可以看成一个计算图.在 MegEngine 中,按照计算图的拓扑结构,将张量和算子连接起来,即可完成对网络的搭建.M ...

  9. 容斥+dp (一)

    ARC115 E AtCoder Problem Statement Given is a sequence of \(N\) integers \(A_1\),\(A_2\),...,\(A_N\) ...

  10. Django基础之auth模块

    内容概要 用户认证模块auth auth模块补充 auth_user表扩展字段 内容详细 auth模块 主要是用来做用户相关的功能 注册 登录 验证 修改密码 注销 ​ 访问admin需要管理员账号 ...