青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

山寨:不是最好的,是最適合我們的!歡迎體驗山寨 中文版MSDN

Blog @ Blog

當華美的葉片落盡,生命的脈絡才歷歷可見。 -- 聶魯達

常用鏈接

統(tǒng)計

積分與排名

BBS

Blog

Web

最新評論

CAsyncSocket,CSocket的使用方法[轉]

    Socket有同步阻塞方式和異步非阻塞方式兩種使用,事實上同步和異步在我們編程的生涯中可能遇到了很多,而Socket也沒什么特別。雖然同步好用,不費勁,但不能滿足一些應用場合,其效率也很低。
    也許初涉編程的人不能理解“同步(或阻塞)”和“異步(或非阻塞)”,其實簡單兩句話就能講清楚,同步和異步往往都是針對一個函數來說的,“同步”就是函數直到其要執(zhí)行的功能全部完成時才返回,而“異步”則是,函數僅僅做一些簡單的工作,然后馬上返回,而它所要實現的功能留給別的線程或者函數去完成。例如,SendMessage就是“同步”函數,它不但發(fā)送消息到消息隊列,還需要等待消息被執(zhí)行完才返回;相反PostMessage就是個異步函數,它只管發(fā)送一個消息,而不管這個消息是否被處理,就馬上返回。

一、Socket API
    首先應該知道,有Socket1.1提供的原始API函數,和Socket2.0提供的一組擴展函數,兩套函數。這兩套函數有重復,但是2.0提供的函數功能更強大,函數數量也更多。這兩套函數可以靈活混用,分別包含在頭文件Winsock.h,Winsock2.h,分別需要引入庫wsock32.lib、Ws2_32.lib。

1、默認用作同步阻塞方式,那就是當你從不調用WSAIoctl()和ioctlsocket()來改變Socket IO模式,也從不調用WSAAsyncSelect()和WSAEventSelect()來選擇需要處理的Socket事件。正是由于函數accept(),WSAAccept(),connect(),WSAConnect(),send(),WSASend(),recv(),WSARecv()等函數被用作阻塞方式,所以可能你需要放在專門的線程里,這樣以不影響主程序的運行和主窗口的刷新。
2、如果作為異步用,那么程序主要就是要處理事件。它有兩種處理事件的辦法:
    第一種,它常關聯(lián)一個窗口,也就是異步Socket的事件將作為消息發(fā)往該窗口,這是由WinSock擴展規(guī)范里的一個函數WSAAsyncSelect()來實現和窗口關聯(lián)。最終你只需要處理窗口消息,來收發(fā)數據。
  第二種,用到了擴展規(guī)范里另一個關于事件的函數WSAEventSelect(),它是用事件對象的方式來處理Socket事件,也就是,你必須首先用WSACreateEvent()來創(chuàng)建一個事件對象,然后調用WSAEventSelect()來使得Socket的事件和這個事件對象關聯(lián)。最終你將要在一個線程里用WSAWaitForMultipleEvents()來等待這個事件對象被觸發(fā)。這個過程也稍顯復雜。
二、CAsyncSocket
    看類名就知道,它是一個異步非阻塞Socket封裝類,CAsyncSocket::Create()有一個參數指明了你想要處理哪些Socket事件,你關心的事件被指定以后,這個Socket默認就被用作了異步方式。那么CAsyncSocket內部到底是如何將事件交給你的呢?
    CAsyncSocket的Create()函數,除了創(chuàng)建了一個SOCKET以外,還創(chuàng)建了個CSocketWnd窗口對象,并使用WSAAsyncSelect()將這個SOCKET與該窗口對象關聯(lián),以讓該窗口對象處理來自Socket的事件(消息),然而CSocketWnd收到Socket事件之后,只是簡單地回調CAsyncSocket::OnReceive(),CAsyncSocket::OnSend(),CAsyncSocket::OnAccept(),CAsyncSocket::OnConnect()等虛函數。所以CAsyncSocket的派生類,只需要在這些虛函數里添加發(fā)送和接收的代碼。
 
  簡化后,大致的代碼為:
 

bool CAsyncSocket::Create( long lEvent ) //參數lEvent是指定你所關心的Socket事件
{
    m_hSocket 
= socket( PF_INET, SOCK_STREAM, 0 ); //創(chuàng)建Socket本身

CSocketWnd
* pSockWnd = new CSocketWnd; //創(chuàng)建響應事件的窗口,實際的這個窗口在AfxSockInit()調用時就被創(chuàng)建了。
pSockWnd->Create();

WSAAsyncSelect( m_hSocket, pSockWnd
->m_hWnd, WM_SOCKET_NOTIFY, lEvent ); //Socket/事件和窗口關聯(lián)
}


static void PASCAL CAsyncSocket::DoCallBack(WPARAM wParam, LPARAM lParam)
{
    CAsyncSocket Socket;
    Socket.Attach( (SOCKET)wParam ); 
//wParam就是觸發(fā)這個事件的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類大致為:

 


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;
}

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

 

void CMySocket::OnAccept( int ErrCode )
{
    CMySocket
* pSocket = new CMySocket;
    Accept( 
*pSocket );
}


    于是,上面的pSocket和客戶方建立了連接,以后的通信就是這個pSocket對象去和客戶方進行,而監(jiān)聽的Socket仍然繼續(xù)在監(jiān)聽,一旦又有一個客戶方要連接服務方,則上面的OnAccept()又會被調用一次。當然pSocket是和客戶方通信的服務方,它不會觸發(fā)OnAccept()事件,因為它不是監(jiān)聽Socket。

三、CSocket
   CSocket是MFC在CAsyncSocket基礎上派生的一個同步阻塞Socket的封裝類。它是如何又把CAsyncSocket變成同步的,而且還能響應同樣的Socket事件呢?
  其實很簡單,CSocket在Connect()返回WSAEWOULDBLOCK錯誤時,不是在OnConnect(),OnReceive()這些事件終端函數里去等待。你先必須明白Socket事件是如何到達這些事件函數里的。這些事件處理函數是靠CSocketWnd窗口對象回調的,而窗口對象收到來自Socket的事件,又是靠線程消息隊列分發(fā)過來的。總之,Socket事件首先是作為一個消息發(fā)給CSocketWnd窗口對象,這個消息肯定需要經過線程消息隊列的分發(fā),最終CSocketWnd窗口對象收到這些消息就調用相應的回調函數(OnConnect()等)。
   所以,CSocket在調用Connect()之后,如果返回一個WSAEWOULDBLOCK錯誤時,它馬上進入一個消息循環(huán),就是從當前線程的消息隊列里取關心的消息,如果取到了WM_PAINT消息,則刷新窗口,如果取到的是Socket發(fā)來的消息,則根據Socket是否有操作錯誤碼,調用相應的回調函數(OnConnect()等)。
  大致的簡化代碼為:

 

BOOL CSocket::Connect(  )
{
    
if!CAsyncSocket::Connect(  ) )
    
{
        
if( WSAGetLastError() == WSAEWOULDBLOCK ) //由于異步操作需要時間,不能立即完成,所以Socket返回這個錯誤
        {
            
//進入消息循環(huán),以從線程消息隊列里查看FD_CONNECT消息,直到收到FD_CONNECT消息,認為連接成功。
            while( PumpMessages( FD_CONNECT ) );
        }

    }

}

BOOL CSocket::PumpMessages( UINT uEvent )
{
    CWinThread
* pThread = AfxGetThread();
    
while( bBlocking )    //bBlocking僅僅是一個標志,看用戶是否取消對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 ) )
    
{    
        
//這里僅關心WM_PAINT消息,以處理阻塞期間的主窗口重畫
        ::DispatchMessage( &msg );
        
return FALSE;
    }

    
return FALSE;
}

   其它的CSocket函數,諸如Send(),Receive(),Accept()都在收到WSAEWOULDBLOCK錯誤時,進入PumpMessages()消息循環(huán),這樣一個原本異步的CAsyncSocket,到了派生類CSocket,就變成同步的了。
  明白之后,我們可以對CSocket應用自如了。比如有些程序員將CSocket的操作放入一個線程,以實現多線程的異步Socket(通常,同步+多線程 相似于 異步 )。

四、CSocketFile
  另外,進行Socket編程,不能不提到CSocketFile類,其實它并不是用來在Socket雙方發(fā)送文件的,而是將需要序列化的數據,比如一些結構體數據,傳給對方,這樣,程序的CDocument()的序列化函數就完全可以和CSocketFile聯(lián)系起來。例如你有一個CMyDocument實現了Serialize(),你可以這樣來將你的文檔數據傳給Socket的另一方:

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

  同樣,接收一方可以只改變上面的代碼為CArchive ar( &file, CArchive::load );即可。
   注意到,CSocketFile類雖然從CFile派生,但它屏蔽掉了CFile::Open()等函數,而函數里僅扔出一個例外。那么也就是說,你不能調用CSocketFile的Open函數來打開一個實實在在的文件,否則會導致例外,如果你需要利用CSocketFile來傳送文件,你必須提供CSocketFile類的這些函數的實現。
  再一點,CArchive不支持在datagram的Socket連接上序列化數據
本文來自: 中國自學編程網(www.zxbc.cn) 詳細出處參考:http://www.zxbc.cn/html/cjjjc/0707454252198_5.html



posted on 2008-01-14 10:35 isabc 閱讀(1183) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發(fā)表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


廣告信息(免費廣告聯(lián)系)

中文版MSDN:
歡迎體驗

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美国产视频日韩| 亚洲一区区二区| 在线电影一区| 在线亚洲自拍| 久久综合久久久| 一区二区三区四区精品| 久久免费国产精品1| 国产精品久久久久久一区二区三区 | 亚洲激情视频在线播放| 亚洲一区尤物| 亚洲免费人成在线视频观看| 欧美激情视频一区二区三区免费 | 欧美大胆成人| 国内一区二区三区| 午夜欧美视频| 夜夜狂射影院欧美极品| 蜜桃久久精品一区二区| 国产亚洲成av人片在线观看桃| 亚洲美女毛片| 亚洲第一免费播放区| 亚洲欧美精品在线观看| 欧美激情精品久久久久| 欧美美女福利视频| 亚洲人成网站777色婷婷| 久久夜色精品国产欧美乱| 猫咪成人在线观看| 一区二区三区视频免费在线观看 | 久久久五月天| 先锋影音国产一区| 国产乱子伦一区二区三区国色天香| 一区二区精品国产| 欧美一区久久| 在线观看国产成人av片| 亚洲精品久久久久久久久久久久| 欧美激情精品久久久久久大尺度| 亚洲国产经典视频| 亚洲第一毛片| 国产婷婷色一区二区三区四区| 亚洲国产精品va在线观看黑人| 免费观看在线综合| 亚洲精品一区二区网址| 亚洲精品视频在线播放| 国产精品xxx在线观看www| 亚洲午夜av| 亚洲综合色婷婷| 一本色道久久综合亚洲精品婷婷| 99国产精品一区| 在线视频国产日韩| 亚洲日本欧美在线| 亚洲国产高清视频| 欧美一区激情视频在线观看| 亚洲在线观看视频网站| 欧美欧美天天天天操| 欧美国产日韩a欧美在线观看| 国产一区在线观看视频| 亚洲国产精品尤物yw在线观看| 狠狠色狠狠色综合系列| 欧美一二三区精品| 亚欧成人精品| 欧美福利网址| 亚洲国产成人久久综合一区| 狠狠色丁香久久婷婷综合丁香 | 亚洲精品视频在线看| 91久久精品www人人做人人爽| 久久精品免费观看| 一本色道久久综合亚洲精品高清 | 亚洲亚洲精品在线观看| 精久久久久久久久久久| 亚洲日本国产| 亚洲毛片在线看| 欧美韩日高清| 日韩天天综合| 亚洲国产高清一区| 免费成人你懂的| 亚洲黄色在线看| 激情欧美日韩| 久久深夜福利免费观看| 欧美激情自拍| 一区二区三区导航| 欧美三级资源在线| 欧美aa国产视频| 国产婷婷色一区二区三区| 性做久久久久久久免费看| 久久久欧美一区二区| 伊人久久亚洲影院| 欧美大片在线观看| 中日韩美女免费视频网址在线观看| 在线播放日韩欧美| 女同一区二区| 亚洲深爱激情| 久久亚洲私人国产精品va媚药| 亚洲第一福利视频| 欧美日韩国产综合视频在线观看中文 | 久久久九九九九| 国产精品电影在线观看| 最新国产成人在线观看| 亚洲综合视频在线| 国产有码一区二区| 欧美激情精品久久久久久大尺度 | 亚洲人成欧美中文字幕| 亚洲欧美视频在线观看| 激情欧美一区二区三区| 欧美理论在线播放| 欧美与欧洲交xxxx免费观看 | 亚洲精品麻豆| 国产欧美日韩免费看aⅴ视频| 亚洲一区二区三区成人在线视频精品 | 国产伪娘ts一区| 免费av成人在线| 亚洲字幕在线观看| 亚洲国产成人高清精品| 久久精精品视频| 国产亚洲精品久久久| 欧美一区二区三区播放老司机| 欧美电影在线观看| 亚洲精品久久久久久下一站 | 欧美日韩一区二区三区在线视频 | 免费高清在线一区| 在线日韩中文| 国产精品亚洲综合色区韩国| 午夜影视日本亚洲欧洲精品| 亚洲高清在线视频| 久久一区精品| 欧美专区亚洲专区| 国产一区二区久久精品| 欧美日韩一区三区| 欧美大片专区| 玖玖国产精品视频| 一区二区三区福利| 亚洲日本成人女熟在线观看| 麻豆freexxxx性91精品| 99re热这里只有精品免费视频| 欧美午夜宅男影院| 欧美理论片在线观看| 久久美女性网| 久久裸体视频| 亚洲精品你懂的| 蜜臀va亚洲va欧美va天堂| 欧美一区二区三区四区高清| 亚洲高清在线观看一区| 国产主播一区二区三区四区| 国产伦精品一区二区三区在线观看| 欧美日韩视频在线观看一区二区三区 | 亚洲成人在线网| 午夜久久久久久| 午夜电影亚洲| 欧美一级理论性理论a| 亚洲一区二区三区精品在线 | 亚洲人成网站精品片在线观看| 亚洲成人直播| 亚洲人成网站色ww在线| 亚洲欧洲精品一区二区三区不卡 | 亚洲福利久久| 另类av一区二区| 久久久青草婷婷精品综合日韩 | 久久久精品日韩欧美| 久久精品成人| 欧美激情视频网站| 欧美激情一区| 日韩系列欧美系列| 亚洲在线观看视频| 久久电影一区| 美女精品网站| 欧美日韩伦理在线| 国产欧美91| 亚洲丰满少妇videoshd| 日韩午夜电影av| 亚洲欧洲av一区二区三区久久| 久久久国产91| 亚洲国产精品va在线看黑人动漫| 亚洲美女电影在线| 午夜在线视频一区二区区别| 久久精品国产免费看久久精品| 免费成人在线视频网站| 欧美视频一区二区| 好男人免费精品视频| 亚洲精品一区久久久久久| 午夜精品福利在线观看| 欧美高清在线一区二区| 亚洲私拍自拍| 免费成人美女女| 国产精品一区二区久久国产| 亚洲国产婷婷香蕉久久久久久| 99精品国产一区二区青青牛奶| 久久不射2019中文字幕| 亚洲韩国日本中文字幕| 亚洲综合色自拍一区| 欧美成人免费观看| 国产日韩精品一区观看| 91久久精品一区二区别| 午夜精品免费| 亚洲理伦电影| 久久久久久色| 国产农村妇女毛片精品久久麻豆| 亚洲区国产区| 毛片基地黄久久久久久天堂 | 久久一区二区三区超碰国产精品 | 久久精品一区二区三区不卡牛牛| 亚洲国语精品自产拍在线观看| 性久久久久久久|