日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

MFC之CAsyncSocket详解

發(fā)布時間:2023/12/10 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MFC之CAsyncSocket详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

CAsyncSocket類是從Object類派生而來。CAsyncSocket對象稱為異步套接字對象

使用CAsyncSocket進(jìn)行網(wǎng)絡(luò)編程,可以充分利用Windows操作系統(tǒng)提供的消息驅(qū)動機(jī)制,通過應(yīng)用程序框架來傳遞消息,方便地處理各種網(wǎng)絡(luò)事件。另一方面,作為MFC微軟基礎(chǔ)類庫中的一員,CAsyncSocket可以和MFC的其他類融為一體,大大擴(kuò)展了網(wǎng)絡(luò)編程的空間,方便了編程。

?

使用CAsyncSocket的一般步驟

網(wǎng)絡(luò)應(yīng)用程序一般采用客戶端/服務(wù)器模式,他們使用的CAsyncSocket編程有所不同,下面以表格的形式方式看一下服務(wù)器和客戶端之間的不同

?

序號服務(wù)端客戶端
1

構(gòu)造一個套接字

CAsyncSocket sockServer

構(gòu)造一個套接字

CAsyncSocket sockClient

2

創(chuàng)建SOCKET句柄,綁定到指定的端口

sockServer.Create(nPort);

創(chuàng)建SOCKET句柄,使用默認(rèn)參數(shù)

sockClient.Create();

3

啟動監(jiān)聽,時刻準(zhǔn)備接收連接請求

sockServer.Listen();

?
4?

請求鏈接服務(wù)器

sockClient.Connect(strAddress,nPort)

5

構(gòu)造一個新的空套接字

CAsyncSocket sockRecv;

接收連接

sockServer.Accept(sockRecv);

?
6

接收數(shù)據(jù)

sockRecv.Receive(pBuffer,nLen);

發(fā)送連接

sockClient.Send(pBuffer,nLen);

7

發(fā)送數(shù)據(jù)

sockRecv.Send(pBuffer,nLen);

接收數(shù)據(jù)

sockClient.Receive(pBuffer,nLen);

8

關(guān)閉套接字對象

sockRecv.Close();

關(guān)閉套接字對象

sockClient.Close();

ps:客戶端與服務(wù)端都要首先構(gòu)造一個CAsyncSocket對象,然后使用該對象的Create成員函數(shù)來創(chuàng)建底層的SOCKET句柄。服務(wù)器端要綁定到特定的端口

?

對于服務(wù)器端的套接字對象,應(yīng)使用CAsyncSocket::Listen函數(shù)進(jìn)行監(jiān)聽狀態(tài),一旦收到來自客戶端的鏈接請求,就調(diào)用CAsyncSocket::Accept來接收。對于客戶端的套接字對象,應(yīng)當(dāng)使用CAsyncSocket::Connect來連接到一個服務(wù)器端的套接字對象。建立鏈接之后,雙方就可以按照應(yīng)用層協(xié)議交換數(shù)據(jù)了。

這里需要注意,Accept是將一個新的空CAsyncSocket對象作為它的參數(shù),在調(diào)用Accept之前必須構(gòu)造這個對象。與客戶端套接字的連接是通過它建立的,如果這個套接字對象退出,連接也就關(guān)閉。對于這個新的套接字對象,不需要調(diào)用Create來創(chuàng)建它的底層套接字

?

調(diào)用CAsyncSocket對象的其他成員函數(shù),如Send和Receive執(zhí)行與其他套接字對象的通信,這些成員函數(shù)與Windows Sockets API函數(shù)在形式和用法上基本是一致的。

?

關(guān)閉并銷毀CAsyncSocket對象。如果在堆棧上創(chuàng)建了套接字對象,當(dāng)包含此對象的函數(shù)退出時,會調(diào)用該類的析構(gòu)函數(shù),銷毀該對象。在銷毀該對象之前,析構(gòu)函數(shù)會調(diào)用該對象的Close成員函數(shù)。如果在堆上使用new創(chuàng)建了套接字對象,可先調(diào)用Close成員函數(shù)關(guān)閉它,在使用delete來刪除釋放該對象

?

在使用CAsyncSocket進(jìn)行網(wǎng)絡(luò)通信時,我們還需要處理以下幾個問題:

?

1.堵塞處理,CAsyncSocket對象專用于異步操作,不支持堵塞工作模式,如果應(yīng)用程序需要支持堵塞操作,必須自己解決

2.字節(jié)順序的轉(zhuǎn)換。在不同的結(jié)構(gòu)類型的計算機(jī)之間進(jìn)行數(shù)據(jù)傳輸時,可能會有計算機(jī)之間字節(jié)存儲順序不一致的情況。用戶程序需要自己對不用的字節(jié)順序進(jìn)行轉(zhuǎn)換

3.字符串轉(zhuǎn)換。同樣,不同結(jié)構(gòu)類型的計算機(jī)的字符串存儲順序也可能不同,需要自行轉(zhuǎn)換,如Unicode和ANSI字符串之間的轉(zhuǎn)換

?

創(chuàng)建CAsyncSocket對象

創(chuàng)建異步套接字對象一般是分為兩個步驟,首先要構(gòu)造CAsyncSocket對象,其次創(chuàng)建該對象底層的SOCKET句柄

?

1.創(chuàng)建空的CAsyncSocket對象

通過調(diào)用CAsyncSocket構(gòu)造函數(shù),創(chuàng)建一個新的空CAsyncSocket套接字對象,構(gòu)造函數(shù)還帶參數(shù)。套接字對象創(chuàng)建之后必須調(diào)用他的成員函數(shù)來創(chuàng)建底層的套接字?jǐn)?shù)據(jù)結(jié)構(gòu),并綁定他的地址

?

方法如下:

1.

C++

  • CAsyncSocket Sock

  • Sock.Create(...)

  • 2.

    C++

  • CAsyncSocket *pSock = new CAsyncSocket;

  • pSock->Create(...);

  • ?
  • delete pSock;

  • pSock =NULL;

  • ps:之前見過很多朋友釋放指針的時候總是delete就完事了,往往不知正在給自己的程序帶來前所未有的災(zāi)難,而此時的指針我們稱之為“野指針”,注意:野指針不是NULL指針,而是不可用內(nèi)存的指針,即垃圾指針;野指針是很危險的,因為我們無法通過if去判斷指針是正常指針還是野指針,所以,我們在書寫代碼時一定要養(yǎng)成良好的編程習(xí)慣!!!避免野指針的方法我們可以通過以下幾點:

    1.聲明指針一定要初始化,如果不初始化為NULL,那么此時一定要指向一塊合法的內(nèi)存

    2.當(dāng)調(diào)用delete或者free去釋放指針后,一定要將指針重新指向NULL,可以參照SkinUI的SafeDelete

    3.指針操作超出了變量的作用范圍,比如如下代碼,

    C++

  • class A

  • {

  • void Fun(){}

  • };

  • class B

  • {

  • A *m_A;

  • B(){m_A=NULL;}

  • ?
  • void Fun()

  • {

  • A a

  • m_A =&a;

  • //注意變量A的生命周期,當(dāng)該方法執(zhí)行完畢后,A會被釋放,此時m_A就變成了無效的野指針

  • }

  • void Fun1()

  • {

  • m_A->Fun(); //m_A為野指針,到這里也就出現(xiàn)了錯誤

  • }

  • };

  • 通過上述方法可以大大的降低代碼出現(xiàn)野指針的風(fēng)險。

    ?

    2.創(chuàng)建CAsyncSocket套接字的底層套接字句柄

    通過CAsyncSocket::Create創(chuàng)建該對象的底層套接字句柄,決定套接字對象的具體特性。

    函數(shù)原型如下:

    C++

  • BOOL Create(

  • UINT nSocketPort = 0,

  • int nSocketType = SOCK_STREAM,

  • long lEvent = FD_READ|FD_WRITE|FD_OOB|FD_ACCEPT|FD_CONNECT|FD_CLOSE,

  • LPCTSTR lpszSocketAddress = NULL

  • );

  • ?

    參數(shù):

    nSocketPort,指定了一個分配給套接字的傳輸層端口號,默認(rèn)值為0,表示讓系統(tǒng)為這個套接字分配一個自由的端口號。但是對于服務(wù)器應(yīng)用程序而言,一般都需要事先分配一個公認(rèn)的端口號,所以切記,服務(wù)器應(yīng)用程序調(diào)用此函數(shù)時,必須分配一個端口號

    nSocketType,套接字的類型,當(dāng)指定為SOCK_STREAM時表示生成流式套接字,若使用SOCK_DGRAM表示生成數(shù)據(jù)報套接字

    lEvent,指定為CAsyncSocket對象生成通知消息的套接字事件,默認(rèn)對所有的套接字事件都生成通知消息

    lpszSocketAddress,指定套接字的網(wǎng)絡(luò)地址,對Internet通信域來說,就是主機(jī)的域名或者ip地址,比如www.gymsaga.com或123.123.123.123。如果使用默認(rèn)值,表示使用默認(rèn)的本機(jī)ip地址

    ?

    關(guān)于CAsyncSocket可以接受并處理的消息事件

    在CAsyncSocket::Create中,參數(shù)lEvent指定了為CAsyncSocket對象生成通知消息的套接字事件,最能體現(xiàn)CAsyncSocket對Windows消息驅(qū)動機(jī)制的支持

    先認(rèn)識一下這六種相關(guān)事件和通知消息

    關(guān)于lEvent參數(shù)的符號常量,我們可以在WinSock中找到

    C++

  • /*

  • * Define flags to be used with the WSAAsyncSelect() call.

  • */

  • #define FD_READ 0x01

  • #define FD_WRITE 0x02

  • #define FD_OOB 0x04

  • #define FD_ACCEPT 0x08

  • #define FD_CONNECT 0x10

  • #define FD_CLOSE 0x20

  • 它們代表了MFC套接字對象可以接收并處理的6種網(wǎng)絡(luò)事件,當(dāng)事件發(fā)生時,套接字對象會收到相應(yīng)的通知消息,并自動執(zhí)行套接字對象響應(yīng)的事件處理函數(shù)

    1:FD_READ : ? 通知有數(shù)據(jù)可讀。當(dāng)一個套接字對象的數(shù)據(jù)輸入緩沖區(qū)收到其他套接字對象發(fā)送來的數(shù)據(jù)時,發(fā)生此事件,并通過該套接字對象 ,告訴它可以調(diào)用Receive成員來接收數(shù)據(jù)

    2:FD_WRITE: ? 通知可以寫數(shù)據(jù),當(dāng)一個套接字對象的數(shù)據(jù)輸出緩沖區(qū)中的數(shù)據(jù)已經(jīng)發(fā)送出去,輸出緩沖區(qū)已騰空時,發(fā)生此事件,并通過該套接字對象,告訴它可以調(diào)用Send函數(shù)向外發(fā)送數(shù)據(jù)

    3:FD_ACCEPT: ?通知監(jiān)聽套接字有連接請求可以接收。當(dāng)客戶端的鏈接請求到達(dá)服務(wù)器時,進(jìn)一步說,是當(dāng)客戶端的連接請求已經(jīng)進(jìn)入服務(wù)器監(jiān)聽套接字的接收緩沖區(qū)隊列時,發(fā)生此事件,并通過監(jiān)聽套接字對象,告訴它可以調(diào)用Accept成員來接收待決的鏈接請求。這個事件僅對流式套接字有效,并且發(fā)生在服務(wù)器端

    4:FD_CONNECT: 通知請求鏈接的套接字,鏈接的要求已經(jīng)被處理。當(dāng)客戶端的連接請求已被處理時,發(fā)生此事件。存在兩種情況:一種是服務(wù)器端已接收了鏈接請求,雙方的連接已經(jīng)建立,通知客戶端套接字,可以使用鏈接來傳輸數(shù)據(jù)了;另一種情況是鏈接請求被拒絕,通知客戶機(jī)套接字,它所請求的連接失敗。這個事件僅對流式套接字有效,并且發(fā)生在客戶端

    5:FD_CLOSE: ? 通知套接字已關(guān)閉。當(dāng)鏈接的套接字關(guān)閉時發(fā)生

    6:FD_OOB: ? ? 通知將帶外數(shù)據(jù)到達(dá)。當(dāng)對方的流失套接字發(fā)送帶外數(shù)據(jù)時,發(fā)生此事件,并通知接收套接字,正在發(fā)送的套接字有帶外數(shù)據(jù)要求發(fā)送,帶外數(shù)據(jù)是有沒對鏈接的流失套接字相關(guān)的在邏輯上獨立的通道,帶外數(shù)據(jù)通道典型的是用來發(fā)送緊急數(shù)據(jù)。MFC支持帶外有數(shù)據(jù),使用CAsyncSocket類的高級用戶可能需要使用帶外數(shù)據(jù)通道,但不鼓勵使用CSocket類的用戶使用它,更容易的方法是創(chuàng)建第二個套接字來傳送這樣的數(shù)據(jù)

    ?

    MFC框架對這六種事件的處理

    當(dāng)上述的網(wǎng)絡(luò)事件發(fā)生時,MFC框架做何處理呢?MFC框架按照Windows系統(tǒng)的消息驅(qū)動把消息發(fā)送給相應(yīng)的套接字對象,并調(diào)用作為該對象函數(shù)的事件處理函數(shù),事件與處理函數(shù)一一映射。

    ?

    在afxSock.h中我們可以找到CAsyncSocket類對這六種對應(yīng)事件的處理函數(shù)

    C++

  • // Overridable callbacks

  • protected:

  • virtual void OnReceive(int nErrorCode);

  • virtual void OnSend(int nErrorCode);

  • virtual void OnOutOfBandData(int nErrorCode);

  • virtual void OnAccept(int nErrorCode);

  • virtual void OnConnect(int nErrorCode);

  • virtual void OnClose(int nErrorCode);

  • 其中參數(shù)nErrorCode的值,是在函數(shù)被調(diào)用時,由MFC框架提供的,表明套接字最新的狀況,如果是0,說明成功,如果為非零值,說明套接字對象有某種錯誤

    當(dāng)某個網(wǎng)絡(luò)事件發(fā)生時,MFC框架會自動調(diào)用套接字對象對應(yīng)的事件處理函數(shù)。這就相當(dāng)于給套接字對象一個通知,告訴它某個重要的事件已經(jīng)發(fā)生,所以也稱為套接字類的通知函數(shù)或者回調(diào)函數(shù)

    ?

    3.重載套接字對象的回調(diào)函數(shù)

    在編程中,一般我們不會直接去使用CAsyncSocket或者CSocket,而是從他們派生出自己的套接字類來。然后在派生類中對這些虛函數(shù)進(jìn)行重載處理,加入應(yīng)用程序?qū)τ诰W(wǎng)絡(luò)事件處理的特定代碼

    如果是從CAsyncSocket類派生了自己的套接字類,就必須重載該應(yīng)用程序所感興趣的那些網(wǎng)絡(luò)事件所對應(yīng)的通知函數(shù)。如果從CSocket類派生一個類,是否重載所感興趣的通知函數(shù)則由自己決定。也可以使用CSocket類本身的回調(diào)函數(shù),但默認(rèn)情況下,CSocket本身的回調(diào)函數(shù)什么也不做,只是一個空函數(shù)。

    MFC框架自動調(diào)用通知函數(shù),使得用戶可以在套接字被通知的時候來優(yōu)化套接字的行為。例如,用戶可以從自己的OnReceive通知函數(shù)中調(diào)用套接字對象的成員函數(shù)Receive,就是說,在被通知的時候,已經(jīng)有數(shù)據(jù)可讀了,才調(diào)用Receive來讀取它。這個方法不是必須的,但它是一個有效的方案。此外,也可以使用自己的通知函數(shù)跟蹤進(jìn)程,打印TRACE消息等

    對于CSocket對象,還有如下一些不同之處

    在一個諸如接收或者發(fā)送數(shù)據(jù)的操作期間,一個CSocket對象成為同步的,在同步狀態(tài)期間,在當(dāng)前套接字等待它想要的通知時,任何的為其他套接字的通知被排成隊列,一旦該套接字完成了它的同步操作,并再次成為異步的,其他的套接字才可以開始接收排列的通知

    ?

    重要的一點是:在CSocket中,從來不調(diào)用OnConncet通知函數(shù),對于連接,簡單的調(diào)用Conncet函數(shù),僅當(dāng)連接完成時,無論成功還是失敗,該函數(shù)都返回,連接通知如何被處理是一個MFC內(nèi)部的實現(xiàn)細(xì)節(jié)。

    總結(jié)

    以上是生活随笔為你收集整理的MFC之CAsyncSocket详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。