一、引言 Windows 95作為微機的操作系統,已經完全融入了網絡與通信功能,不僅可以建立純Windows 95環境下的“對等網絡”,而且支持多種協議,如TCP/IP、IPX/SPX、NETBUI等。在TCP/IP協議組中,TPC是一種面向連接的協義,為用戶提供可靠的、全雙工的字節流服務,具有確認、流控制、多路復用和同步等功能,適于數據傳輸。UDP協議則是無連接的,每個分組都攜帶完整的目的地址,各分組在系統中獨立傳送。它不能保證分組的先后順序,不進行分組出錯的恢復與重傳,因此不保證傳輸的可靠性,但是,它提供高傳輸效率的數據報服務,適于實時的語音、圖像傳輸、廣播消息等網絡傳輸。 Winsock接口為進程間通信提供了一種新的手段,它不但能用于同一機器中的進程之間通信,而且支持網絡通信功能。隨著Windows 95的推出。Winsock已經被正式集成到了Windows系統中,同時包括了16位和32位的編程接口。而Winsock的開發工具也可以在Borland C++4.0、Visual C++2.0這些C編譯器中找到,主要由一個名為winsock.h的頭文件和動態連接庫winsock.dll或wsodk32.dll組成,這兩種動態連接庫分別用于Win16和Win32的應用程序。 本文針對話音的全雙工傳輸要求,采用UDP協議實現了實時網絡通信。使用VisualC++2.0編譯環境,其動態連接庫名為wsock32.dll。 二、主要函數的使用要點 通過建立雙套接字,可以很方便地實現全雙工網絡通信。 1.套接字建立函數: SOCKET socket(int family,int type,int protocol) 對于UDP協議,寫為: SOCKRET s; s=socket(AF_INET,SOCK_DGRAM,0); 或s=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP) 為了建立兩個套接字,必須實現地址的重復綁定,即,當一個套接字已經綁定到某本地地址后,為了讓另一個套接字重復使用該地址,必須為調用bind()函數綁定第二個套接字之前,通過函數setsockopt()為該套接字設置SO_REUSEADDR套接字選項。通過函數getsockopt()可獲得套接字選項設置狀態。需要注意的是,兩個套接字所對應的端口號不能相同。 此外,還涉及到套接字緩沖區的設置問題,按規定,每個區的設置范圍是:不小于512個字節,大大于8k字節,根據需要,文中選用了4k字節。
2.套接字綁定函數 int bind(SOCKET s,struct sockaddr_in*name,int namelen) s是剛才創建好的套接字,name指向描述通訊對象的結構體的指針,namelen是該結構體的長度。該結構體中的分量包括:IP地址(對應name.sin_addr.s_addr)、端口號(name.sin_port)、地址類型(name.sin_family,一般都賦成AF_INET,表示是internet地址)。 (1)IP地址的填寫方法:在全雙工通信中,要把用戶名對應的點分表示法地址轉換成32位長整數格式的IP地址,使用inet_addr()函數。 (2)端口號是用于表示同一臺計算機不同的進程(應用程序),其分配方法有兩種:1)進程可以讓系統為套接字自動分配一端口號,只要在調用bind前將端口號指定為0即可。由系統自動分配的端口號位于1024~5000之間,而1~1023之間的任一TCP或UDP端口都是保留的,系統不允許任一進程使用保留端口,除非其有效用戶ID是零(超級用戶)。 (2)進程可為套接字指定一特定端口。這對于需要給套接字分配一眾所端口的服務器是很有用的。指定范圍為1024和65536之間∩任意指定。 在本程序中,對兩個套接字的端口號規定為2000和2001,前者對應發送套接字,后者對應接收套接字。 端口號要從一個16位無符號數(u_short類型數)從主機字節順序轉換成網絡字節順序,使用 htons()函數。 根據以上兩個函數,可以給出雙套接字建立與綁定的程序片斷; //設置有關的全局變量 SOCKET sr,ss; HPSTR sockBufferS,sockBufferR; HANDLE hSendData,hReceiveData; DWROD dwDataSize=1024*4; struct sockaddr_in therel.there2; #DEFINE LOCAL_HOST_ADDR 200.200.200.201 #DEFINE REMOTE_HOST-ADDR 200.200.200.202 #DEFINE LOCAL_HOST_PORT 2000 #DEFINE LOCAL_HOST_PORT 2001 //套接字建立函數 BOOL make_skt(HWND hwnd) {
struct sockaddr_in here,here1; ss=socket(AF_INET,SOCK_DGRAM,0); sr=socket(AF_INET,SOCK_DGRAM,0); if((ss==INVALID_SOCKET)||(sr==INVALID_SOCKET)) {
MessageBox(hwnd,“套接字建立失敗!”,“”,MB_OK); return(FALSE);
} here.sin_family=AF_INET; here.sin_addr.s_addr=inet_addr(LOCAL_HOST_ADDR); here.sin_port=htons(LICAL_HOST_PORT); //another socket herel.sin_family=AF_INET; herel.sin_addr.s_addr(LOCAL_HOST_ADDR); herel.sin_port=htons(LOCAL_HOST_PORT1); SocketBuffer();//套接字緩沖區的鎖定設置 setsockopt(ss,SOL_SOCKET,SO_SNDBUF,(char FAR*)sockBufferS,dwDataSize); if(bind(ss,(LPSOCKADDR)&here,sizeof(here))) {
MessageBox(hwnd,“發送套接字綁定失敗!”,“”,MB_OK); return(FALSE);
} setsockopt(sr SQL_SOCKET,SO_RCVBUF|SO_REUSEADDR,(char FAR*) sockBufferR,dwDataSize); if(bind(sr,(LPSOCKADDR)&here1,sizeof(here1))) {
MessageBox(hwnd,“接收套接字綁定失敗!”,“”,MB_OK); return(FALSE);
} return(TRUE);
} //套接字緩沖區設置 void sockBuffer(void) {
hSendData=GlobalAlloc(GMEM_MOVEABLE|GMEM_SHARE,dwDataSize); if(!hSendData) {
MessageBox(hwnd,“發送套接字緩沖區定位失敗!”,NULL, MB_OK|MB_ICONEXCLAMATION); return;
} if((sockBufferS=GlobalLock(hSendData)==NULL) {
MessageBox(hwnd,“發送套接字緩沖區鎖定失敗!”,NULL, MB_OK|MB_ICONEXCLAMATION); GlobalFree(hRecordData[0]; return;
} hReceiveData=globalAlloc(GMEM_MOVEABLE|GMEM_SHARE,dwDataSize); if(!hReceiveData) {
MessageBox(hwnd,"“接收套接字緩沖區定位敗!”,NULL MB_OK|MB_ICONEXCLAMATION); return;
} if((sockBufferT=Globallock(hReceiveData))=NULL) MessageBox(hwnd,"發送套接字緩沖區鎖定失敗!”,NULL, MB_OK|MB_ICONEXCLAMATION); GlobalFree(hRecordData[0]); return;
}
[1] [2] 下一頁
|