欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
CAsyncSocket,CSocket內幕及其用法
         Socket有同步阻塞方式和異步非阻塞方式兩種使用,事實(shí)上同步和異步在我們編程的生涯中可能遇到了很多,而Socket也沒(méi)什么特別。雖然同步好用,不費勁,但不能滿(mǎn)足一些應用場(chǎng)合,其效率也很低。
         也許初涉編程的人不能理解“同步(或阻塞)”和“異步(或非阻塞)”,其實(shí)簡(jiǎn)單兩句話(huà)就能講清楚,同步和異步往往都是針對一個(gè)函數來(lái)說(shuō)的,“同步”就是函數直到其要執行的功能全部完成時(shí)才返回,而“異步”則是,函數僅僅做一些簡(jiǎn)單的工作,然后馬上返回,而它所要實(shí)現的功能留給別的線(xiàn)程或者函數去完成。例如SendMessage就是“同步”函數,它不但發(fā)送消息到消息隊列,還需要等待消息被執行完才返回;相反PostMessage就是個(gè)異步函數,它只管發(fā)送一個(gè)消息,而不管這個(gè)消息是否被處理,就馬上返回。
一、Socket API
         首先應該知道,有Socket1.1提供的原始API函數,和Socket2.0提供的一組擴展函數,兩套函數。這兩套函數有重復,但是2.0提供的函數功能更強大,函數數量也更多。這兩套函數可以靈活混用,分別包含在頭文件Winsock.h,Winsock2.h,分別需要引入庫wsock32.lib、Ws2_32.lib。
         1、默認用作同步阻塞方式,那就是當你從不調用WSAIoctl()和ioctlsocket()來(lái)改變Socket IO模式,也從不調用WSAAsyncSelect()和WSAEventSelect()來(lái)選擇需要處理的Socket事件。正是由于函數accept(),WSAAccept(),connect(),WSAConnect(),send(),WSASend(),recv(),WSARecv()等函數被用作阻塞方式,所以可能你需要放在專(zhuān)門(mén)的線(xiàn)程里,這樣以不影響主程序的運行和主窗口的刷新。
         2、如果作為異步用,那么程序主要就是要處理事件。它有兩種處理事件的辦法:
         第一種,它常關(guān)聯(lián)一個(gè)窗口,也就是異步Socket的事件將作為消息發(fā)往該窗口,這是由WinSock擴展規范里的一個(gè)函數WSAAsyncSelect()來(lái)實(shí)現和窗口關(guān)聯(lián)。最終你只需要處理窗口消息,來(lái)收發(fā)數據。
         第二種,用到了擴展規范里另一個(gè)關(guān)于事件的函數WSAEventSelect(),它是用事件對象的方式來(lái)處理Socket事件,也就是,你必須首先用WSACreateEvent()來(lái)創(chuàng )建一個(gè)事件對象,然后調用WSAEventSelect()來(lái)使得Socket的事件和這個(gè)事件對象關(guān)聯(lián)。最終你將要在一個(gè)線(xiàn)程里用WSAWaitForMultipleEvents()來(lái)等待這個(gè)事件對象被觸發(fā)。這個(gè)過(guò)程也稍顯復雜。
二、CAsyncSocket
         看類(lèi)名就知道,它是一個(gè)異步非阻塞Socket封裝類(lèi),CAsyncSocket::Create()有一個(gè)參數指明了你想要處理哪些Socket事件,你關(guān)心的事件被指定以后,這個(gè)Socket默認就被用作了異步方式。那么CAsyncSocket內部到底是如何將事件交給你的呢?
         CAsyncSocket的Create()函數,除了創(chuàng )建了一個(gè)SOCKET以外,還創(chuàng )建了個(gè)CSocketWnd窗口對象,并使用WSAAsyncSelect()將這個(gè)SOCKET與該窗口對象關(guān)聯(lián),以讓該窗口對象處理來(lái)自Socket的事件(消息),然而CSocketWnd收到Socket事件之后,只是簡(jiǎn)單地回調CAsyncSocket::OnReceive(),CAsyncSocket::OnSend(),CAsyncSocket::OnAccept(),CAsyncSocket::OnConnect()等虛函數。所以CAsyncSocket的派生類(lèi),只需要在這些虛函數里添加發(fā)送和接收的代碼。
         簡(jiǎn)化后,大致的代碼為:
  bool CAsyncSocket::Create( long lEvent )       //參數lEvent是指定你所關(guān)心的Socket事件
  {
   m_hSocket = socket( PF_INET, SOCK_STREAM, 0 );    //創(chuàng )建Socket本身
   CSocketWnd* pSockWnd = new CSocketWnd;       //創(chuàng )建響應事件的窗口,實(shí)際的這個(gè)窗口在A(yíng)fxSockInit()調用時(shí)就被創(chuàng )建了。
   pSockWnd->Create(...);

   WSAAsyncSelect( m_hSocket, pSockWnd->m_hWnd, WM_SOCKET_NOTIFY, lEvent ); //Socket事件和窗口關(guān)聯(lián)
  }
 
  static void PASCAL CAsyncSocket::DoCallBack(WPARAM wParam, LPARAM lParam)
  {
   CAsyncSocket Socket;
   Socket.Attach( (SOCKET)wParam ); //wParam就是觸發(fā)這個(gè)事件的Socket的句柄
   int nErrorCode = WSAGETSELECTERROR(lParam); //lParam是錯誤碼與事件碼的合成
   switch (WSAGETSELECTEVENT(lParam))
   {
         case FD_READ:
             pSocket->OnReceive(nErrorCode);
             break;
         case FD_WRITE:
             pSocket->OnSend(nErrorCode);
             break;
         case FD_OOB:
             pSocket->OnOutOfBandData(nErrorCode);
             break;
         case FD_ACCEPT:
            pSocket->OnAccept(nErrorCode);
             break;
         case FD_CONNECT:
             pSocket->OnConnect(nErrorCode);
             break;
         case FD_CLOSE:
             pSocket->OnClose(nErrorCode);
             break;
   }
  }

  CSocketWnd類(lèi)大致為:

  BEGIN_MESSAGE_MAP(CSocketWnd, CWnd)
   ON_MESSAGE(WM_SOCKET_NOTIFY, OnSocketNotify)
  END_MESSAGE_MAP()

  LRESULT CSocketWnd::OnSocketNotify(WPARAM wParam, LPARAM lParam)
  {
   CAsyncSocket::DoCallBack( wParam, lParam ); //收到Socket事件消息,回調CAsyncSocket的DoCallBack()函數
   return 0L;
  }

         然而,最不容易被初學(xué)Socket編程的人理解的,也是本文最要提醒的一點(diǎn)是,客戶(hù)方在使用CAsyncSocket::Connect()時(shí),往往返回一個(gè)WSAEWOULDBLOCK的錯誤(其它的某些函數調用也如此),實(shí)際上這不應該算作一個(gè)錯誤,它是Socket提醒我們,由于你使用了非阻塞Socket方式,所以(連接)操作需要時(shí)間,不能瞬間建立。既然如此,我們可以等待呀,等它連接成功為止,于是許多程序員就在調用Connect()之后,Sleep(0),然后不停地用WSAGetLastError()或者CAsyncSocket::GetLastError()查看Socket返回的錯誤,直到返回成功為止。這是一種錯誤的做法,斷言,你不能達到預期目的。事實(shí)上,我們可以在Connect()調用之后等待CAsyncSocket::OnConnect()事件被觸發(fā),CAsyncSocket::OnConnect()是要表明Socket要么連接成功了,要么連接徹底失敗了。至此,我們在CAsyncSocket::OnConnect()被調用之后就知道是否Socket連接成功了,還是失敗了。
         類(lèi)似的,Send()如果返回WSAEWOULDBLOCK錯誤,我們在OnSend()處等待,Receive()如果返回WSAEWOULDBLOCK錯誤,我們在OnReceive()處等待,以此類(lèi)推。
         還有一點(diǎn),也許是個(gè)難點(diǎn),那就是在客戶(hù)方調用Connect()連接服務(wù)方,那么服務(wù)方如何Accept(),以建立連接的問(wèn)題。簡(jiǎn)單的做法就是在監聽(tīng)的Socket收到OnAccept()時(shí),用一個(gè)新的CAsyncSocket對象去建立連接,例如:

 void CMySocket::OnAccept( int ErrCode )
 {
       CMySocket* pSocket = new CMySocket;
       Accept( *pSocket );
 }
         于是,上面的pSocket和客戶(hù)方建立了連接,以后的通信就是這個(gè)pSocket對象去和客戶(hù)方進(jìn)行,而監聽(tīng)的Socket仍然繼續在監聽(tīng),一旦又有一個(gè)客戶(hù)方要連接服務(wù)方,則上面的OnAccept()又會(huì )被調用一次。當然pSocket是和客戶(hù)方通信的服務(wù)方,它不會(huì )觸發(fā)OnAccept()事件,因為它不是監聽(tīng)Socket。
三、CSocket
          CSocket是MFC在CAsyncSocket基礎上派生的一個(gè)同步阻塞Socket的封裝類(lèi)。它是如何又把CAsyncSocket變成同步的,而且還能響應同樣的Socket事件呢?
         其實(shí)很簡(jiǎn)單,CSocket在Connect()返回WSAEWOULDBLOCK錯誤時(shí),不是在OnConnect(),OnReceive()這些事件終端函數里去等待。你先必須明白Socket事件是如何到達這些事件函數里的。這些事件處理函數是靠CSocketWnd窗口對象回調的,而窗口對象收到來(lái)自Socket的事件,又是靠線(xiàn)程消息隊列分發(fā)過(guò)來(lái)的??傊?,Socket事件首先是作為一個(gè)消息發(fā)給CSocketWnd窗口對象,這個(gè)消息肯定需要經(jīng)過(guò)線(xiàn)程消息隊列的分發(fā),最終CSocketWnd窗口對象收到這些消息就調用相應的回調函數(OnConnect()等)。
         所以,CSocket在調用Connect()之后,如果返回一個(gè)WSAEWOULDBLOCK錯誤時(shí),它馬上進(jìn)入一個(gè)消息循環(huán),就是從當前線(xiàn)程的消息隊列里取關(guān)心的消息,如果取到了WM_PAINT消息,則刷新窗口,如果取到的是Socket發(fā)來(lái)的消息,則根據Socket是否有操作錯誤碼,調用相應的回調函數(OnConnect()等)。
         大致的簡(jiǎn)化代碼為:

   BOOL CSocket::Connect( ... )
  {
      if( !CAsyncSocket::Connect( ... ) )
      {
          if( WSAGetLastError() == WSAEWOULDBLOCK ) //由于異步操作需要時(shí)間,不能立即完成,所以Socket返回這個(gè)錯誤
          {
     //進(jìn)入消息循環(huán),以從線(xiàn)程消息隊列里查看FD_CONNECT消息,直到收到FD_CONNECT消息,認為連接成功。
           while( PumpMessages( FD_CONNECT ) );
          }
      }
  }
  BOOL CSocket::PumpMessages( UINT uEvent )
  {
      CWinThread* pThread = AfxGetThread();
      while( bBlocking )      //bBlocking僅僅是一個(gè)標志,看用戶(hù)是否取消對Connect()的調用
      {
          MSG msg;
          if( PeekMessage( &msg, WM_SOCKET_NOTIFY ) )
          {
             if( msg.message == WM_SOCKET_NOTIFY && WSAGETSELECTEVENT(msg.lParam) == uStopFlag )
             {
                 CAsyncSocket::DoCallBack( msg.wParam, msg.lParam );
                 return TRUE;
             }    
         }
         else
        {
             OnMessagePending();   //處理消息隊列里的其它消息
             pThread->OnIdle(-1);
        }
     }
  }
  BOOL CSocket::OnMessagePending()
  {
      MSG msg;
       if( PeekMessage( &msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE ) )
       { //這里僅關(guān)心WM_PAINT消息,以處理阻塞期間的主窗口重畫(huà)
           ::DispatchMessage( &msg );
           return FALSE;
       }
       return FALSE;
  }

         其它的CSocket函數,諸如Send(),Receive(),Accept()都在收到WSAEWOULDBLOCK錯誤時(shí),進(jìn)入PumpMessages()消息循環(huán),這樣一個(gè)原本異步的CAsyncSocket,到了派生類(lèi)CSocket,就變成同步的了。
         明白之后,我們可以對CSocket應用自如了。比如有些程序員將CSocket的操作放入一個(gè)線(xiàn)程,以實(shí)現多線(xiàn)程的異步Socket(通常,同步+多線(xiàn)程相似于異步)。
四、CSocketFile
         另外,進(jìn)行Socket編程,不能不提到CSocketFile類(lèi),其實(shí)它并不是用來(lái)在Socket雙方發(fā)送文件的,而是將需要序列化的數據,比如一些結構體數據,傳給對方,這樣,程序的CDocument()的序列化函數就完全可以和CSocketFile聯(lián)系起來(lái)。例如你有一個(gè)CMyDocument實(shí)現了Serialize(),你可以這樣來(lái)將你的文檔數據傳給Socket的另一方:

 CSocketFile file( pSocket );
 CArchive ar( &file, CArchive::store );
 pDocument->Serialize( ar );
 ar.Close();

         同樣,接收一方可以只改變上面的代碼為CArchive ar( &file, CArchive::load );即可。
         注意到,CSocketFile類(lèi)雖然從CFile派生,但它屏蔽掉了CFile::Open()等函數,而函數里僅扔出一個(gè)例外。那么也就是說(shuō),你不能調用CSocketFile的Open函數來(lái)打開(kāi)一個(gè)實(shí)實(shí)在在的文件,否則會(huì )導致例外,如果你需要利用CSocketFile來(lái)傳送文件,你必須提供CSocketFile類(lèi)的這些函數的實(shí)現。
         再一點(diǎn),CArchive不支持在datagram的Socket連接上序列化數據

本文來(lái)自CSDN博客,轉載請標明出處:http://blog.csdn.net/phlexii/archive/2006/06/27/839053.aspx

 
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
第十四章 SOCKET類(lèi)的設計和實(shí)現
深入 CSocket 編程之阻塞和非阻塞模式
MFC疑難注解:CAsyncSocket及CSocket
CSocket Class
基于多線(xiàn)程的CSocket網(wǎng)絡(luò )編程技術(shù)
Windows Sockets網(wǎng)絡(luò )編程讀書(shū)筆記(及簡(jiǎn)單C/S實(shí)現)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久