基於TCP的C/S模式模板(Winsock實現)
阿新 • • 發佈:2018-12-14
伺服器程式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; }