1. 程式人生 > >VC++ TCP網路控制檯程式

VC++ TCP網路控制檯程式

     在Windows7系統下,採用工具為VS2008,Win32控制檯應用程式,編寫一個基於TCP的Client/Server網路程式。

1、伺服器端程式碼

#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、客戶端程式碼

#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幫助文件