// OneServerMain.cpp #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <vector> #include <iterator> #include <algorithm> #include <Winsock2.h> #include <Windows.h> using namespace std; HANDLE bufferMutex; // 令其能互斥成功正常通訊的信號量句柄 SOCKET sockConn; // 客戶端的套接字 vector <SOCKET> clientSocketGroup; int main() { // 加載socket動態連接庫(dll) WORD wVersionRequested; WSADATA wsaData; // 這結構是用於接收Wjndows Socket的結構信息的 wVersionRequested = MAKEWORD( 2, 2 ); // 請求2.2版本的WinSock庫 int err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { return -1; // 返回值爲零的時候是表示成功申請WSAStartup } if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { // 檢測是否2.2版本的socket庫 WSACleanup( ); return -1; } // 建立socket操做,創建流式套接字,返回套接字號sockSrv SOCKET sockSrv = socket(AF_INET, SOCK_STREAM, 0); // 套接字sockSrv與本地地址相連 SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY); // 將INADDR_ANY轉換爲網絡字節序,調用 htonl(long型)或htons(整型) addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(6000); if(SOCKET_ERROR == bind(sockSrv, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR))){ // 第二參數要強制類型轉換 return -1; } // 將套接字設置爲監聽模式(鏈接請求), listen()通知TCP服務器準備好接收鏈接 listen(sockSrv, 20); cout << "服務器已成功就緒,若服務器想發送信息給客戶端,可直接輸入內容後按回車.\n"; // accept(),接收鏈接,等待客戶端鏈接 bufferMutex = CreateSemaphore(NULL, 1, 1, NULL); DWORD WINAPI SendMessageThread(LPVOID IpParameter); DWORD WINAPI ReceiveMessageThread(LPVOID IpParameter); HANDLE sendThread = CreateThread(NULL, 0, SendMessageThread, NULL, 0, NULL); while(true){ // 不斷等待客戶端請求的到來 sockConn = accept(sockSrv, NULL, NULL); if (SOCKET_ERROR != sockConn){ clientSocketGroup.push_back(sockConn); } HANDLE receiveThread = CreateThread(NULL, 0, ReceiveMessageThread, (LPVOID)sockConn, 0, NULL); WaitForSingleObject(bufferMutex, INFINITE); // P(資源未被佔用) if(NULL == receiveThread) { printf("\nCreatThread AnswerThread() failed.\n"); } else{ printf("\nCreate Receive Client Thread OK.\n"); } ReleaseSemaphore(bufferMutex, 1, NULL); // V(資源佔用完畢) } WaitForSingleObject(sendThread, INFINITE); // 等待線程結束 CloseHandle(sendThread); CloseHandle(bufferMutex); WSACleanup(); // 終止對套接字庫的使用 printf("\n"); system("pause"); return 0; } DWORD WINAPI SendMessageThread(LPVOID IpParameter) { while(1){ string talk; getline(cin, talk); WaitForSingleObject(bufferMutex, INFINITE); // P(資源未被佔用) /* if("quit" == talk){ ReleaseSemaphore(bufferMutex, 1, NULL); // V(資源佔用完畢) return 0; } else*/ { talk.append("\n"); } printf("I Say:(\"quit\"to exit):"); cout << talk; for(int i = 0; i < clientSocketGroup.size(); ++i){ // send(clientSocketGroup[i], talk.c_str(), talk.size(), 0); // 發送信息 send(clientSocketGroup[i], talk.c_str(), 200, 0); // 發送信息 } ReleaseSemaphore(bufferMutex, 1, NULL); // V(資源佔用完畢) } return 0; } DWORD WINAPI ReceiveMessageThread(LPVOID IpParameter) { SOCKET ClientSocket=(SOCKET)(LPVOID)IpParameter; while(1){ char recvBuf[300]; recv(ClientSocket, recvBuf, 200, 0); WaitForSingleObject(bufferMutex, INFINITE); // P(資源未被佔用) if (recvBuf[0] == 'q' && recvBuf[1] == 'u' && recvBuf[2] == 'i' && recvBuf[3] == 't' && recvBuf[4] == '\0'){ vector<SOCKET>::iterator result = find(clientSocketGroup.begin(), clientSocketGroup.end(), ClientSocket); clientSocketGroup.erase(result); closesocket(ClientSocket); ReleaseSemaphore(bufferMutex, 1, NULL); // V(資源佔用完畢) printf("\nAttention: A Client has leave...\n", 200, 0); break; } printf("%s Says: %s\n", "One Client", recvBuf); // 接收信息 ReleaseSemaphore(bufferMutex, 1, NULL); // V(資源佔用完畢) } return 0; }
// MulClientMain.cpp #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <winsock2.h> #include <Windows.h> using namespace std; SOCKET sockClient; // 鏈接成功後的套接字 HANDLE bufferMutex; // 令其能互斥成功正常通訊的信號量句柄 int main() { // 加載socket動態連接庫(dll) WORD wVersionRequested; WSADATA wsaData; // 這結構是用於接收Wjndows Socket的結構信息的 wVersionRequested = MAKEWORD( 2, 2 ); // 請求2.2版本的WinSock庫 int err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { // 返回值爲零的時候是表示成功申請WSAStartup return -1; } if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { // 檢查版本號是否正確 WSACleanup( ); return -1; } // 建立socket操做,創建流式套接字,返回套接字號sockClient sockClient = socket(AF_INET, SOCK_STREAM, 0); if(sockClient == INVALID_SOCKET) { printf("Error at socket():%ld\n", WSAGetLastError()); WSACleanup(); return -1; } // 將套接字sockClient與遠程主機相連 // int connect( SOCKET s, const struct sockaddr* name, int namelen); // 第一個參數:須要進行鏈接操做的套接字 // 第二個參數:設定所須要鏈接的地址信息 // 第三個參數:地址的長度 SOCKADDR_IN addrSrv; addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // 本地迴路地址是127.0.0.1; addrSrv.sin_family = AF_INET; addrSrv.sin_port = htons(6000); connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); cout << "本客戶端已準備就緒,用戶可直接輸入文字向服務器反饋信息。\n"; // send(sockClient, "\nAttention: A Client has enter...\n", strlen("Attention: A Client has enter...\n")+1, 0); send(sockClient, "\nAttention: A Client has enter...\n", 200, 0); bufferMutex = CreateSemaphore(NULL, 1, 1, NULL); DWORD WINAPI SendMessageThread(LPVOID IpParameter); DWORD WINAPI ReceiveMessageThread(LPVOID IpParameter); HANDLE sendThread = CreateThread(NULL, 0, SendMessageThread, NULL, 0, NULL); HANDLE receiveThread = CreateThread(NULL, 0, ReceiveMessageThread, NULL, 0, NULL); WaitForSingleObject(sendThread, INFINITE); // 等待線程結束 closesocket(sockClient); CloseHandle(sendThread); CloseHandle(receiveThread); CloseHandle(bufferMutex); WSACleanup(); // 終止對套接字庫的使用 printf("End linking...\n"); printf("\n"); system("pause"); return 0; } DWORD WINAPI SendMessageThread(LPVOID IpParameter) { while(1){ string talk; getline(cin, talk); WaitForSingleObject(bufferMutex, INFINITE); // P(資源未被佔用) if("quit" == talk){ talk.push_back('\0'); // send(sockClient, talk.c_str(), talk.size(), 0); send(sockClient, talk.c_str(), 200, 0); break; } else{ talk.append("\n"); } printf("\nI Say:(\"quit\"to exit):"); cout << talk; // send(sockClient, talk.c_str(), talk.size(), 0); // 發送信息 send(sockClient, talk.c_str(), 200, 0); // 發送信息 ReleaseSemaphore(bufferMutex, 1, NULL); // V(資源佔用完畢) } return 0; } DWORD WINAPI ReceiveMessageThread(LPVOID IpParameter) { while(1){ char recvBuf[300]; recv(sockClient, recvBuf, 200, 0); WaitForSingleObject(bufferMutex, INFINITE); // P(資源未被佔用) printf("%s Says: %s\n", "Server", recvBuf); // 接收信息 ReleaseSemaphore(bufferMutex, 1, NULL); // V(資源佔用完畢) } return 0; }