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. 删除docker的运行目录出错

    1.      错误类型

  2. Android 通过Uri获取Bitmap对象

    (转自:http://blog.sina.com.cn/s/blog_5de73d0b0100zfm8.html) private Bitmap getBitmapFromUri(Uri uri) { ...

  3. 关于linux中的时间 时区问题

    本文部分来源于:  http://hi.baidu.com/peruke/blog/item/b8de06ec6a04583b27979132.html 系统是fedora: glibc实现了从RTC ...

  4. 第3章 Linux常用命令(3)_文件搜索命令

    3. 文件搜索命令 3.1 文件搜索:find (1)find命令 命令名称 find 命令所在路径 /bin/find 执行权限 所有用户 语法 find [搜索范围] [-选项] [匹配条件] - ...

  5. mysql 性能优化方案

    网 上有不少MySQL 性能优化方案,不过,mysql的优化同sql server相比,更为麻烦与复杂,同样的设置,在不同的环境下 ,由于内存,访问量,读写频率,数据差异等等情况,可能会出现不同的结果 ...

  6. 14-前端开发之CSS

    什么是 CSS ? CSS 指层叠样式表 (Cascading Style Sheets),用于对页面进行美化. 存在的方式有3种: 元素内联:在标签中使用 style='xx:xxx;' 页面嵌入: ...

  7. Qt——浅谈样式表

    优秀的程序,不仅要有严密逻辑,而且应该有美观的外表.从软件界面,便可看出你是否用心在做,是否是一个有思想的人. Qt样式表的术语和语法规则和HTML CSS有很多相似之处. 样式规则 Qt中样式规则由 ...

  8. Showbo.Msg.alert

    注意alert,confirm及prompt并不同于系统的,这个是用层模仿的,并不能挂起程序的执行 所以如果需要在确认后执行相关的操作,需要在配置文件中传递回调函数fn 按钮只提供yes和no两个 S ...

  9. sql server 使用nolock提升性能

    博客园有许多关于nolock的文章,大部分都写得很好,例如:http://www.cnblogs.com/huangxincheng/p/4292320.html 这里仅结合个人项目,作为个人笔记记录 ...

  10. Javascript execCommon

    http://blog.csdn.net/woshinia/article/details/18664903 https://developer.mozilla.org/zh-CN/docs/Web/ ...