深入阐明驴子系列(1)
副标题#e#
一直在看驴子的代码,网长举办深入阐明的文章不多,也许 这和驴子的代码量太大, 代码质量不高也许有干系。但更多的也许是不想分享,舍不得分享。其实,它自己就是开 源的 不分享人家逐步看也能看懂 。由于时间干系 我会连续把阐明的文章帖上来,与各 位网友分享,也但愿各人拍砖 举办接头 也把你的心得分享出来。。系列阐明文章假如没 有出格注明 以easy mule 0.47为准
CListenSocket 类 的浸染就是 监听 期待客户 端的socket 到来 并维护到来的套接字 把accept进来的套接字 插手到list 中
// 该函数的浸染是建设当地的listensocket, 是否Accept 毗连是由 winsock动静驱动
bool CListenSocket::StartListening()
{
bListening = true;
// Creating the socket with SO_REUSEADDR may solve LowID issues if emule was restarted
// quickly or started after a crash, but(!) it will also create another problem. If the
// socket is already used by some other application (e.g. a 2nd emule), we though bind
// to that socket leading to the situation that 2 applications are listening at the same
// port!
if (!Create (thePrefs.GetPort(), SOCK_STREAM, FD_ACCEPT, thePrefs.GetBindAddrA(), FALSE/*bReuseAddr*/))
return false;
if (!Listen())
return false;
m_port = thePrefs.GetPort();
return true;
}
// 该函数更名为RestartAccept 更符合
// 它的本意 是从头开始接管毗连
// 为什么需要从头开始接管毗连呢,原因是毗连数过多环境 下,
// 会临时StopListeing (bListening 配置为false;) ,
// 毗连数少 的环境下会从头开始接管毗连RestartListening;
// 应该留意的是:这个暂停和 从头开始并不实际封锁/打开当地listen端口,只是配置一个bool符号
void CListenSocket::ReStartListening()
{
bListening = true;
ASSERT( m_nPendingConnections >= 0 );
if (m_nPendingConnections > 0)
{
m_nPendingConnections--;
OnAccept(0);
}
}
#p#副标题#e#
毗连到来
void CListenSocket::OnAccept(int nErrorCode)
{
if (!nErrorCode) //先判定是否有错误
{
m_nPendingConnections++;
if (m_nPendingConnections < 1)
{
ASSERT(0);
m_nPendingConnections = 1;
}
if (TooManySockets(true) && !theApp.serverconnect->IsConnecting()) // 假如已经毗连的套接字过多 可能 毗连断开
{ // 则遏制监听返回
StopListening();
return;
}
else if (! bListening)
ReStartListening(); //If the client is still at maxconnections, this will allow it to go above it.. But if you don't, you will get a lowID on all servers.
uint32 nFataErrors = 0;
while (m_nPendingConnections > 0)
{
m_nPendingConnections--;
CClientReqSocket* newclient;
SOCKADDR_IN SockAddr = {0};
int iSockAddrLen = sizeof SockAddr;
if (thePrefs.GetConditionalTCPAccept() && ! thePrefs.GetProxySettings().UseProxy)
{
_iAcceptConnectionCondRejected = 0;
SOCKET sNew = WSAAccept(m_SocketData.hSocket, (SOCKADDR*)&SockAddr, &iSockAddrLen, AcceptConnectionCond, 0); // 这是挪用API接管毗连
if (sNew == INVALID_SOCKET)
{
DWORD nError = GetLastError(); // 按照返回的异常举办处理惩罚
if (nError == WSAEWOULDBLOCK)
{
DebugLogError(LOG_STATUSBAR, _T("%hs: Backlogcounter says %u connections waiting, Accept() says WSAEWOULDBLOCK - setting counter to zero! "), __FUNCTION__, m_nPendingConnections);
m_nPendingConnections = 0;
break;
}
else
{
if (nError != WSAECONNREFUSED || _iAcceptConnectionCondRejected == 0){
DebugLogError(LOG_STATUSBAR, _T("%hs: Backlogcounter says %u connections waiting, Accept() says %s - setting counter to zero!"), __FUNCTION__, m_nPendingConnections, GetErrorMessage(nError, 1));
nFataErrors++;
}
else if (_iAcceptConnectionCondRejected == 1)
theStats.filteredclients++;
}
if (nFataErrors > 10)
{
// the question is what todo on a error. We cant just ignore it because then the backlog will fill up
// and lock everything. We can also just endlos try to repeat it because this will lock up eMule
// this should basically never happen anyway
// however if we are in such a position, try to reinitalize the socket.
DebugLogError (LOG_STATUSBAR, _T("%hs: Accept() Error Loop, recreating socket"), __FUNCTION__);
Close();
StartListening();
m_nPendingConnections = 0;
break;
}
continue;
}
newclient = new CClientReqSocket; // 一个新的套接字
VERIFY( newclient->InitAsyncSocketExInstance() );
newclient- >m_SocketData.hSocket = sNew;
newclient- >AttachHandle(sNew);
AddConnection();
}
else
{
newclient = new CClientReqSocket;
if (!Accept(*newclient, (SOCKADDR*) &SockAddr, &iSockAddrLen))
{
newclient->Safe_Delete();
DWORD nError = GetLastError();
if (nError == WSAEWOULDBLOCK)
{
DebugLogError(LOG_STATUSBAR, _T("%hs: Backlogcounter says %u connections waiting, Accept() says WSAEWOULDBLOCK - setting counter to zero!"), __FUNCTION__, m_nPendingConnections);
m_nPendingConnections = 0;
break;
}
else
{
DebugLogError(LOG_STATUSBAR, _T("%hs: Backlogcounter says %u connections waiting, Accept() says %s - setting counter to zero!"), __FUNCTION__, m_nPendingConnections, GetErrorMessage(nError, 1));
nFataErrors++;
}
if (nFataErrors > 10){
// the question is what todo on a error. We cant just ignore it because then the backlog will fill up
// and lock everything. We can also just endlos try to repeat it because this will lock up eMule
// this should basically never happen anyway
// however if we are in such a position, try to reinitalize the socket.
DebugLogError(LOG_STATUSBAR, _T("%hs: Accept() Error Loop, recreating socket"), __FUNCTION__);
Close();
StartListening();
m_nPendingConnections = 0;
break;
}
continue;
}
AddConnection();
if (SockAddr.sin_addr.S_un.S_addr == 0) // for safety..
{
iSockAddrLen = sizeof SockAddr;
newclient->GetPeerName((SOCKADDR*)&SockAddr, &iSockAddrLen);
DebugLogWarning(_T ("SockAddr.sin_addr.S_un.S_addr == 0; GetPeerName returned %s"), ipstr(SockAddr.sin_addr.S_un.S_addr));
}
ASSERT( SockAddr.sin_addr.S_un.S_addr != 0 && SockAddr.sin_addr.S_un.S_addr != INADDR_NONE );
if (theApp.ipfilter->IsFiltered(SockAddr.sin_addr.S_un.S_addr))
{
if (thePrefs.GetLogFilteredIPs())
AddDebugLogLine(false, _T("Rejecting connection attempt (IP=%s) - IP filter (%s)"), ipstr(SockAddr.sin_addr.S_un.S_addr), theApp.ipfilter->GetLastHit());
newclient- >Safe_Delete();
theStats.filteredclients++;
continue;
}
if (theApp.clientlist->IsBannedClient(SockAddr.sin_addr.S_un.S_addr))
{
if (thePrefs.GetLogBannedClients())
{
CUpDownClient* pClient = theApp.clientlist->FindClientByIP(SockAddr.sin_addr.S_un.S_addr);
AddDebugLogLine(false, _T("Rejecting connection attempt of banned client %s %s"), ipstr(SockAddr.sin_addr.S_un.S_addr), pClient->DbgGetClientInfo());
}
newclient->Safe_Delete();
continue;
}
}
newclient->AsyncSelect (FD_WRITE | FD_READ | FD_CLOSE);
}
ASSERT( m_nPendingConnections >= 0 );
}
}
以上就是这个类 的 主要函数 剩下的都较量简朴,就不再。。。