UDT中epoll对CLOSE状态的处理

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()的调用。

这是比较简单也比较粗糙的改法,应该有更方便的思路才对。

时间: 2024-12-19 14:29:49

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

UDT中的epoll

epoll 是为处理大量句柄而改进的poll,在UDT中也有支持.UDT使用了内核提供的epoll,主要是epoll_create,epoll_wait,epoll_ctl,UDT定义了CEPollDesc这个结构来管理epoll的描述符和套接字. struct CEPollDesc { int m_iID;                                // epoll ID std::set<UDTSOCKET> m_sUDTSocksOut;       // set o

供多处理器系统中的高速缓存同步中使用的转发状态

这里所述的是一种具有五种状态的高速缓存同步协议,该五种状态为:修改.排它.共享.无效和转发(MESIF).所述MESIF高速缓存同步协议包括转发(F)状态,该状态指明单个数据副本,从所述数据副本中能够产生另一个副本.利用F状态下的超高速缓冲存储器行来响应对超高速缓冲存储器行的副本的请求.在一个实施例中,将新创建的副本置于F状态下并将先前处于F状态下的超高速缓冲存储器行置成共享(S)状态或无效(I)状态.由此,如果共享超高速缓冲存储器行,则一个共享的副本就处于F状态下并且剩余的超高速缓冲存储器行副

(转)JavaMail中的Flag(邮件状态)

本文转载自:http://blog.csdn.net/chjttony/article/details/6005594 标记邮件就是把邮件标记为已读,删除等操作,需要使用Flags类,它mail.jar包中的Flags类代表以组邮件标记的集合,邮件标记用于标示邮件的使用情况,例如邮件的删除标记.已读标记等.JavaMail中的邮件标记分为系统标记和用户标记,系统标记指Flags.Flag这个内部类中表示的邮件标记,用户标记指用户自定义的标记. Flags.Flag类:是Flags的内部类,以定义

十九、android中判断sim卡状态和读取联系人资料的方法

在写程序中,有时候可能需要获取sim卡中的一些联系人资料.在获取sim卡联系人前,我们一般会先判断sim卡状态,找到sim卡后再获取它的资料,如下代码我们可以读取sim卡中的联系人的一些信息. PhoneTest.java package com.android.test; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.datab

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

adapter+线程 1.很多时候自定义adapter的数据都是来源于服务器的,所以在获取服务器的时候就需要异步获取,这里就需要开线程了(线程池)去获取服务器的数据了.但这样有的时候adapter的中没有数据. 如下面的代码: 这就是在initData中异步获取服务器的数据,然后实例化adatper,再将adapter赋给listView. 2.initData()中的代码是: 这里线程要睡眠5秒钟,是为了模仿网络的耗时操作 3.Handler: 在Handler中接收到数据后给list赋值后,

01-08-01【Nhibernate (版本3.3.1.4000) 出入江湖】NHibernate中的三种状态

以下属于不明来源资料: 引入 在程序运行过程中使用对象的方式对数据库进行操作,这必然会产生一系列的持久化类的实例对象.这些对象可能是刚刚创建并准备存储的,也可能是从数据库中查询的,为了区分这些对象,根据对象和当前会话的关联状态,我们可以把对象分为三种: 瞬时对象:对象刚刚建立.该对象在数据库中没有记录,也不在ISession缓存中.如果该对象是自动生成主键,则该对象的对象标识符为空. 持久化对象:对象已经通过NHibernate进行了持久化,数据库中已经存在对应的记录.如果该对象是自动生成主键,

ASP.Net中的四种状态保持机制

本文档转载自http://blog.csdn.net/popping_dancer/article/details/7765464 因时间紧迫,未做个人笔记,仅参考. 这几天在学ASP.Net (就是传说中最难的东西)  上课刚听的时候的确有点听不懂 毕竟第一次接触每天晚上回来看视频的时候 才慢慢的恍然大悟 哦~~ 原来是这么回事呀 想必大牛们当初也是这样的感觉吧 哈哈 !今天来说说ASP.Net中的4种状态保持机制 状态保持机制?神马意思?别急 且听我下面慢慢道来 每个人上网可多有过这样的情况

ORM进阶之Hibernate中对象的三大状态解析

ORM进阶之 ORM简单介绍 ORM进阶之Hibernate简单介绍及框架搭 ORM进阶之Hibernate的三大对象 ORM进阶之Hibernate中对象的三大状态解析 在Hibernatea中每一个对象都有三种状态,他们在这三种状态下,Hibernate会他们进行不同的处理.下边我们通过一张图来看一下这三种状态以及他们之间的互相转换! 能够看到对象可能会有这三种状态.暂时状态(transient),持久化状态(persistent).游离状态(detached).下边我们来分别来解释一下这三

android中判断sim卡状态和读取联系人资料的方法

在写程序中,有时候可能需要获取sim卡中的一些联系人资料.在获取sim卡联系人前,我们一般会先判断sim卡状态,找到sim卡后再获取它的资料,如下代码我们可以读取sim卡中的联系人的一些信息. PhoneTest.java package com.android.test; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.datab