網路程式設計(53)—— Windows下使用WSAAsyncSelect實現視窗處理socket訊息
一、引言
上一文中我們介紹了使用WSAEventSelect實現非同步通知IO的方法,本文我們主要討論下使用WSAAsyncSelect處理socket的方法。本文的主要目標,是建立一個帶介面的回聲服務端,接收並返回客戶端傳過來的字串,並在介面上顯示該字串。為此,我們將採用MFC的程式設計環境,建立如下的對話方塊程式:
二、WSAAsyncSelect函式
WSAAsyncSelect也是windows下一種非同步的select,它可以註冊IO事件,當發生註冊的IO事件時,它會發送一個我們自定義的訊息給我們的視窗,而我們在視窗的訊息處理函式中就可以處理這些訊息了。它的原型如下:
int WSAAsyncSelect(
__in SOCKET s,
__in HWND hWnd,
__in unsigned int wMsg,
__in long lEvent
);
s —— 用於監視的socket。
hWnd —— 用來接收socket訊息的視窗。
wMsg —— 是我們自定義的訊息,一般情況下使用“WM_USER+ 數字”的形式進行定義。
lEvent —— 進行監視的IO事件,包含如下幾種:
FD_READ:套接字可讀通知。
FD_WRITE:可寫通知。
FD_ACCEPT:伺服器接收連線的通知。
FD_CONNECT:有客戶連線通知。
FD_OOB:外帶資料到達通知。
FD_CLOSE:套接字關閉通知。
FD_QOS:服務質量發生變化通知。
FD_GROUP_QOS:組服務質量發生變化通知。
FD_ROUTING_INTERFACE_CHANGE:與路由器介面發生變化的通知。
FD_ADDRESS_LIST_CHANGE:本地地址列表發生變化的通知。
返回值 —— 正常情況下返回0,出現錯誤時返回錯誤碼。
我們知道Windows系統中訊息都會攜帶兩個引數wParam和lParam,我們在進行視窗的訊息處理時往往會利用這兩個引數。WSAAsyncSelect傳送的socket訊息也不例外,它的wParam引數攜帶的是發生IO事件的socket。而lParam低位元組表明已發生的事件。高位元組包含錯誤程式碼。我們可以使用WSAGETSElECTERROR巨集來讀取lParam的高位元組獲取錯誤碼,使用WSAGETSELECTEVENT巨集讀取lParam的低位元組來獲取發生的事件型別。
三、程式設計步驟
3.1 自定義訊息
我們先自定義一個socket訊息以用WSAAsyncSelect傳送:
#define WM_SOCKET WM_USER+1
3.2 註冊服務端的socket
我們先經過一般步驟建立服務端的socket,並然後用WSAAsyncSelect進行註冊:
WSAStartup(MAKEWORD(2,2),&m_wsaData);
m_servSock=socket(AF_INET,SOCK_STREAM,0);
memset(&m_servAddr,0,sizeof(m_servAddr));
m_servAddr.sin_family=AF_INET;
m_servAddr.sin_addr.s_addr=htonl(INADDR_ANY);
m_servAddr.sin_port=htons(atoi("8888"));
bind(m_servSock,(SOCKADDR*)&m_servAddr,sizeof(m_servAddr));
listen(m_servSock,5);
WSAAsyncSelect(m_servSock,this->m_hWnd,WM_SOCKET,FD_ACCEPT|FD_READ);
最後一句程式碼中,我們使用WSAAsyncSelect註冊了服務端的socketm_servSock,WSAAsyncSelect的第二個引數填寫了我們視窗的m_hWnd值,第三個引數是我們自定義的訊息,而第四個引數填寫的是註冊的IO事件,分別表示接受連結和有資料可讀。註冊完成之後,一旦有新的客戶端連線,系統就會發送一個WM_SOCKET訊息給我們的視窗。
3.3 處理socket訊息
為了能夠處理socket訊息,我們先引入視窗的訊息處理函式,從類嚮導中新增虛擬函式OnWndMsg,在OnWndMsg中我們進行socket訊息的處理:
BOOL CWSAAsyncSelectServDlg::OnWndMsg(UINT message,WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
switch(message)
{
case WM_SOCKET:
{
SOCKETsock = (SOCKET) wParam;
if(m_servSock == sock)
{
//獲?取¨?
m_clntAddrSz=sizeof(m_clntAddr);
m_clntSock=accept(m_servSock,(SOCKADDR*)&m_clntAddr,&m_clntAddrSz);
WSAAsyncSelect(m_clntSock,this->m_hWnd,WM_SOCKET,FD_READ);
//將?m_clntSock和¨ªm_clntAddr存ä?到Ì?映®3射¦?中D
m_sockMap.SetAt(m_clntSock,m_clntAddr);
PrintClientConnectMsg();
}
else
{
m_strLen= recv(sock,buf,BUF_SIZE - 1,0);
send(sock,buf,m_strLen,0);
buf[m_strLen]=0;
PrintClientSendMsg(sock);
}
}
break;
default:
break;
}
return CDialogEx::OnWndMsg(message, wParam, lParam,pResult);
}
從上述函式的WM_SOCKETswitch分支可以看到,我們通過wParam獲取到了發生IO事件的socket,如果有需要還可以通過lParam獲取到錯誤碼或者事件型別。獲取到socket之後,先判斷socket是不是服務端的m_servSock。如果是,表明有新的客戶端連結,接收連線並列印客戶端資訊;如果不是則是由客戶端傳來了資料,呼叫recv接收資料並send給客戶端,最後列印資料。
下面是用來列印客戶端資訊和客戶端資料的兩個函式:
void CWSAAsyncSelectServDlg::PrintClientConnectMsg(void)
{
CString str;
CTimelocTime=CTime::GetCurrentTime(); //獲?取¨?當Ì¡À前¡ã時º¡À間?
CStringstrTime=locTime.Format("%Y-%m-%d%H:%M:%S");//將?當Ì¡À前¡ã時º¡À間?轉Áa換?成¨¦CString類¤¨¤型¨ª
str.Format("%s Client %s:%d Connectted",strTime,inet_ntoa(m_clntAddr.sin_addr),m_clntAddr.sin_port);
this->m_list.AddString(str);
}
void CWSAAsyncSelectServDlg::PrintClientSendMsg(SOCKET sock)
{
CString str;
m_clntAddr=m_sockMap[sock];
CTimelocTime=CTime::GetCurrentTime();
CStringstrTime=locTime.Format("%Y-%m-%d%H:%M:%S");//將?當Ì¡À前¡ã時º¡À間?轉Áa換?成¨¦CString類¤¨¤型¨ª
str.Format("%s Client %s:%d say:%s",strTime,inet_ntoa(m_clntAddr.sin_addr),m_clntAddr.sin_port,buf);
this->m_list.AddString(str);
}
執行程式,效果如下,服務端不單返回了客戶端傳過來的資訊,還對資訊進行了列印。
客戶端1:
客戶端2:
服務端:
Github位置:https://github.com/HymanLiuTS/NetDevelopment克隆本專案:git clone git@github.com:HymanLiuTS/NetDevelopment.git獲取本文原始碼:
git checkout NL53
相關推薦
網路程式設計(53)—— Windows下使用WSAAsyncSelect實現視窗處理socket訊息
一、引言 上一文中我們介紹了使用WSAEventSelect實現非同步通知IO的方法,本文我們主要討論下使用WSAAsyncSelect處理socket的方法。本文的主要目標,是建立一個帶介面的回聲服務端,接收並返回客戶端傳過來的字串,並在介面上顯示該字串。為
網路程式設計(55)—— Windows下使用WSASocket基於Completion Routine進行IO重疊
一、引言 上一文中我們介紹了使用基於事件進行IO重疊的方法,本文主要介紹另外一種,基於回撥函式void CALLBACK CompletionRoutine(DWORD dwError,DWORDszRecvBytes,LPWSAOVERLAPPED lpO
網路程式設計(52)—— Windows下使用WSAEventSelect實現非同步通知IO
一、同步IO和非同步IO 同步IO是指發生IO事件的時間點和相關函式返回的時間點一致。如使用send函式傳送資料時,所有的資料傳送到輸出緩衝區後,send函式才會返回,這種IO方式就是同步IO。非同步IO指函式先於IO事件返回。還是以send函式為例,呼叫s
網路程式設計(46)—— windows核心物件的兩種狀態
一、 什麼是核心物件? 我們知道程序、執行緒、檔案、互斥、訊號量這些都是作業系統級別的資源。我們在使用這些資源時,實際上都是由作業系統進行建立和管理的。作業系統為了管理這些資 源,會在其內部建立一個數據塊,也可以理解為一個結構體物件。這個資料塊就是核心物件。
遊戲網路程式設計(三)——WebSocket入門及實現自己的WebSocket協議
(一)WebSocket簡介 短連線:在傳統的Http協議中,客戶端和伺服器端的通訊方式是短連線的方式,也就是伺服器端並不會保持一個和客戶端的連線,在訊息傳送後,會斷開這個連線,客戶端下次通訊時,必須再建立和伺服器的新連線,這就是短連線。在短連結的情況下,客戶
Socket網路程式設計(1) ———— 基於TCP協議的客戶-伺服器socket例項
Socket網路程式設計(1) ———— 基於TCP協議的客戶-伺服器socket例項 1、TCP網路程式設計架構 2、程式碼段 伺服器: #include <stdio.h> #include <stdlib.h&
c++ 網路程式設計(九)TCP/IP LINUX/windows下 多執行緒超詳細教程 以及 多執行緒實現服務端
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <process.h> #include <winsock2.h> #include <win
c++ 網路程式設計(九)TCP/IP LINUX/windows下 多執行緒超詳細教程 以及 多執行緒實現服務端
原文作者:aircraft 原文連結:https://www.cnblogs.com/DOMLX/p/9661012.html 先講Linux下(windows下在後面可以直接跳到後面看): 一.執行緒基本概念 前面我們講過多程序伺服器,但我們知道它開銷很大
Windows網路程式設計(九):訊息選擇模型
概述 之前介紹過,系統提供了幾種網路模型用於非同步的網路互動,訊息選擇模型就是其中一種。 這種模型的使用需要在呼叫完socket()函式以後呼叫WSAAsyncSelect(),這個函式的宣告如下: int WSAAsyncSelect(SOCKET s,HWND h
Windows網路程式設計(八):非阻塞模式(非同步模式)
前面幾篇文章介紹的無論是TCP通訊還是UDP通訊都是阻塞式的,它們在執行recv或recvfrom時會線上程中等待,直到接收到資訊為止,所以在應用的時候一般都需要開闢子執行緒,在子執行緒裡專門做這類事情,不然它會影響主執行緒的執行。 系統提供三種網路模型
Windows網路程式設計(七):原始套接字開發
在呼叫socket()函式時,如果將第二個引數填為SOCK_RAW,代表建立的是原始套接字型別,第三個引數可以選擇IPPROTO_ICMP、IPPROTO_TCP、IPPROTO和IPPROTO_RAW。 #include <winsock2.h> #pragma co
Windows網路程式設計(六):IP Helper
IP Helper是Windows系統與IP配置和管理的重要介面,通過IP Helper 可以獲得很多跟網路配置相關的資訊。比如說本機IP、閘道器設定、網絡卡數量和連線資訊。 #include <windows.h> #include "iphlpapi.h" /* 全域
Windows網路程式設計(五):多執行緒訊息處理
對於服務端來說,呼叫accept()函式同意客戶端連線的請求後,需要處理完與這個客戶端的通訊後回到accept()繼續等待下一個客戶端的連線,如果一個客戶端請求連線時服務端並沒有在accept()處等待,客戶端是無法成功連上服務端的,因此併發客戶端連線的服務端必然是多執行緒的。 服務
Windows網路程式設計(四):建立UDP連線和收發訊息
UDP訊息的傳送和接收需要UDP連線,所以,上面的TCP連線已經不適用了,具體的區別主要有: 建立Socket時引數不同建立服務端時不需要listen和accept操作建立客戶端時不需要connect操作伺服器需要bind操作,客戶端不需要。 傳送和接收UDP訊息要用到sendt
Windows網路程式設計(三):建立TCP連線和收發訊息
先看服務端: // ConsoleApplication3.cpp : 定義控制檯應用程式的入口點。 // #include "stdafx.h" #define _WINSOCK_DEPRECATED_NO_WARNINGS //這個宣告要在stdafx.h的後面,但要
Windows網路程式設計(二):Socket簡介
Socket簡介 Socket被稱為套接字,描述了IP和埠等資訊,是一個通訊鏈的控制代碼。 微軟專門開發了一套支援多種網路協議的網路程式設計介面,叫做Winsock,Winsock是Windos SDK的一部分,全稱Windows Sockets API。它對多種協議做了封裝,S
Windows網路程式設計(一):TCP/IP協議
概述 這個協議是一個四層協議: 應用層,主要協議有HTTP、FTP等 傳輸層,主要協議有TCP、UDP等 網路層,主要協議有IP等 鏈路層,主要協議有ICMP等 下層中的協議總是為上層中的協議服務的,比如說應用層的HTTP、FTP協議都是基於T
從零開始學習音視訊程式設計技術(35) windows下編譯並除錯ffmpeg
前面介紹了Linux下編譯ffmpeg的方法,考慮到大部分時候測試ffmpeg功能都是使用的windows系統(至少我是這樣的),因此將戰場重新轉移到windows上。 前面寫了那麼多的程式碼,但都只是簡單的呼叫了ffmpeg的API,並不知道他內部是如何實現的。如果可
(一)Windows下安裝RabbitMQ服務
百度網盤 http lang gin 配置 ble localhost 語言 load 一:安裝RabbitMQ需要先安裝Erlang語言開發包,百度網盤地址:http://pan.baidu.com/s/1jH8S2u6。直接下載地址:http://erlang.org/
python學習-網路程式設計(一)
udp的接收和傳送資料程式碼: udp的傳送資料程式碼如下: import socket def main(): #建立套接字 udp_socket = socket.socket(socket.AF_I