摘要:Internet在我國日益普及,用戶對網絡應用的需求也不斷增加,網絡狀況瞬息萬變,如何開發高效的Windows網絡應用程序對網絡應用程序開發人員來說相當重要。文中對Windows Socket、異步選擇機制進行了簡要的介紹,根據網絡編程的原理詳細介紹了在VC中基于異步選擇機制的局域網通信的實現。該方法具有實時性、高效性的特點,可被廣泛應用于C/S結構的軟件中。
關鍵詞:Windows Socket;TCP/IP;阻塞;非阻塞;異步選擇機制
中圖分類號:TP393文獻標識碼:A文章編號:1009-3044(2008)09-11598-02
The Implementation of LAN Communication Based on Asynchronous Selection Mechanism
YANG Xiao-yan, BAI Ya-xiu
(Ankang University, Ankang 725000, China)
Abstract: Internet is increasingly universal in our country, customer's needs to network application also increase continuously. For the network condition's fast changing, to network application procedure development personnel, it is very important to develop the highly effective windows network application procedure. The article introduces Windows Socket, Asynchronous Selection Mechanism briefly and the implementation of LAN communication based on the mechanism according to the basic principle of the network correspondence with VC in dail.The method has characteristics of real time and high efficiency, and may be widely applied in C/S structure softwares.
Key words: Windows Socket; TCP/IP; Blocking; Non-blocking; Asynchronous Selection Mechanism
1 引言
Internet在我國日益普及,用戶對網絡應用的需求也不斷增長,提高網絡程序的效率就顯得相當重要。網絡由一系列協議組成,TCP/IP協議是當今異種機互聯的工業標準,它支持不同廠家、不同操作系統的計算機之間的通信。TCP/IP協議族的分層結構中的傳輸層為相互通信的主機提供了端到端的通信能力。其中,TCP協議向應用層提供可靠的數據連接,它保證進程間數據傳輸的正確、有序和不重復。UDP協議僅僅為應用層提供數據報的分組發送服務,數據傳輸的可靠性只能通過應用層來保證。TCP和UDP的主要差別在于可靠性,TCP高度可用,需要大量功能開銷,而UDP是簡單、高效。由于是在局域網中實現通信,為了達到簡單、實時、高效的目的,在介紹Windwins Socket,異步選擇機制,網絡通信原理等相關知識的基礎上,根據基于數據報套接字(UDP協議)的編程步驟,詳細探討了在VC中基于異步選擇機制的局域網通信的實現。
2 Windows Socket及異步選擇機制
2.1 Windows Socket
套接字(Socket)是建立在傳輸層協議(主要是TCP和UDP)上的一種套接字規范,最初是由美國加州Berkley大學提出,它定義了兩臺計算機間進行通信的規范,套接字屏蔽了底層通信軟件和具體操作系統的差異,使得任何兩臺安裝了TCP協議軟件和實現了套接字規范的計算機之間的通信成為可能。Windows Scoket是UNIX操作系統下的Bakeley Socket應用程序開發接口在Windows環境下的實現。Windows Socket規范主要有WinSock1.1和WinSock2兩個版本,它們保持了和Bekeley Socket函數的兼容性,并做出了重要擴充。這些擴充主要是增加了一些異步請求函數和對網絡事件的異步選擇機制,使之更適合Windows平臺消息驅動的特性。
2.2 異步選擇機制
Windows Socket在兩種模式下執行I/O操作,阻塞和非阻塞。在阻塞模式下,在I/O操作完成前,執行操作的Winsock函數會一直等待下去,不會立即返回程序(將控制權交還給程序)。Windows Sockets為了支持Windows消息驅動機制,使應用程序開發者能夠方便的處理網絡通信,它對網絡事件采用了基于消息的異步存取策略。Windows Sockets的異步選擇函數WSAAsyncSelect()提供了消息機制的網絡事件選擇,當使用它登記的網絡事件發生時,Windows應用程序相應的窗口函數將收到一個消息,消息中指示了發生的網絡事件,以及與事件相關的一些信息。這個函數自動設置套接字為非阻塞模式。
Int WSAAsyncSelect(SOCKET s, HWND hWnd, unsigned int wMsg)
S,標識了請求事件通知的套接字描述符。
hWnd,標識當一個網絡事件發生時,接收消息的窗口的句柄
wMsg,網絡事件發生時,窗口接收到的消息(這里指的是一個自定義的消息。)
lEvent,指定應用感興趣的網絡事件。
3 網絡通信的基本原理
網絡通信實質上是網絡中的不同主機進程之間的相互通信(可以把同機進程通信看作其中的特例)問題。與單純的同機通信相比,網絡通信需要解決以下三個問題。第一,標識網絡中的進程。在同一主機上,不同進程可以用進程標識符來標識,而在網絡通信中則是利用端口號來標識。端口是TCP和UDP與應用程序打交道的訪問點,是TCP/IP協議軟件的一部份。TCP/IP協議規定了一些標準保留端口,主要提供給服務器進程使用,用戶進程可以申請使用非保留端口,其端口的標識符在本機種具有唯一性。因此可以利用端口號作為網絡中進程本身的標識。第二,多重協議的識別。網絡中的兩個進程必須使用協議來相互通信,而網絡協議有多種,這就要求進程能夠在眾多的協議中作出選擇。原因在于不同的協議地址格式不同、工作方式不同(比如面向連接與無連接),協議端口分配是相互獨立的。綜合以上兩點,在網絡中全局地址標識一個本地進程需要一個三元組:協議,本地地址,本地端口號。而一個完整的網絡通信實例是由通信兩端的進程組成,因此需要一個五元組來標識:協議,本地地址,本地端口號,異地地址,異地端口號。這里的本地地址、異地地址是用來標識計算機的,一般是指計算機的IP地址。第三,進程之間相互作用模式,即應用程序相互作用的模式。在網絡中兩個應用程序間主要的作用模式是客戶機/服務器模式,在這種模式中客戶應用程序向服務器程序請求服務,這種方式隱含了在建立客戶機/服務器間通信時的非對稱性。表1顯示了基于數據報套接字的客戶機/服務器編程模型。

4 基于異步選擇機制的局域網通信的實現
4.1 實現思想
根據數據報套接字的客戶機/服務器編程模型,采用Windows Scoket的異步選擇機制,將服務器端和客戶端在同一個程序中實現。需要通信的計算機只要運行同樣的程序,通過輸入對方的IP地址,或主機名就可以實現相互通信。
4.2 在VC中的具體實現
4.2.1 創建基于對話框的MFC EXE工程
在應用程序類的初始化函數:InitInstance()種調用如下語句加載套接字庫進行版本協商。(采用Winsock2版本)
WSAStartup(wVersionRequested,wsaData);
if(LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
{WSACleanup();return FALSE;}
在預編譯頭文件中包含頭文件winsock2.h,并鏈接庫文件ws2_32.lib.
4.2.2 服務器端的實現
m_socket=WSASocket(AF_INET,SOCK_DGRAM,0,NULL,0,0);//創建數據報套接字
SOCKADDR_IN addrSock;//地址結構體的定義
addrSock.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
addrSock.sin_family=AF_INET;
addrSock.sin_port=htons(6000);//端口號為6000
//將套接字綁定到一個本地地址和端口上
bind(m_socket,(SOCKADDR*)addrSock,sizeof(SOCKADDR));
//采用異步選擇機制注冊網絡讀取事件
WSAAsyncSelect(m_socket,m_hWnd,UM_SOCK,FD_READ);
#define UM_SOCK WM_USER+1 //自定義消息UM_SOCK
afx_msg void OnSock(WPARAM,LPARAM);//消息響應函數原型聲明
ON_MESSAGE(UM_SOCK,OnSock)//消息映射
//接收數據(消息響應函數的實現)
OnSock(WPARAM wParam,LPARAM lParam)
{ switch(LOWORD(lParam))//判斷是否是網絡讀取事件發生了。
{case FD_READ:
if(SOCKET_ERROR==WSARecvFrom(m_socket,wsabuf,1,dwRead, dwFlag,(SOCKADDR*)addrFrom,len,NULL,NULL))
{MessageBox(\"接收數據失敗!\");return;}
str.Format(\"%s說:%s\",inet_ntoa(addrFrom.sin_addr),wsabuf.buf);
str+=\"\\r\\";
GetDlgItemText(IDC_EDIT_RECV,strTemp);
str+=strTemp;
SetDlgItemText(IDC_EDIT_RECV,str);
break;
}
}
4.2.3 客戶端(實現數據的發送)
((CIPAddressCtrl*)GetDlgItem(IDC_IPADDRESS1))->GetAddress(dwIP); //獲取服務器端的IP地址
SOCKADDR_IN addrTo;// 接收方地址結構體定義
addrTo.sin_addr.S_un.S_addr=htonl(dwIP);
addrTo.sin_family=AF_INET;
addrTo.sin_port=htons(6000);
//將數據發給服務器
if(SOCKET_ERROR==WSASendTo(m_socket,wsabuf,1,dwSend,0,
(SOCKADDR*)addrTo,sizeof(SOCKADDR),NULL,NULL))
{MessageBox(\"發送數據失敗!\");return;}
4.3.4 在應用類及對話框類的析構函數中分別終止套接字庫,關閉套接字
WSACleanup();//終止對套接字庫的使用
closesocket(m_socket);//關閉套接字,釋放與套接字相關的資源。
4.3.5 程序運行效果如圖1所示
<E:\\2008學術交流\\2008學術交流第一卷第九期\\第1次供稿 54\\2網絡通訊及安全\\yxy02.tif>

4.3.6 注意問題
編寫網絡通信程序需要特別注意的是:每一臺機器內部對變量的字節存儲順序不同,而網絡傳輸的數據是一定要統一順序的。所以對內部字節表示順序與網絡字節順序不同的機器,一定要對數據進行轉換;在一個套接字上基于消息請求網絡事件通知,可以同時請求多個網絡事件,當接收到到消息時,需要根據發生的網絡事件作相應的處理;網絡的狀況瞬息萬變,在調用函數的時候,應對函數的返回值進行判斷,以便找到出錯原因。
5 結論
在Windows平臺下程序的運行都是基于消息的,如果采用阻塞套接字,就會由于接收函數的調用而導致程序暫停運行,影響了程序運行的效率。采用異步選擇機制,接收端和發送端在同一個程序中,并且采用數據報套接字實現了局域網通信,達到了簡單、高效、實時的目的。在實現網絡通信時,除了應注意的問題外,還應了解相關的網絡協議以及程序在Windows平臺下工作的原理,根據應用的具體需求,才能實現真正高性能的網絡通信。
參考文獻:
[1] 陳明.實用網絡教程[M].北京:清華大學出版社,2006.1.
[2] 胡志坤,秦業,等.Visual C++通信工程實例精解[M].北京:機械工業出版社,2007.1
[3] 孫小剛,韓冬,等.面向軟件工程的Visual C++網絡程序開發[M].北京:清華大學出版社,2004,11.
[4] 李峰.利用流式Socket編程實現Windows與Linux的通信[J].微計算機信息,2006,22:73-75.
[5] 戴大蒙.基于非阻塞式Winsock的多線程網絡通信機制[J].計算機工程,2006,06:137-142.