1. 程式人生 > >基於TCP的C/S模式模板(Winsock實現)

基於TCP的C/S模式模板(Winsock實現)

伺服器程式server.cpp:

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <tchar.h>
#include <locale.h>
#include <WinSock2.h>

#pragma comment(lib,"ws2_32.lib")

void ShowSystemError(DWORD dwError)
{
	HLOCAL hlocal = NULL;
	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
		NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), (TCHAR*)&hlocal, 0, NULL);
	_tprintf(_T("%s\n"), (TCHAR*)LocalLock(hlocal));
	LocalFree(hlocal);
}

struct Node
{
	SOCKET sc;
	SOCKADDR_IN addr;
	Node* next;
	Node* prev;
};

int _tmain(int argc, TCHAR* argv[])
{
	setlocale(LC_ALL, "chs");
	int nRet = 0;
	WSADATA wsadata;
	nRet = WSAStartup(MAKEWORD(2, 2), &wsadata);
	if (nRet != 0)
	{
		printf("WSAStartup呼叫失敗,錯誤資訊:");
		ShowSystemError(nRet);
		getchar();
		return -1;
	}

	SOCKET serverSocket = INVALID_SOCKET;
	serverSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (serverSocket == INVALID_SOCKET)
	{
		printf("socket呼叫失敗,錯誤資訊:");
		ShowSystemError(WSAGetLastError());
		goto END;
	}

	SOCKADDR_IN serverAddr;
	ZeroMemory(&serverAddr, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.S_un.S_addr = INADDR_ANY;
	serverAddr.sin_port = htons(8888);
	if (bind(serverSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) != 0)
	{
		printf("bind呼叫失敗,錯誤資訊:");
		ShowSystemError(WSAGetLastError());
		goto END;
	}

	if (listen(serverSocket, 5) != 0)
	{
		printf("listen呼叫失敗,錯誤資訊:");
		ShowSystemError(WSAGetLastError());
		goto END;
	}

	Node* pHead = new Node;
	pHead->prev = pHead->next = NULL;

	Node* pNewNode = new Node;
	pNewNode->sc = serverSocket;
	memcpy(&pNewNode->addr, &serverAddr, sizeof(SOCKADDR_IN));
	pNewNode->prev = pHead;
	pNewNode->next = pHead->next;
	pHead->next = pNewNode;

	FD_SET readSet;

	SOCKET clientSocket;
	SOCKADDR_IN clientAddr;
	int nAddrLen;
	Node* p;
	Node* pTemp;
	char recvBuf[1024];
	while (true)
	{
		FD_ZERO(&readSet);
		for (p = pHead->next; p != NULL; p = p->next)
			FD_SET(p->sc, &readSet);
		nRet = select(0, &readSet, NULL, NULL, NULL);
		if (nRet < 0)
		{
			printf("select呼叫失敗,錯誤資訊:");
			ShowSystemError(WSAGetLastError());
			continue;
		}
		for (p = pHead->next; p != NULL; p = p->next)
		{
			if (FD_ISSET(p->sc, &readSet))
			{
				if (p->sc == serverSocket)
				{
					clientSocket = INVALID_SOCKET;
					ZeroMemory(&clientAddr, sizeof(SOCKADDR_IN));
					nAddrLen = sizeof(SOCKADDR_IN);
					clientSocket = accept(serverSocket, (SOCKADDR*)&clientAddr, &nAddrLen);
					if (clientSocket == INVALID_SOCKET)
					{
						printf("accept呼叫失敗,錯誤資訊:");
						ShowSystemError(WSAGetLastError());
						continue;
					}
					printf("%s:%d的客戶成功連線到伺服器。\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
					pNewNode = new Node;
					pNewNode->sc = clientSocket;
					memcpy(&pNewNode->addr, &clientAddr, sizeof(SOCKADDR_IN));
					pNewNode->prev = pHead;
					pNewNode->next = pHead->next;
					pHead->next->prev = pNewNode;
					pHead->next = pNewNode;
				}
				else
				{
					ZeroMemory(recvBuf, sizeof(recvBuf));
					nRet = recv(p->sc, recvBuf, sizeof(recvBuf), 0);
					if (nRet < 0)
					{
						printf("recv呼叫失敗,錯誤資訊:");
						ShowSystemError(WSAGetLastError());
						if (closesocket(p->sc) != 0)
						{
							printf("closesocket呼叫失敗,錯誤資訊:");
							ShowSystemError(WSAGetLastError());
						}
						pTemp = p->prev;
						p->prev->next = p->next;
						p->next->prev = p->prev;
						delete p;
						p = pTemp;
					}
					else if (nRet == 0)
					{
						printf("%s:%d的客戶主動關閉連線。\n", inet_ntoa(p->addr.sin_addr), ntohs(p->addr.sin_port));
						if (closesocket(p->sc) != 0)
						{
							printf("closesocket呼叫失敗,錯誤資訊:");
							ShowSystemError(WSAGetLastError());
						}
						pTemp = p->prev;
						p->prev->next = p->next;
						p->next->prev = p->prev;
						delete p;
						p = pTemp;
					}
					else
					{
						//解析資料
						printf("%s:%d的客戶傳送:%s\n", inet_ntoa(p->addr.sin_addr), ntohs(p->addr.sin_port), recvBuf);
					}
				}
			}
		}
	}

END:
	if (serverSocket != INVALID_SOCKET)
	{
		if (closesocket(serverSocket) != 0)
		{
			printf("closesocket呼叫失敗,錯誤資訊:");
			ShowSystemError(WSAGetLastError());
		}
	}
	if (WSACleanup() != 0)
	{
		printf("WSACleanup呼叫失敗,錯誤資訊:");
		ShowSystemError(WSAGetLastError());
	}
	getchar();
	return 0;
}

客戶端程式client.cpp:

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <tchar.h>
#include <locale.h>
#include <WinSock2.h>

#pragma comment(lib,"ws2_32.lib")

void ShowSystemError(DWORD dwError)
{
	HLOCAL hlocal = NULL;
	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
		NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), (TCHAR*)&hlocal, 0, NULL);
	_tprintf(_T("%s\n"), (TCHAR*)LocalLock(hlocal));
	LocalFree(hlocal);
}

int _tmain(int argc, TCHAR* argv[])
{
	setlocale(LC_ALL, "chs");
	int nRet = 0;
	WSADATA wsadata;
	nRet = WSAStartup(MAKEWORD(2, 2), &wsadata);
	if (nRet != 0)
	{
		printf("WSAStartup呼叫失敗,錯誤資訊:");
		ShowSystemError(nRet);
		getchar();
		return -1;
	}

	SOCKET clientSocket = INVALID_SOCKET;
	clientSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (clientSocket == INVALID_SOCKET)
	{
		printf("socket呼叫失敗,錯誤資訊:");
		ShowSystemError(WSAGetLastError());
		goto END;
	}

	SOCKADDR_IN serverAddr;
	ZeroMemory(&serverAddr, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	serverAddr.sin_port = htons(8888);
	if (connect(clientSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) != 0)
	{
		printf("connect呼叫失敗,錯誤資訊:");
		ShowSystemError(WSAGetLastError());
		goto END;
	}

	printf("連線伺服器成功。\n");

	char* sendBuf = "Hello, World!";
	nRet = send(clientSocket, sendBuf, strlen(sendBuf) + 1, 0);
	if (nRet < 0)
	{
		printf("send呼叫失敗,錯誤資訊:");
		ShowSystemError(WSAGetLastError());
	}
	else
		printf("傳送成功。\n");
	getchar();

END:
	if (clientSocket != INVALID_SOCKET)
	{
		if (closesocket(clientSocket) != 0)
		{
			printf("closesocket呼叫失敗,錯誤資訊:");
			ShowSystemError(WSAGetLastError());
		}
	}
	if (WSACleanup() != 0)
	{
		printf("WSACleanup呼叫失敗,錯誤資訊:");
		ShowSystemError(WSAGetLastError());
	}
	getchar();
	return 0;
}