大漠落日

while(!dead) study++;
posts - 46, comments - 126, trackbacks - 0, articles - 0
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

FileZilla Server源码分析(4)

Posted on 2010-06-25 11:11 乱78糟 阅读(1100) 评论(0)  编辑 收藏 引用 所属分类: 开源

    本节的分析是基于本系列第二篇FileZilla Server源码分析(2之上,严格意义上来说是更为详细的分析,深入了解CAsyncSocketEx的实现,我将挑出重要的函数一一分析。

    函数名都为红色粗体,并且带一对小括号,如果括号不含有字符“...”表示该函数无参数,否则有参数,具体什么参数不具体指明。变量均为黑色粗体。  


    首先来看一下该类的构造函数CAsyncSocketEx(),构造函数完成的是部分成员变量的初始化工作,其中最重要的是一个结构体变量m_SocketData,它的原型为:
   
    //Strucure to hold the socket data
    struct t_AsyncSocketExData
    {
        SOCKET hSocket; 
//Socket handle
        int nSocketIndex; //Index of socket, required by CAsyncSocketExHelperWindow
        int nFamily;
        addrinfo 
*addrInfo, *nextAddr; // Iterate through protocols on connect failure
        bool onCloseCalled; // Set to true on first received OnClose event
    } m_SocketData;

    还有m_pLocalAsyncSocketExThreadData的原型为:
//Pointer to the data of the local thread
    struct t_AsyncSocketExThreadData
    {
        CAsyncSocketExHelperWindow 
*m_pHelperWindow;
        
int nInstanceCount;
        DWORD nThreadId;
        std::list
<CAsyncSocketEx*> layerCloseNotify;
    } 
*m_pLocalAsyncSocketExThreadData;

    每个成员具体作用注释已经比较清楚地说明了,后面用到的时候再指出。除了层NOLAYERS编译(如果不明白,请看第二篇)此外还有一个宏条件编译需要注意
#ifndef NOSOCKETSTATES
    m_nPendingEvents 
= 0//socket当前未决的网络事件,例如FD_READ
    m_nState = notsock; //socket当前状态
#endif //NOSOCKETSTATES

    析构函数~CAsyncSocketEx()调用函数Close()关闭socket,并调用FreeAsyncSocketExInstance()做清理工作。
    Close()函数中关闭层m_pFirstLayer->Close(),之后关闭成员变量m_SocketData.hSocket并且从辅助窗口m_pLocalAsyncSocketExThreadData->m_pHelperWindow记录中移除掉这个socket,之后就是销毁各种资源如地址、代理层等,有一个细节,不明白的可以MSDN,不细说了。
   if (m_hAsyncGetHostByNameHandle)
        WSACancelAsyncRequest(m_hAsyncGetHostByNameHandle);
    m_hAsyncGetHostByNameHandle 
= NULL;

    再说FreeAsyncSocketExInstance()之前先说对应的函数InitAsyncSocketExInstance(),这两个函数干的活都和一个static变量m_spAsyncSocketExThreadDataList有关,一个初始化,一个销毁m_pLocalAsyncSocketExThreadData保存了当前线程的id和辅助窗口的指针。

    Create(...)函数创建代理层或者自身的socket以及做绑定到辅助窗口等操作。如果定义了使用代理层,那么所有关于socket的操作都会被代理层拦截,如create,listen,connect,accpet,recv,send,但是不包括bind,因为代理层create的时候已经提前绑定过了。
    TriggerEvent(...)这个函数用来触发程序员指定的网络事件,例如CControlSocket类中的Send(...)函数就调用了TriggerEvent(FD_WRITE)来触发写操作。它通过PosetMessage给辅助窗口,然后窗口通过消息处理函数WindowProc(...)处理这种种消息(详细请参考第二节)。
   
    与代理层相关的函数,如AddLayer(...)RemoveAllLayers()等,还有设置获取各种信息的函数如GetSockOpt()就不在详述了。

    下面再补充之前函数WindowProc(...)关于网络事件的详细处理,仅仅针对非代理层的处理:
//if (!pSocket->m_pFirstLayer)
//{
   switch (nEvent)
   {
    
case FD_READ:
       
if (pSocket->GetState() == connecting && !nErrorCode)
        {
            pSocket
->m_nPendingEvents |= FD_READ; //如果正在连接,那么将读事件加入未决事件变量里
            break;
        }
        
else if (pSocket->GetState() == attached)//已绑定成功的设置为连接成功
             pSocket->SetState(connected);
        
if (pSocket->GetState() != connected)    //如果还没有连接成功,跳出
             break;

        
// Ignore further FD_READ events after FD_CLOSE has been received
        if (pSocket->m_SocketData.onCloseCalled)
            
break;
        
if (pSocket->m_lEvent & FD_READ)
        {
             DWORD nBytes 
= 0;
             
if (!nErrorCode)
             
if (!pSocket->IOCtl(FIONREAD, &nBytes)) //获取要可读的字节数
                  nErrorCode = WSAGetLastError();
             
if (nErrorCode)
                  pSocket
->SetState(aborted);    //出错
             if (nBytes != 0 || nErrorCode != 0//通知socket已经有数据可以读了
                  pSocket->OnReceive(nErrorCode);
         }
         
break;
   
case FD_FORCEREAD:
       
//除了不用获取去可读的字节数之外,完全可FD_READ一样,这是作者自定义的类型
         break;
   
case FD_WRITE:
       
//前面的状态判断和FD_READ类似,不再详述
       if (pSocket->m_lEvent & FD_WRITE)
       {
            
if (nErrorCode)
                pSocket
->SetState(aborted);

            pSocket
->OnSend(nErrorCode);//通知socket已经有数据可以发送了
        }
        
break;
    
case FD_CONNECT:
        
if (pSocket->GetState() == connecting)
        {
            
if (nErrorCode && pSocket->m_SocketData.nextAddr)  //有多个地址?
            {
                 
if (pSocket->TryNextProtocol())  //尝试下一个协议地址
                      break;
             }
                 pSocket
->SetState(connected);
        }
        
else if (pSocket->GetState() == attached && !nErrorCode)
             pSocket
->SetState(connected);
        
if (pSocket->m_lEvent & FD_CONNECT)
             pSocket
->OnConnect(nErrorCode);
        
if (!nErrorCode)
        {
             
//判断未决事件中是否期望的读写事件,如果有,通知socket
             if ((pSocket->m_nPendingEvents&FD_READ) && pSocket->GetState() == connected)
                 pSocket
->OnReceive(0);
             
if ((pSocket->m_nPendingEvents&FD_FORCEREAD) && pSocket->GetState() == connected)
                 pSocket
->OnReceive(0);
             
if ((pSocket->m_nPendingEvents&FD_WRITE) && pSocket->GetState() == connected)
                  pSocket
->OnSend(0);
         }
         pSocket
->m_nPendingEvents = 0;
         
break;
    
case FD_ACCPET:
         
//如果不是监听或已经绑定状态,跳出
         if (pSocket->GetState() != listening && pSocket->GetState() != attached)
              
break;
         
if (pSocket->m_lEvent & FD_ACCEPT)
              pSocket
->OnAccept(nErrorCode);//通知
         break;
    
case FD_CLOSE:
         
//没有连接或绑定,跳出
         if (pSocket->GetState() != connected && pSocket->GetState() != attached)
              
break;

         
// If there are still bytes left to read, call OnReceive instead of
         
// OnClose and trigger a new OnClose
         DWORD nBytes = 0;
         
if (!nErrorCode && pSocket->IOCtl(FIONREAD, &nBytes))
         {
              
//作者的注释很清楚,如果关闭的时候还有数据可读,将当前pSocket->m_SocketData.onCloseCalled 设置为TRUE
              
//以表示需要再一次调用关闭函数OnClose
              if (nBytes > 0)
              {
                   
// Just repeat message.
                   PostMessage(hWnd, message, wParam, lParam);
                   pSocket
->m_SocketData.onCloseCalled = true;                               
                   pSocket
->OnReceive(WSAESHUTDOWN);
                   
break;
               }
          }

          pSocket
->SetState(nErrorCode?aborted:closed);
          pSocket
->OnClose(nErrorCode);
          
break;
   }
//}

   本节是对第二节的一个小补充,也算是对MS的CAsyncSocket类的一个另类剖析吧。

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理