FileZilla Server源码分析(4)

    本节的分析是基于本系列第二篇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类的一个另类剖析吧。

你可能感兴趣的:(FileZilla Server源码分析(4))