epoll_wait()返回可用uid时,对uid取状态,本该是BROKEN的,却取到CLOSED,然而,不能像处理BROKEN事件那样处理CLOSED事件,这样移除不了CLOSED事件,于是epoll_wait不断返回该uid,就造成了死循环。跟踪代码至底层,寻找原因。
 
int CUDTUnited::epoll_remove_usock(const int eid, const UDTSOCKET u)
{
   int ret = m_EPoll.remove_usock(eid, u);
 
   CUDTSocket* s = locate(u);
   if (NULL != s)
   {
      s->m_pUDT->removeEPoll(eid);
   }
   //else
   //{
   //   throw CUDTException(5, 4);
   //}
 
   return ret;
}
 
CUDTSocket* CUDTUnited::locate(const UDTSOCKET u)
{
   CGuard cg(m_ControlLock);
 
   map<UDTSOCKET, CUDTSocket*>::iterator i = m_Sockets.find(u);
 
   if ((i == m_Sockets.end()) || (i->second->m_Status == CLOSED))
      return NULL;
 
   return i->second;
}
 
void CUDT::removeEPoll(const int eid)
{
   // clear IO events notifications;
   // since this happens after the epoll ID has been removed, they cannot be set again
   set<int> remove;
   remove.insert(eid);
   s_UDTUnited.m_EPoll.update_events(m_SocketID, remove, UDT_EPOLL_IN | UDT_EPOLL_OUT, false);
 
   CGuard::enterCS(s_UDTUnited.m_EPoll.m_EPollLock);
   m_sPollID.erase(eid);
   CGuard::leaveCS(s_UDTUnited.m_EPoll.m_EPollLock);
}
 
CUDTUnited::epoll_remove_usock里,先locate目前uid的位置,但如果此时uid的状态是CLOSED,则返回NULL, 于是,epoll_remove_usock无法再继续调用removeEPoll,所以无法移除epoll事件。
但为什么会发生CLOSED事件呢?按照作者的原意,应该是只会发生BROKEN事件,不会发生CLOSED事件的,继续查找原因。
 
首先看看BROKEN事件怎么发生的。
 
客户端疑似断开十秒以上之后, CUDT::checkTimers()做以下操作
 ……
 ……
         m_bClosing = true;
         m_bBroken = true;
         m_iBrokenCounter = 30;
 
         // update snd U list to remove this socket
         m_pSndQueue->m_pSndUList->update(this);
 
         releaseSynch();
 
         // app can call any UDT API to learn the connection_broken error
         s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, UDT_EPOLL_IN | UDT_EPOLL_OUT | UDT_EPOLL_ERR, true);
 
         CTimer::triggerEvent();
 ……
 ……
在这里把m_bBroken置为true,并触发epoll事件。
然而,在epoll_wait返回事件之前,还可能发生这个:
 
#ifndef WIN32
   void* CUDTUnited::garbageCollect(void* p)
#else
   DWORD WINAPI CUDTUnited::garbageCollect(LPVOID p)
#endif
{
 
   CUDTUnited* self = (CUDTUnited*)p;
 
   CGuard gcguard(self->m_GCStopLock);
 
   while (!self->m_bClosing)
   {
 
      self->checkBrokenSockets();
 ……
 ……
 
void CUDTUnited::checkBrokenSockets()
{
 
   CGuard cg(m_ControlLock);
 
   // set of sockets To Be Closed and To Be Removed
   vector<UDTSOCKET> tbc;
   vector<UDTSOCKET> tbr;
 
   for (map<UDTSOCKET, CUDTSocket*>::iterator i = m_Sockets.begin(); i != m_Sockets.end(); ++ i)
   {
      // check broken connection
      if (i->second->m_pUDT->m_bBroken)
      {
         if (i->second->m_Status == LISTENING)
         {
            // for a listening socket, it should wait an extra 3 seconds in case a client is connecting
            if (CTimer::getTime() - i->second->m_TimeStamp < 3000000)
               continue;
         }
         else if ((i->second->m_pUDT->m_pRcvBuffer != NULL) && (i->second->m_pUDT->m_pRcvBuffer->getRcvDataSize() > 0) && (i->second->m_pUDT->m_iBrokenCounter -- > 0))
         {
            // if there is still data in the receiver buffer, wait longer
            continue;
         }
 
         //close broken connections and start removal timer
         i->second->m_Status = CLOSED;
         i->second->m_TimeStamp = CTimer::getTime();
         tbc.push_back(i->first);
         m_ClosedSockets[i->first] = i->second;
……
……
GC线程是UDT的垃圾回收处理,在UDT调用cleanup(),之前,会一直处于checkBrokenSocket和阻塞的循环中。
然后在checkBrokenSocket里,当socket的m_bBroken为true时,m_Status的状态被置为CLOSED。
 
所以,这时候再用getsocketstate取socket的状态,就会取到CLOSED,也就是明明是BROKEN事件,硬生生变成了CLOSED事件!然后接下去epoll事件的移除就失败了。
 
于是,修改如下,
int CEPoll::remove_usock(const int eid, const UDTSOCKET& u)
{
   CGuard pg(m_EPollLock);
 
   map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
   if (p == m_mPolls.end())
      throw CUDTException(5, 13);
 
   p->second.m_sUDTSocksIn.erase(u);
   p->second.m_sUDTSocksOut.erase(u);
   p->second.m_sUDTSocksEx.erase(u);
 
   return 0;
}
改为
int CEPoll::remove_usock2(const int eid, const UDTSOCKET& u)
{
   CGuard pg(m_EPollLock);
 
   map<int, CEPollDesc>::iterator p = m_mPolls.find(eid);
   if (p == m_mPolls.end())
      throw CUDTException(5, 13);
 
   p->second.m_sUDTSocksIn.erase(u);
   p->second.m_sUDTSocksOut.erase(u);
   p->second.m_sUDTSocksEx.erase(u);
 
   p->second.m_sUDTWrites.erase(u);
   p->second.m_sUDTReads.erase(u);
   p->second.m_sUDTExcepts.erase(u);
 
   return 0;
}
并去掉CUDTUnited::epoll_remove_usock()中对removeEPoll()的调用。
 
这是比较简单也比较粗糙的改法,应该有更方便的思路才对。

UDT中epoll对CLOSE状态的处理的更多相关文章

  1. UDT中的epoll

    epoll 是为处理大量句柄而改进的poll,在UDT中也有支持.UDT使用了内核提供的epoll,主要是epoll_create,epoll_wait,epoll_ctl,UDT定义了CEPollD ...

  2. 快来体验快速通道,netty中epoll传输协议详解

    目录 简介 epoll的详细使用 EpollEventLoopGroup EpollEventLoop EpollServerSocketChannel EpollSocketChannel 总结 简 ...

  3. android 自定义adapter和线程结合 + ListView中按钮滑动后状态丢失解决办法

    adapter+线程 1.很多时候自定义adapter的数据都是来源于服务器的,所以在获取服务器的时候就需要异步获取,这里就需要开线程了(线程池)去获取服务器的数据了.但这样有的时候adapter的中 ...

  4. ubuntu中vi在编辑状态下方向键不能用的解决

    ubuntu中vi在编辑状态下方向键不能用,还有回格键不能删除等,我们平时习惯的一些键都不能使用. 解决办法: 可以安装vim full版本,在full版本下键盘正常,安装好后同样使用vi命令. 安装 ...

  5. 如何设置Installshield中 feature的选中状态

    原文:如何设置Installshield中 feature的选中状态 上一篇: 使用strtuts2的iterator标签循环输出二维数组之前一直有筒子问如何设置Installshield中 feat ...

  6. Hibernate中的对象有三种状态

    Hibernate中的对象有三种状态: 瞬时状态 (Transient),持久状态 (Persistent), 1. 脱管状态 (Detached) 1. 1. 瞬时状态 (Transient) 由  ...

  7. Apache beam中的便携式有状态大数据处理

    Apache beam中的便携式有状态大数据处理 目标: 什么是 apache beam? 状态 计时器 例子&小demo 一.什么是 apache beam? 上面两个图片一个是正面切图,一 ...

  8. Pvmove中断后恢复LV状态

    Pvmove中断后恢复LV状态   pvmove执行时关闭中断窗口后,pvmove进程会被强制杀掉,从而导致lv的状态异常,无法重新进行pvmove和其他lvm镜像增加相关操作,可以通过如下方式修复: ...

  9. Unity 2D游戏开发教程之游戏中精灵的跳跃状态

    Unity 2D游戏开发教程之游戏中精灵的跳跃状态 精灵的跳跃状态 为了让游戏中的精灵有更大的活动范围,上一节为游戏场景添加了多个地面,于是精灵可以从高的地面移动到低的地面处,如图2-14所示.但是却 ...

随机推荐

  1. Angularjs promise对象解析

    1.先来看一段Demo,看完这个demo你可以思考下如果使用$.ajax如何处理同样的逻辑,使用ng的promise有何优势? var ngApp=angular.module('ngApp',[]) ...

  2. Android监听系统短信数据库变化-提取短信内容

    由于监听系统短信广播受到权限的限制,所以很多手机可能使用这种方式没法监听广播,从而没办法获取到系统短信,所以又重新开辟一条路. Android监听系统短信数据库内容变化使用场景: 1.监听短信数据库的 ...

  3. 在新浪云SAE中使用smarty引擎模版

    在新浪云上使用smarty时会发现又这样的错误信息: “SAE_Fatal_error: Uncaught exception 'SmartyException' with message 'unab ...

  4. Visual Studio 2013中因SignalR的Browser Link引起的Javascript错误一则

    众所周知Visual Studio 2013中有一个由SignalR机制实现的Browser Link功能,意思是开发人员可以同时使用多个浏览器进行调试,当按下IDE中的Browser Link按钮后 ...

  5. C#基础知识二之this关键字

    this关键字 引用类的当前实例,包括继承而来的方法,通常可以省略. public class Person { public string Name { get; set; } public int ...

  6. C#学习笔记-封装

    前言 说起来惭愧,学了大半年的C#,其实最开始就接触到了封装的部分,但是一直模模糊糊的弄不清楚,也觉得没什么影响就没怎么在意,现在才开始认真的看这部分内容,看懂了过后好多东西清晰了不少,才发现封装这个 ...

  7. WPF CheckBox 自定义样式

    WPF 自定义样式.CheckBox <Style x:Key="EmptyCheckBox" TargetType="CheckBox"> < ...

  8. js的touch事件的实际引用

    一开始做前端页面的时候,接触的也是js,但是随后便被简单高效的jquery吸引过去,并一直使用至今. 而js,则被我主观的认为底层技术而抛弃. 直到这几天工作需要,研究移动端页面的触屏滑动事件,搜索j ...

  9. Redis学习笔记——初级

    1. Redis是什么.特点.优势 Redis是一个开源的使用C语言编写.开源.支持网络.可基于内存亦可持久化的日志型.高性能的Key-Value数据库,并提供多种语言的API. 它通常被称为数据结构 ...

  10. 速战速决 (6) - PHP: 获取 http 请求数据, 获取 get 数据 和 post 数据, json 字符串与对象之间的相互转换

    [源码下载] 速战速决 (6) - PHP: 获取 http 请求数据, 获取 get 数据 和 post 数据, json 字符串与对象之间的相互转换 作者:webabcd 介绍速战速决 之 PHP ...