// Sockets with exceptions are returned to both read and write sets.
if ((NULL != readfds) && (!p->second.m_sUDTReads.empty() || !p->second.m_sUDTExcepts.empty()))
{
*readfds = p->second.m_sUDTReads;
for (set<UDTSOCKET>::const_iterator i = p->second.m_sUDTExcepts.begin(); i != p->second.m_sUDTExcepts.end(); ++ i)
readfds->insert(*i);
total += p->second.m_sUDTReads.size() + p->second.m_sUDTExcepts.size();
}
epoll 监听不到close事件,不知为何,谢谢!
我也发现了,如果客户端不掉用UDT::close(fhandle) 那么服务器端可以读到错误。如果客户端调用UDT::close(fhandle)就收不到,比较奇怪。我是客户端和服务器端在一台电脑上,不知到有没有关系。
是个bug,正在修改,估计一两天之内会把新的代码放到cvs上去。
已经更新了CVS。谢谢。
请问这个更新是版本5?
确实有这个BUG。。。在底层检测到broken的socket时,然后调用close候会添加一个ERROR事件,但是并没添加成功,代码如下:
void CUDT::close()
{
.............
s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, UDT_EPOLL_ERR, true);
.............
}
但是跟踪代码发现update_events(m_SocketID, m_sPollID, UDT_EPOLL_ERR, true)会调用:
update_epoll_sets(uid, p->second.m_sUDTSocksEx, p->second.m_sUDTExcepts, enable);
进而调用
void update_epoll_sets(const UDTSOCKET& uid, const set<UDTSOCKET>& watch, set<UDTSOCKET>& result, bool enable)
{
if (enable && (watch.find(uid) != watch.end()))
{
result.insert(uid);
}
else if (!enable)
{
result.erase(uid);
}
}
此时的set<UDTSOCKET>& watch即为p->second.m_sUDTExcepts,但是p->second.m_sUDTExcepts为empty(),
所以事件添加不成功,导致上层不能接受到事件。
为什么m_sUDTExcepts为空,查看代码就能发现跟epoll之前调用的add_usock有关,当我们需要关注ERROR时,并没有往这里面添加socket描述符:
int CEPoll::add_usock(const int eid, const UDTSOCKET& u, const int* events)
{
CGuard pg(m_EPollLock);
map<int, CEPollDesc="">::iterator p = m_mPolls.find(eid);
if (p == m_mPolls.end())
throw CUDTException(5, 13);
if (!events || (events & UDT_EPOLL_IN))
p->second.m_sUDTSocksIn.insert(u);
if (!events || (events & UDT_EPOLL_OUT))
p->second.m_sUDTSocksOut.insert(u);
return 0;
}
查看函数int CEPoll::wait(const int eid, set<UDTSOCKET> readfds, set<UDTSOCKET> writefds, int64_t msTimeOut, set<SYSSOCKET> lrfds, set<SYSSOCKET> lwfds)可以发现:即使有一个error事件触发,在事件收集的时候也是合并为EPOLL_IN事件来处理的。
所以可以这样修改:
1)在close函数里面修改 s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, UDT_EPOLL_ERR, true);
为 s_UDTUnited.m_EPoll.update_events(m_SocketID, m_sPollID, UDT_EPOLL_IN, true);
这样就能导致上层收到一个读事件。
2)然后上层调用recv或者recvmsg,此时因为socket已经在udt层面不存在了,会引发一个异常,这时候要在异常里面做处理
就是剔除跟这个socket有关的事件,职位为false,否则会导致这个事件一直存在,不停的循环告诉上层有读的事件发生。
所以需要修改recv和recvmsg函数的异常处理分支
int CUDT::recv(UDTSOCKET u, char buf, int len, int)
{
try
{
CUDT udt = s_UDTUnited.lookup(u);
return udt->recv(buf, len);
}
catch (CUDTException e)
{
s_UDTUnited.m_EPoll.remove_events(u); //////////因为bug新增行remove_events在源代码里面是没有的。
s_UDTUnited.setError(new CUDTException(e));
return ERROR;
}
catch (...)
{
s_UDTUnited.setError(new CUDTException(-1, 0, 0));
return ERROR;
}
}
recvmsg函数的修改同上。。。。。。
新增函数:
void CEPoll::remove_events(const UDTSOCKET& uid)
{
CGuard pg(m_EPollLock);
}
我用的是utd的最新版本udt4.11,udt5好像还没出来。。。
<BODY>
</body>
</html>
<BODY>
</body>
</html>
<BODY>
</body>
</html>
上次回复修改这个bug并不完善,还有自动检测的地方,并没有关闭事件通知到上层,接着上面的帖子,还要修稿到文件为api.cpp,在函数
void CUDTUnited::checkBrokenSockets()里面加上事件通知
//EPOLL SIGNAL
m_EPoll.update_events(i->first, i->second->m_pUDT->m_sPollID, UDT_EPOLL_IN, true);
<BODY>
</body>
</html>
<BODY>
</body>
</html>
<BODY>
</body>
</html>