0. 前言

  这篇文章主要记录在使用epoll实现NIO接入时所遇到的问题。

1. epoll简介

  epoll是Linux下提供的NIO,其主要有两种模式,ET(Edge trige)和LT(Level trige)。在linux下使用man epoll手册即可知道这两种模式主要的区别:

  ET:边缘触发,故名思议,所添加的描述符,只在当其改变状态的时候才会触发一次,就如同数电里面电平的边缘触发。

  在man里面列举了一个例子,当一个fd添加到epoll中时,当有2KB数据到达时,epoll_wait会返回事件个数以及其fd,此时,当程序读取了1KB数据后继续调用epoll_wait,1)对于ET来说会继续等待,2)而LT则是继续触发返回。

2. epoll错误程序分析

  下述为错误的示例:

 #include <sys/epoll.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h> #define MAX_BACKLOG 256
#define MAX_EVENTS 1024 static int SetNonBlock(int nFd)
{
int nOldOpt = fcntl(nFd, F_GETFD, );
int nNewOpt = nOldOpt | O_NONBLOCK; return fcntl(nFd, F_SETFD, nNewOpt);
} static void AddEvent(int nEpfd, int nFd)
{
struct epoll_event event;
event.data.fd = nFd;
event.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET; return epoll_ctl(nEpfd, EPOLL_CTL_ADD, &event);
} int main(int argc, char const *argv[])
{
if (argc != )
{
printf("usage: CMD Port\n");
exit(-);
} int nPort = atoi(argv[]);
if (nPort < )
{
printf("Port Invalid\n");
exit(-);
} int nSvrFd = socket(AF_INET, SOCK_STREAM, );
//设置非阻塞
SetNonBlock(nSvrFd); //绑定地址
struct sockaddr_in addr;
bzero(&addr, sizeof(addr)); addr.sin_addr = ;
addr.sin_port = htons(argv[]);
addr.sin_family = htos(AF_INET); if ( != bind(nSvrFd, (struct sockaddr*)&addr, sizeof(addr)))
{
perror("Bind Failure:");
exit(-);
} //监听端口
if ( != listen(nSvrFd, MAX_BACKLOG))
{
perror("Listen Failure:");
exit(-);
} int nEpfd = epoll_create();
struct epoll_event events[MAX_EVENTS]; AddEvent(nEpfd, nSvrFd); while ()
{
//等待事件到来
int nReadyNums = epoll_wait(nEpfd, events, MAX_EVENTS, -); for (int i = ; i < nReadyNums; ++i)
{
if (events[i].data.fd == nSvrFd)
{
//这里对于ET模式来说是有问题的
int nClientFd = accept(nSvrFd, NULL, NULL);
if (- != nClientFd)
{
//设置为非阻塞
SetNonBlock(nClientFd);
//添加事件监听
AddEvent(nEpfd, nClientFd);
} } else
{
//处理FD事件
}
}
} return ;
}

  分析:这里的程序使用ET + 非阻塞,对于accept没有使用循环接收,则会导致当两个连接同时接入的时候,只触发一次,则accept一次,另外一个则停留在SYN队列中。当终端超时后发送FIN状态,这边只是将该连接标识为只读状态。并连接处于CLOSE_WAIT状态。当下一次接入的时候,触发epoll,这次accept的却是上一次的连接,这次的连接依然停留在SYN队列中。如果后续都是单次触发的话,则会导致后续交易都失败。

  这里对KEEPALIVE选项做个补充,KEEPALIVE是用于检测到连接断开后有操作系统自动释放资源,但是并不会释放SYN队列里面的连接,也就是说,CLOSE_WAIT状态会被清除,但是问题还是存在,会把现象遮蔽了。

  正确应该是在accept加上一个循环:

while ((nClientFd = accept(nSvrFd, NULL, NULL)) > )
{
//设置为非阻塞
SetNonBlock(nClientFd);
//添加事件监听
AddEvent(nEpfd, nClientFd);
}

3. 总结

  对于ET模式+非阻塞,无论是recv还是accept,都需要加上循环处理

epoll ET模式陷阱分析的更多相关文章

  1. (转)彻底学会使用epoll(一)——ET模式实现分析

    注:之前写过两篇关于epoll实现的文章,但是感觉懂得了实现原理并不一定会使用,所以又决定写这一系列文章,希望能够对epoll有比较清楚的认识.是请大家转载务必注明出处,算是对我劳动成果的一点点尊重吧 ...

  2. C/C++ 知识点---sizeof使用规则及陷阱分析(网摘)

    C/C++ 知识点---sizeof使用规则及陷阱分析 原文出处:[胖奇的专栏] 1.什么是sizeof 首先看一下sizeof在msdn上的定义:     The sizeof keyword gi ...

  3. epoll(2) 源码分析

    epoll(2) 源码分析 文本内核代码取自 5.0.18 版本,和上一篇文章中的版本不同是因为另一个电脑出了问题,但是总体差异不大. 引子留下的问题 关键数据结构 提供的系统调用 就绪事件相关逻辑 ...

  4. 三种工厂模式的分析以及C++实现

    三种工厂模式的分析以及C++实现 以下是我自己学习设计模式的思考总结. 简单工厂模式 简单工厂模式是工厂模式中最简单的一种,他可以用比较简单的方式隐藏创建对象的细节,一般只需要告诉工厂类所需要的类型, ...

  5. 基于Java 生产者消费者模式(详细分析)

    Java 生产者消费者模式详细分析 本文目录:1.等待.唤醒机制的原理2.Lock和Condition3.单生产者单消费者模式4.使用Lock和Condition实现单生产单消费模式5.多生产多消费模 ...

  6. 微软和Google的盈利模式对比分析

    一: 微软和Google是世界上最成功科技巨头之一,但他们之间却有着不同的产品和业务,二者的盈利方式也各有不同,本文将分析和探讨的二者盈利模式的异同. 微软的盈利模式 在1975年由大学肄业的Bill ...

  7. Libreswan软件的密钥协商协议IKEv1主模式实现分析

    Libreswan软件的密钥协商协议IKEv1主模式实现分析 1 协商过程 IKEv1(互联网密钥交换协议第一版)是IPsec VPN隧道协商使用的标准密钥协商协议,其协商过程如下图所示. 总共来回交 ...

  8. C2B电商三种主要模式的分析_数据分析师

    C2B电商三种主要模式的分析_数据分析师 在过去的一年中电商领域血雨腥风,尤其是天猫.京东.苏宁.当当.易讯等B2C电商打得不亦乐乎.而随着B2C领域竞争进入白热化阶段,C2B模式也在天猫" ...

  9. epoll惊群原因分析

    考虑如下情况(实际一般不会做,这里只是举个例子): 在主线程中创建一个socket.绑定到本地端口并监听 在主线程中创建一个epoll实例(epoll_create(2)) 将监听socket添加到e ...

随机推荐

  1. 推荐一个不错的css3网站 可以直接调用的

    animate.css 一搜就能出来  我用着还不错

  2. android Intent使用

    ntent.setType(“image/*”);//图片格式 intent.setType(“audio/*”); //选择音频 intent.setType(“video/*”); //选择视频 ...

  3. Win10系统旗舰版ghost版系统镜像下载

    微软已经发布了Win10预览版10041快速版更新,但通过Windows更新的方式比较慢.现在微软官方已经发布Win10预览版10041的系统ISO镜像,还没更新这一版本的朋友可以使用该镜像进行更新. ...

  4. 【转载】Web移动端Fixed布局的解决方案

    特别声明:本文转载于EFE的<Web移动端Fixed布局的解决方案>.如需转载,烦请注明原文出处:http://efe.baidu.com/blog/mobile-fixed-layout ...

  5. transactionManager的type与dataSource的type

    1. 在ibatis的配置文件中dataSource 节点有这么个配置<datasource type="SIMPLE"></datasource>,根据原 ...

  6. Mybatis(综合案例)

    MyBatis本是apache的一个开源项目iBatis,2010年这个项目有Apache software foundation 迁移到了Google code,并改名MyBatis.2013年11 ...

  7. Flash Builder 4.7 注册机完美激活方法

    Flash Builder 4.7 破解注册方法目前较为通用的三种方法: 第一种:三步修改配置文件方法,这种有开发者反应这种方法在升级和创建纯 AS 项目时会存在问题,但我懒的去试这种方法的主要原因是 ...

  8. 分布式监控系统Zabbix-3.0.3-完整安装记录(2)-添加mysql监控

    Zabbix3.0 Server以后就自带了MySQL插件来监控mysql数据库的模板,只需要配置好agent客户端,然后在web端给主机增加模板就行了. 以下是公司线上的zabbix3.0环境下添加 ...

  9. AndroidStudio导入Eclipse的代码格式化文件

    对于一个团队来说,使用统一的代码格式是非常重要的,否则在使用版本控制工具时,会出现大量的冲突.在Eclipse里,我们可以通过一些xml来进行代码格式的统一,但是这些文件要应用在AndroidStud ...

  10. windows7配置Nginx+php+mysql教程

    windows7配置Nginx+php+mysql教程 最近在学习php,想把自己的学习经历记录下来,并写一些经验,仅供参考交流.此文适合那些刚刚接触php,想要学习并想要自己搭建Nginx+php+ ...