在Windows7系統下,採用工具爲VS2008,Win32控制檯應用程序,編寫一個基於TCP的Client/Server網絡程序。
1、服務器端代碼
[cpp] view plain copy
#include <WinSock2.h>
#include <stdio.h>
#define SERVERPORT 6000 //服務端口號
int main(int argc, char *argv[])
{
//加載套接字庫
WORD wVersionRequested;//用於保存WinSock庫的版本號
WSADATA wsaData;
int err;
printf("This is a Server side application!\n");
wVersionRequested = MAKEWORD(2,2);
err = WSAStartup( wVersionRequested, &wsaData);
if (err != 0)
{
printf("WSAStartup() called failed!\n");
return -1;
}
else
{
printf("WSAStartup() called successful!\n");
}
if (LOBYTE(wsaData.wVersion) != 2 ||
HIBYTE(wsaData.wVersion) != 2)
{
//若不是所請求的版本號2.2,則終止WinSock庫的使用
WSACleanup();
return -1;
}
//創建用於監聽的套接字
SOCKET sockServer = socket(AF_INET, SOCK_STREAM, 0);
if(sockServer == INVALID_SOCKET)
{
printf("socket() called failed! ,error code is: %d", WSAGetLastError());
return -1;
}
else
{
printf("socket() called successful!\n");
}
//填充服務器端套接字結構
SOCKADDR_IN addrServer;
addrServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//將主機字節順序轉換成TCP/IP網絡字節順序
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(SERVERPORT);
//將套接字綁定到一個本地地址和端口上
err = bind(sockServer, (SOCKADDR*)&addrServer, sizeof(SOCKADDR));
if (err == SOCKET_ERROR)
{
printf("bind() called failed! The error code is: %d\n", WSAGetLastError());
return -1;
}
else
{
printf("bind() called successful\n");
}
//將套接字設置爲監聽模式,準備接收客戶請求
err = listen(sockServer, 5);
if (err == SOCKET_ERROR)
{
printf("listen() called failed! The error code is: %d\n", WSAGetLastError());
return -1;
}
else
{
printf("listen() called successful!\n");
}
SOCKADDR_IN addrClient; //保存發送請求連接的客戶端的套接字信息
int len = sizeof(SOCKADDR);
while(1)
{
//等待客戶請求到來
SOCKET sockConn = accept(sockServer, (SOCKADDR*)&addrClient, &len);
if (sockConn == INVALID_SOCKET)
{
printf("accept() called falied! The error code is: %d\n", WSAGetLastError());
}
else
{
printf("The Server receive a new client connection!\n");
}
char sendBuf[100];
sprintf_s(sendBuf, 100, "Welcome %s",inet_ntoa(addrClient.sin_addr));
//發送數據
send(sockConn, sendBuf, strlen(sendBuf)+1 , 0);
char recvBuf[100];
//接收數據
recv(sockConn, recvBuf, 100, 0);
//打印接收到的數據
printf("receive data from client side [%s,%d] is: %s\n", inet_ntoa(addrClient.sin_addr), addrClient.sin_port,
recvBuf);
closesocket(sockConn); //關閉連接套接字
}
return 0;
}
2、客戶端代碼
[cpp] view plain copy
#include <WinSock2.h>
#include <stdio.h>
#define SERVERPORT 6000 //服務端口號
#pragma comment(lib, "WS2_32.lib");
int main(int argc, char *argv[])
{
//加載套接字庫
WORD wVersionRequested;
WSAData wsaData;
int err;
printf("This is a Client side application!\n");
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0 )
{
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
printf("WSAStartup() called failed!\n");
return -1;
}
else
{
printf("WSAStartup() called successful!\n");
}
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 ) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
WSACleanup( );
return -1;
}
/* The WinSock DLL is acceptable. Proceed. */
//創建套接字
SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0);
if(sockClient == INVALID_SOCKET)
{
printf("socket() called failed! ,error code is: %d", WSAGetLastError());
return -1;
}
else
{
printf("socket() called successful!\n");
}
//需要連接的服務端套接字結構信息
SOCKADDR_IN addrServer;
addrServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//設定服務器的IP地址
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(SERVERPORT);//設定服務器的端口號(使用網絡字節序)
//向服務器發出連接請求
err = connect(sockClient, (SOCKADDR*)&addrServer, sizeof(SOCKADDR));
if (err == SOCKET_ERROR)
{
printf("connect() called failed! The error code is: %d\n", WSAGetLastError());
return -1;
}
else
{
printf("connect() called successful\n");
}
//接收數據
char recvBuf[100]={0};
recv(sockClient, recvBuf, 100, 0);
printf("receive data from server side is: %s\n", recvBuf);
//發送數據
send(sockClient, "This is a client side!\n", strlen("This is a client side!\n")+1, 0);
//關閉套接字
closesocket(sockClient);
//終止套接字庫的使用
WSACleanup();
return 0;
}
另外,需要注意的是需要在服務器和客戶端都需要鏈接WinSock靜態鏈接庫Ws2_32.lib,有兩種添加方法
方法一:在工程配置屬性中添加
假如創建一個名爲TCPClient的Win32控制檯應用程序
在VC2008中添加靜態鏈接庫WS2_32.lib的方法如下:
(1)切換到TCPServer的【Solution Explorer】,選擇菜單【Project】->【TCPClient Properties】
(2)在TCPClient Properties Pages對話框中,依次選擇【Configuration Properties】->【Linker】->【Input】,在右側的【Addtional Dependencies】中添加Ws2_32.lib庫。
如下如所示:
服務器TCPServer也需要鏈接Ws2_32.lib庫,方法和客戶端TCPClient一樣。
程序結果運行如下:
先啓動服務器端程序TCPServer,結果如下:
再啓動客戶端TCPClient,客戶端結果如下:
服務器端TCPServer結果如下:
方法二:在代碼中添加
#pragma comment(lib, "WS2_32.lib");
參考資料:
1、《VC++深入詳解》 第14章網絡編程 ,孫鑫主編
2、MSDN幫助文檔