多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > 互聯網 > 網絡編程(57)—— Windows下使用CAsyncSocket搭建回聲服務端和客戶端

網絡編程(57)—— Windows下使用CAsyncSocket搭建回聲服務端和客戶端

來源:程序員人生   發布時間:2017-02-22 08:46:16 閱讀次數:2799次

1、 引言

        CAsyncSocketMFC中對WSAAsyncSelect異步非阻塞通知IO的1個封裝我們Windows下使用WSAAsyncSelect實現窗口處理socket消息》1文討論WSAAsyncSelect用法知道它綁定1個窗口1個socket并注冊了我們自定義的消息和需要監視的IO事件類型(FD_ACCEPTFD_READ、FD_WRITE等等綁定socket產生注冊的IO事件后,操作系統會給上述窗口發送我們自定義的消息而接下來我們就能夠針對事件類型而做不同的處理。CAsyncSocket就是將WSAAsyncSelect進行了封裝,內部使用了1個不可見的窗口并隱藏了注冊綁定進程其內部實現原理WSAAsyncSelect使用相同。

  下面主要討論下CAsyncSocket的用法,我們要實現的效果是,創建1個都帶界面的服務端和客戶端。客戶端允許用戶輸入字符串,然后發送給服務端端,服務端接收客戶真個字符串后原樣返回,在客戶端界面上顯示。

2、 CAsyncSocket的主要成員介紹

          CAsyncSocket主要包括以下成員:

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

        我們Create創建1個異步socket對象,在Create的參數中我們可以指定端口號、協議類型、注冊的事件類型IP地址。如果傳參Create提供了默許形參;如果你想要修改,可以使用CAsyncSocket提供Bind、AsyncSelect等接口進行修改

BOOL Listen( int nConnectionBacklog = 5 );

        用來開啟監聽。

virtual BOOL Accept( CAsyncSocket& rConnectedSocket, SOCKADDR* lpSockAddr = NULL, int* lpSockAddrLen = NULL );

       用來接收客戶端連接

BOOL Connect( LPCTSTR lpszHostAddress, UINT nHostPort );

      用來連接服務

virtual void OnAccept( int nErrorCode );
virtual void OnClose ( int nErrorCode );
virtual void OnConnect ( int nErrorCode );
virtual void OnReceive ( int nErrorCode );
virtual void OnSend ( int nErrorCode );

       上述函數都是系統的回調函數,在socket產生相應的IO事件時進行調用它們都定義成了虛函數,需要我們進行繼承并進行相應的處理。

3、封裝CAsyncSocket的派生類

       在使用CAsyncSocket時我們需要定義自己的CAsyncSocket派生類,在派生類中我們通過繼承虛函數的情勢可以自由的處理各類socket的io事件,我們定義的名稱叫做CMySocket:

class CMySocket : public CAsyncSocket
{
    ....
}

       在CMySocket中我們定義1個CWnd*類型的成員變量用來接收伏務端和客戶端窗口的指針:

    CWnd* m_pWnd;

     我們重載OnAccept等回調函數,在每一個函數中向m_pWnd發送自定義的消息,這樣我們在服務端和客戶真個窗口處理函數中就能夠處理這些消息。

void CMySocket::OnAccept(int nErrorCode)
{
	int param=ACCEPT;
	if(m_pWnd!=NULL)
		m_pWnd->SendMessage(WM_MYSOCKET,(WPARAM)this,(LPARAM)?m);
	CAsyncSocket::OnAccept(nErrorCode);
}

void CMySocket::OnReceive(int nErrorCode)
{
	int param=RECIEVE;
	if(m_pWnd!=NULL)
		m_pWnd->SendMessage(WM_MYSOCKET,(WPARAM)this,(LPARAM)?m);
	CAsyncSocket::OnReceive(nErrorCode);
}

void CMySocket::OnClose(int nErrorCode)
{
	int param=CLOSE;
	if(m_pWnd!=NULL)
		m_pWnd->SendMessage(WM_MYSOCKET,(WPARAM)this,(LPARAM)?m);
	CAsyncSocket::OnClose(nErrorCode);
}

void CMySocket::OnConnect(int nErrorCode)
{
	int param=CONNECT;
	if(m_pWnd!=NULL)
		m_pWnd->SendMessage(WM_MYSOCKET,(WPARAM)this,(LPARAM)?m);
	CAsyncSocket::OnConnect(nErrorCode);
}

void CMySocket::OnSend(int nErrorCode)
{
	int param=SEND;
	if(m_pWnd!=NULL)
		m_pWnd->SendMessage(WM_MYSOCKET,(WPARAM)this,(LPARAM)?m);
	CAsyncSocket::OnSend(nErrorCode);
}

       可以看到,在上述每一個虛函數中,我們都調用m_pWnd的SendMessage函數向系統的消息隊列中發送了自定義的WM_MYSOCKET消息。并通過WPARAM和LPARAM參數把當前CMySocket對象和代表事件類型的宏附加到消息的參數中。

4、在客戶端和服務端中添加消息處理函數

       在服務端我們自定義WM_MYSOCKET的消息處理函數以下

afx_msg LRESULT CServDlg::OnMysocket(WPARAM wParam, LPARAM lParam)
{
	CMySocket* pservSock=(CMySocket*)wParam;
	CMySocket* pClntSock=new CMySocket();
	SOCKADDR_IN clntAddr;
	int clntAddrSz=sizeof(clntAddr);
	int param=*((int*)(lParam));
	int recvLen;
	char buf[BUF_SIZE];
	switch(param)
	{
	case ACCEPT:
		{
			pservSock->Accept(*pClntSock,(SOCKADDR*)&clntAddr,&clntAddrSz);
			pClntSock->m_pWnd=this;
			m_pClnts.AddTail(pClntSock);
		}
		break;
	case RECIEVE:
		{
			int strLen =pservSock->Receive(buf,BUF_SIZE,0);
			pservSock->Send(buf,strLen,0);

		}
		break;
	default:
		break;
	}
	return 0;
}

        在上述消息處理函數中我們new了1個客戶端socket的指針:

CMySocket* pClntSock=new CMySocket();

       在這里我們不可以將客戶真個socket聲明為局部變量,由于CAsyncSocket對象離開作用域中會調用析構函數進行析構。如果我們這里在棧中創建1個clntSock而非new1個pClntSock,OnMysocket調用結束后,已連接的客戶端socket會自動斷開連接后續將沒法進行sendreceive等操作。

       在處理ACCEPT消息時,我們調用了Accept函數,這里普通的accept函數類似,我們獲得到了連接到服務真個pClntSock,接下來窗口的this指針賦值給了pClntSockm_pWnd這點很重要,由于我們在調用pservSock->Send(buf,strLen,0)進行數據的發送時,Send函數內部實際上會調用pClntSockOnSend回調函數,我們需要在這個回調函數中向pClntSock的m_pWnd發送自定義消息。

        在客戶端中,我們也要添加1個自定義消息的處理函數:

afx_msg LRESULT CClntDlg::OnMysocket(WPARAM wParam, LPARAM lParam)
{
	CMySocket* pSock=(CMySocket*)wParam;
	int param=*((int*)(lParam));
	int recvLen;
	char buf[BUF_SIZE];
	switch(param)
	{
	case RECIEVE:
		{
			int strLen = pSock->Receive(buf,BUF_SIZE⑴,0);
			buf[strLen]=0;
			CString str;
			str.Format("%s",buf);
			m_recv.SetWindowText(str);
		}
		break;
	default:
		break;
	}
	return 0;
}

       上述內容,只是對幾處關鍵性的代碼進行了解釋,需要全部的代碼,請自行Github下載,服務端和客戶端的運行效果以下:

客戶端:


客戶端:



 Github位置:
https://github.com/HymanLiuTS/NetDevelopment
克隆本項目:
git clone git@github.com:HymanLiuTS/NetDevelopment.git
獲得本文源代碼:
git checkout NL57

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 免费h网站在线观看 | 欧美成人一区二区三区不卡视频 | 美国一级毛片片aa成人 | 五月网站 | 国产精品不卡高清在线观看 | 欧美一级毛片免费观看 | 欧美jizz大又粗 | porn日本xxx护士 | 越猛烈欧美xx00动态图带声音 | 91在线 | porny | 欧美 | 亚洲成年网站 | aa级国产女人毛片好多水 | 久久www成人看片 | 美女福利视频一区二区 | 色人阁在线观看 | 美国私人vps一夜爽毛片免费 | 最近高清中文国语视频 | 高级毛片| 亚洲色图视频在线 | 国产美女激情视频无打码 | 欧美性videostv极度另类 | 复仇之路在线观看免费版高清 | 欧美在线视频观看 | 狂野欧美激情性xxxx | xxfree性人妖hd | 91久久偷偷做嫩草影院免费看 | 欧美精品18videos性欧美 | 久久中文字幕不卡一二区 | 日本高清免费中文字幕不卡 | 天堂日本| 久久精品国产精品亚洲20 | 在线久综合色手机在线播放 | 免费一级毛片正在播放 | 另类小说区 | 天啦噜tianlalu精品视频 | 一区二区久久 | 亚洲图片在线欧美专区图片 | 双性h啪啪樱桃动漫直接观看 | 欧美国产亚洲18 | 日本欧美视频在线 | 午夜视频网址 |