日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

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

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

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

1、 引言

        CAsyncSocketMFC中對WSAAsyncSelect異步非阻塞通知IO的1個封裝。我們Windows下使用WSAAsyncSelect實現窗口處理socket消息》1文討論WSAAsyncSelect用法知道它綁定1個窗口1個socket并注冊了我們自定義的消息和需要監視的IO事件類型(FD_ACCEPT、FD_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

生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 国产91在线 | 亚洲 | 欧美不卡激情三级在线观看 | 欧美精品一区在线观看 | 亚洲精品久久 | 99热在线只有精品 | 999国产视频 | 成人欧美一区二区三区视频xxx | 精品国产综合区久久久久久 | 爱情岛亚洲论坛入口福利 | 伊人9 | 中文字幕一区二区三 | 免费h片| 精品一区二区三区久久 | 国产网站黄 | 精品国产精品国产偷麻豆 | 国产精品视频免费看 | 欧美日韩色 | 国产精品久久久久久久久免费高清 | 99在线精品免费视频九九视 | 免费a在线播放 | 久在草 | 国产在线观看一区二区三区 | 91操视频| 肉色欧美久久久久久久免费看 | 偷拍自拍在线观看 | 91精品国产高清 | 天天操夜夜摸 | 狠狠干狠狠干 | 不卡av电影在线 | 亚洲一级免费视频 | 欧美日韩国产在线一区 | 精品一区二区三区不卡 | 婷婷激情五月 | av免费看片 | 国产日韩精品视频 | 精品美女久久久久久免费 | 欧美 日韩 国产 在线 | 欧美激情视频一区二区三区 | 久久成人在线 | 国产精品色综合一区二区三区 | 日产精品久久久一区二区 |