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

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

Blog @ Blog

當(dāng)華美的葉片落盡,生命的脈絡(luò)才歷歷可見(jiàn)。 -- 聶魯達(dá)

常用鏈接

統(tǒng)計(jì)

積分與排名

BBS

Blog

Web

最新評(píng)論

CAsyncSocket,CSocket的使用方法[轉(zhuǎn)]

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

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

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

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

CSocketWnd
* pSockWnd = new CSocketWnd; //創(chuàng)建響應(yīng)事件的窗口,實(shí)際的這個(gè)窗口在AfxSockInit()調(diào)用時(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是錯(cuò)誤碼與事件碼的合成
    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事件消息,回調(diào)CAsyncSocket的DoCallBack()函數(shù)
    return 0L;
}

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

 

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


    于是,上面的pSocket和客戶(hù)方建立了連接,以后的通信就是這個(gè)pSocket對(duì)象去和客戶(hù)方進(jìn)行,而監(jiān)聽(tīng)的Socket仍然繼續(xù)在監(jiān)聽(tīng),一旦又有一個(gè)客戶(hù)方要連接服務(wù)方,則上面的OnAccept()又會(huì)被調(diào)用一次。當(dāng)然pSocket是和客戶(hù)方通信的服務(wù)方,它不會(huì)觸發(fā)OnAccept()事件,因?yàn)樗皇潜O(jiān)聽(tīng)Socket。

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

 

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

    }

}

BOOL CSocket::PumpMessages( UINT uEvent )
{
    CWinThread
* pThread = AfxGetThread();
    
while( bBlocking )    //bBlocking僅僅是一個(gè)標(biāo)志,看用戶(hù)是否取消對(duì)Connect()的調(diào)用
    {
        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();        
//處理消息隊(duì)列里的其它消息
            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函數(shù),諸如Send(),Receive(),Accept()都在收到WSAEWOULDBLOCK錯(cuò)誤時(shí),進(jìn)入PumpMessages()消息循環(huán),這樣一個(gè)原本異步的CAsyncSocket,到了派生類(lèi)CSocket,就變成同步的了。
  明白之后,我們可以對(duì)CSocket應(yīng)用自如了。比如有些程序員將CSocket的操作放入一個(gè)線程,以實(shí)現(xiàn)多線程的異步Socket(通常,同步+多線程 相似于 異步 )。

四、CSocketFile
  另外,進(jìn)行Socket編程,不能不提到CSocketFile類(lèi),其實(shí)它并不是用來(lái)在Socket雙方發(fā)送文件的,而是將需要序列化的數(shù)據(jù),比如一些結(jié)構(gòu)體數(shù)據(jù),傳給對(duì)方,這樣,程序的CDocument()的序列化函數(shù)就完全可以和CSocketFile聯(lián)系起來(lái)。例如你有一個(gè)CMyDocument實(shí)現(xiàn)了Serialize(),你可以這樣來(lái)將你的文檔數(shù)據(jù)傳給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()等函數(shù),而函數(shù)里僅扔出一個(gè)例外。那么也就是說(shuō),你不能調(diào)用CSocketFile的Open函數(shù)來(lái)打開(kāi)一個(gè)實(shí)實(shí)在在的文件,否則會(huì)導(dǎo)致例外,如果你需要利用CSocketFile來(lái)傳送文件,你必須提供CSocketFile類(lèi)的這些函數(shù)的實(shí)現(xiàn)。
  再一點(diǎn),CArchive不支持在datagram的Socket連接上序列化數(shù)據(jù)
本文來(lái)自: 中國(guó)自學(xué)編程網(wǎng)(www.zxbc.cn) 詳細(xì)出處參考:http://www.zxbc.cn/html/cjjjc/0707454252198_5.html



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


只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問(wèn)   Chat2DB   管理


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

中文版MSDN:
歡迎體驗(yàn)

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            午夜精品短视频| 国产欧美精品日韩精品| 国产一级揄自揄精品视频| 亚洲欧美另类中文字幕| 先锋亚洲精品| 亚洲日本成人网| 亚洲人成网站777色婷婷| 亚洲伊人网站| 国产一区在线免费观看| 久久男人av资源网站| 国产亚洲一区二区在线观看| 欧美精品首页| 巨胸喷奶水www久久久免费动漫| 欧美日韩激情网| 欧美二区在线| 日韩亚洲国产欧美| 欧美人与性动交α欧美精品济南到| 午夜精品999| 久久电影一区| 蜜桃精品一区二区三区| 欧美激情中文字幕乱码免费| 午夜精品电影| 欧美国产另类| 久久久久九九九| 欧美三日本三级少妇三99| 久久五月激情| 国产精品久久福利| 亚洲国产成人精品久久久国产成人一区 | 亚洲黄色毛片| 国产亚洲欧美一区二区| 99国产精品久久久久久久| 亚洲国产成人久久综合一区| 亚洲尤物精选| 一区二区三区欧美视频| 免费在线观看一区二区| 久久午夜电影| 国产一区日韩欧美| 亚洲夜间福利| 一区二区三区视频在线| 欧美精品在线播放| 亚洲国产精品一区二区久 | 亚洲欧美一区二区精品久久久| 中文日韩电影网站| 欧美激情视频免费观看| 欧美jizz19性欧美| 国产日韩欧美在线视频观看| 亚洲无线一线二线三线区别av| 99精品欧美一区二区蜜桃免费| 欧美主播一区二区三区美女 久久精品人 | 国产专区精品视频| 亚洲小说区图片区| 国产精品一区二区久久精品| 久久久久久九九九九| 欧美日韩亚洲一区| 亚洲经典在线| 一区二区视频免费完整版观看| 亚洲午夜精品17c| 在线亚洲美日韩| 99精品热视频| 午夜久久久久久久久久一区二区| 亚洲成色www8888| 欧美在线综合视频| 亚洲欧美电影在线观看| 欧美乱妇高清无乱码| 男人天堂欧美日韩| 韩国av一区二区| 欧美在线视频观看免费网站| 久久av一区二区| 国产精品一级二级三级| 一本色道久久综合亚洲二区三区| 日韩视频一区二区三区| 另类欧美日韩国产在线| 老牛嫩草一区二区三区日本 | 亚洲日本激情| 免费不卡视频| 亚洲国产天堂久久综合| 亚洲人成精品久久久久| 久久亚洲影音av资源网| 欧美成人自拍视频| 亚洲国产日韩欧美综合久久| 久久一区二区三区四区| 欧美刺激性大交免费视频| 亚洲国产老妈| 免费久久99精品国产自在现线| 欧美不卡高清| 亚洲精品专区| 欧美日韩综合久久| 午夜精品久久久久久99热| 久久久.com| 亚洲大片在线观看| 欧美大片一区二区三区| 一本久久精品一区二区| 午夜国产欧美理论在线播放 | 欧美激情亚洲视频| 日韩一级黄色大片| 欧美日韩在线视频首页| 亚洲国产高清在线观看视频| 亚洲免费播放| 国产精品成人一区二区三区夜夜夜| 亚洲一区二区免费看| 久久久99国产精品免费| 国产精品亚洲欧美| 午夜精品999| 久久久久国产精品一区三寸| 影院欧美亚洲| 欧美激情中文字幕在线| 亚洲一区二区三区涩| 久久综合伊人77777尤物| 亚洲国产精品99久久久久久久久| 欧美日本高清| 欧美一区二区三区久久精品茉莉花| 亚洲国产成人久久| 欧美一区二区日韩| 亚洲人成绝费网站色www| 欧美午夜电影在线| 亚洲一区国产精品| 久久这里只有| 在线亚洲一区观看| 韩国精品在线观看| 欧美三级电影精品| 久久久夜精品| 一本久久知道综合久久| 久久夜色精品国产噜噜av| 日韩网站在线观看| 一区二区高清视频| 欧美日韩国产专区| 亚洲成色777777女色窝| 在线免费观看成人网| 欧美日韩精品免费观看视一区二区 | av成人激情| 麻豆国产精品777777在线| 宅男66日本亚洲欧美视频| 国产主播喷水一区二区| 老鸭窝91久久精品色噜噜导演| 亚洲一区久久久| 亚洲国产综合在线看不卡| 久久久999精品| 亚洲永久免费| 亚洲三级影院| 亚洲电影免费观看高清| 国产九区一区在线| 欧美午夜视频一区二区| 欧美a级一区| 久久免费视频一区| 女同性一区二区三区人了人一| 久久xxxx精品视频| 一本一道久久综合狠狠老精东影业 | 欧美成人久久| 久久久www成人免费毛片麻豆| 亚洲一区精品电影| 亚洲美女中出| 亚洲欧洲日本国产| 欧美肥婆bbw| 性久久久久久久久| 久久精品一区蜜桃臀影院| 午夜视频在线观看一区| 99国内精品久久| 亚洲激情电影在线| 91久久精品国产91久久| 亚洲福利视频在线| 好看的亚洲午夜视频在线| 国产视频精品免费播放| 国产情人节一区| 国产日韩欧美在线观看| 尤物在线精品| 在线观看成人小视频| 在线观看91精品国产麻豆| 精品69视频一区二区三区| 国精产品99永久一区一区| 国产一区91精品张津瑜| 国产一级一区二区| 影音先锋另类| 亚洲欧洲免费视频| 一区二区三区在线视频观看| 亚洲人成亚洲人成在线观看| 亚洲人成人99网站| 亚洲免费电影在线| 一区二区三区国产在线观看| 亚洲视屏在线播放| 欧美一区二区成人6969| 久久久久久精| 欧美成人影音| 99成人免费视频| 亚洲乱码国产乱码精品精可以看| 亚洲欧美一区二区三区在线| 欧美在线综合视频| 免费在线观看日韩欧美| 欧美日韩喷水| 国产精品视频一二三| 国产一区二区视频在线观看| 伊人久久大香线蕉综合热线| 伊人久久av导航| 99精品免费视频| 亚洲欧洲一区二区三区久久| 亚洲免费观看在线观看| 你懂的国产精品| 久久精品女人| 欧美大片免费观看| 91久久久久久久久| 亚洲一级免费视频|