?? 14.4.2 客戶端程序 ..txt
字號:
14.4.2 客戶端程序 .
在VC++開發環境中,一個工作區可以包含多個工程。下面我們在已有的TcpSrv工作區(如圖 14.7
所示)中添加客戶端工程。
添加方法是在工作區名稱上單擊鼠標右鍵,選擇【Add New Project to Workspace... >菜單命
令,這時將顯示新工程創建向導,與上面創建的服務器端程序: TCPSrv一樣,我們也創建一個
Win32 Console Apptication類型的應用程序,并調整這個新工程的目錄,將默認路徑中的最后
一級目錄: TcpSrv去掉,使新創建的這個客戶端應用程序與上面的TcpSrv工程在同一個目錄下。
本次創建的客戶端向用程序的名稱為TcpClient.并在工程創建向導的第 l步選擇An empty
project選項,以創建一個空的工程。
這時,在VC++集成開發環境中,在FileView選項卡就可以看到在TCPSrv這個工作區中有兩個工程,
如圖 14.8所示。
那么如何區分當前處于活動狀態的是哪個工程呢?這可以通過 VC++開發環境提供的
Build工具條中提供的工程名稱下拉列表來選擇當前活動工程。在VC++開發環境的初始界
面中是看不到這個工具條的,讀者可以在 VC++開發環境的工具欄空白處單擊鼠標右鍵,
將看到初始選擇的是Build MiniBar工具條,如圖 14.9所示。可以將這個選項取消,然后選中
Build選項,此時在VC++開發環境中就可以看到如圖 14.10所示的Build工具條上的工程下拉列表
了,通過這個列表,就可以很方便地切換工作區中的當前活動工程了。
同樣,為客戶端程序增加一個C++源文件: TcpClient.cpp.并添加如例14-2所示內容。 例14-2
#include <Winsock2.h>
#include <stdio.h>
void main() {
//加載套接字庫
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 1 , 1 );
err WSAStartup( wVersionRequested, &wsaData );
i f ( err ! = 0 ) {
return;
if ( LOBYTE( wsaData.wVersion ) != 1 II
HIBYTE( wsaData.wVersion ) != 1 ) {
WSACleanup( );
return;
//創建套接字
SOCKET sockClient=socket(AF_INET, SOCK_STREAM, O);
SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1") ;
addrSrv.sin_family=AF_INET;
addrSrv.sin_port=htons(6000);
//向服務器發出連接請求
connect(sockClient , (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));
//接收數據
char recvBuf[100);
recv(sockClient , recvBuf , 100 , O);
printf("%S\n" , recvBuf) ;
//發送數據
send(sockClient , "This is lisi" , strlen("This is lisi")+1, 0);
//關閉套接字
closesocket(sockClient) ;
WSACleanup();
因為在利用套接字編寫網絡應用程序時,都需要使用套接字庫提供支持,所以加載套
接字庫這部分代碼可以重用。讀者可以直接復制 TCPSrv工程中已有的這部分代碼,然后按照上
面介紹的基于 TCP(面向連接)的 socket編程的客戶端程序流程完成該程序。
①創建套接宇 (socket>。
同樣,利用 socket函數創建套接字,并且該函數的第一個參數只能用 AF_INET(或 PF_INET);
因為本例是基于 TCP的網絡應用程序,所以第二個參數是 SOCK_STREAM;第三個參數設置為 0.
讓其自動選擇一個合適的協議。
CI1向服務器發出連接請求 (connect)。
對于客戶端來說,它不需要綁定,可以直接連接服務器端。這可以通過調用 connect函數與服務
器端建立一個連接,于是首先定義一個地址結構體 (SOCKADDR_IN)變量: addrS凹,并對其成員
進行賦值,設定服務器端的 IP地址和端口。因為本例中服務器端和客戶端都是本地的,所以可
以使用一個特殊的 E地址: 127.0.0.1,這是本地回路地址,無論機器上是否有網卡,都可以使
用這個 IP地址。如果編寫的網絡程序就是在本地機器上運行的,就可以采用這個 IP地址進行一
些測試。如果編寫的程序需要在兩臺機器上進行通信,此時就應設置服務器端程序所在機器上的
IP地址。要注意. addrSrv.sin_addr.S_ un.S_addr成員需要 u_long類型的數值,因此應該使用
inet_addr函數將點分十進制表示的 IP地址轉換為 u_long類型,接著將 addrSrv的 sin_famiú
ly成員設置為 AF_INET;最后將端口成員 (addrSrv.sin_port)設定為服務器程序等待接收客戶
端連接請求的那個端口,注意,這里的端口需要與服務器端使用的端口號保持一致,而且需要使
用網絡字節順序。設置完 addSrv變量的各個成員之后,就可以調用 connect函數建立連接了。
③和服務器端進行通信( send/recv )。
當建立連接之后,就可以接收服務器端發送的數據了,本例定義一個有 100個字節的字符數組:
recvBuf.用來接收服務器發送的數據,然后調用 recv函數接收數據。之后調用 p由ltf函數將接
收到的數據打印出來,并且在打印時,在接收到的數據后面加上一個"\0"字符,即打印一個回車
符。
然后,客戶端可以調用 send函數向服務器端程序發送數據,注意,這時使用的套接字與上面 recv
函數使用的是一樣的,并且在發送時也多發送一個字節,服務器接收到數據后可以將最后一個字
節的數據設置為"\0。",表示字符串的結束。
④關閉套接字。當通信完成之后,需要調用 closesocket函數關閉套接字,釋放為此套接字分配
的資源。最后需要調用 WSACleanup函數,終止對套接字庫的使用。
同樣,客戶端程序也需要鏈接庫文件: ws2_32 .l ib。需要注意的是,這時工作區中有兩個工程,
因此在設置工程屬性時,在工程設置對話框的左邊面板中一定要選中當前要進行設置的工程。讀
者可以按照上面編寫服務器端程序時介紹的添加庫文件的方法,為 TcpClient工程添加該庫文件
的鏈接。
最后利用 Build命令生成 TCPClient程序。
這時,基于 TCP的服務器端和客戶端程序都已經生成了。注意:服務器端程序總是應先啟動。那
么我們首先運行服務器端程序,然后再運行客戶端程序,可以看到客戶端程序收到了服務器端返
回的信息: Welcome 127.0.0.1 to http://www.sunxin.org;而服務器端程序
收到了客戶端程序發送的信息 :
This is lisi。如圖 14.11所示。
圖 14. 11基于 TCP的網絡應用程序運行結果
如果這時服務器端程序和客戶端程序是在兩臺機器上運行,在客戶端收到的信息中就會顯示客戶
端程序所在機器上的 E地址。
從圖 14.11可以看到,這時客戶端程序已經退出了,但服務器端程序仍在運行。這是因為在實現
服務器程序時采用了一個死循環,當它為一個客戶端提供服務之后,服務器端仍繼續監聽下一個
客戶端的請求,所以客戶端程序可以不斷地啟動,服務器端程序都可以為它們提供服務。讀者可
以自行測試這種情況。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -