在學校淺淺地學習了計網這門課,更多地是關注路由算法這些等等。沒怎么接觸網絡編程這一塊。
最近找到一個實習,本來是要學習IOCP模型的。但是我連基礎的收發消息都沒有實現過。因此在一番搜索學習后個人實現了簡易的windows平台下的阻塞式雙線程服務器,當然了也實現了客戶端。
這就將代碼貼上來給大家參考,主要是發現網上的代碼大多都有點冗雜。所以將個人認為比較簡潔的代碼展示出來。
服務器代碼:
//simpleServer.cpp #include<WinSock2.h> #include<Windows.h> #include<process.h> #include<iostream> #pragma comment (lib, "ws2_32.lib") using namespace std; typedef struct myPara //我設這個結構體只是為了方便傳更多參數到子線程以便debug { SOCKET ClientSocket; sockaddr_in clntAddr; int id; }MyPara; DWORD WINAPI MyThreadPro(const LPVOID param)//子線程執行函數 { MyPara *temp = (MyPara*) param; int my_id = temp->id; cout << my_id << "線程:測試開始, 等待客戶端發送數據。 id地址:" << &(temp->id) << " 客戶端端口號:" << ntohs(temp->clntAddr.sin_port) <<endl; //從客戶端接受數據 char szBuffer[MAXBYTE] = {0}; recv(temp->ClientSocket,szBuffer,MAXBYTE,NULL); cout << my_id << "線程:從客戶端接受到:" << szBuffer << " temp->id:" << temp->id << " 客戶端端口號:" << ntohs(temp->clntAddr.sin_port) <<endl; //向客戶端發送數據 char *str = "你好我是服務器"; send(temp->ClientSocket, str, strlen(str)+sizeof(char), NULL); cout << my_id << "線程:成功向客戶端發送數據" << " temp->id:" << temp->id << " 客戶端端口號:" << ntohs(temp->clntAddr.sin_port)<< endl; return 0; } int main() { WSADATA wsaData;//初始化dll WSAStartup(MAKEWORD(2,2), &wsaData); //創建套接字 SOCKET servSock = socket(PF_INET, SOCK_STREAM, 0); //設置各種條件然后和套接字綁定在一起 sockaddr_in sockAddr; memset(&sockAddr,0,sizeof(sockAddr)); sockAddr.sin_family = PF_INET; sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); sockAddr.sin_port = htons(1234); bind(servSock, (SOCKADDR *)&sockAddr, sizeof(SOCKADDR)); //獲得線程的句柄 HANDLE hThread[2]; listen(servSock, 20); for(int i = 0; i < 2; i ++) { MyPara *temp = new MyPara; sockaddr_in clntAddr; int nSize = sizeof(SOCKADDR); SOCKET clntSock = accept(servSock, (SOCKADDR *)&clntAddr, &nSize); temp->ClientSocket = clntSock; temp->id = i+1; temp->clntAddr = clntAddr; cout << temp << endl; hThread[i] = CreateThread(NULL,0,&MyThreadPro,temp,0,NULL); } WaitForMultipleObjects(2, hThread, TRUE, INFINITE); //關閉套接字 closesocket(servSock); cout << "線程全部執行完畢" << endl; system("pause"); //終止 DLL 的使用 WSACleanup(); return 0; }
客戶端代碼:
#include <iostream> #include <WinSock2.h> #pragma comment(lib, "ws2_32.lib") //加載 ws2_32.dll using namespace std; int main(){ //初始化DLL WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); //創建套接字 SOCKET sock = socket(PF_INET, SOCK_STREAM, 0); //向服務器發起請求 sockaddr_in sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); //每個字節都用0填充 sockAddr.sin_family = PF_INET; sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); sockAddr.sin_port = htons(1234); connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR)); cout << "測試開始" << endl; system("pause"); //向服務器發送數據 char *str = new char[100]; cout << "請輸入發送內容:" << endl; cin >> str; send(sock, str, strlen(str)+sizeof(char), NULL); cout << "成功向服務器發送數據" << endl; system("pause"); //接收服務器傳回的數據 char szBuffer[MAXBYTE] = {0}; recv(sock, szBuffer, MAXBYTE, NULL); //輸出接收到的數據 //printf("Message form server: %s\n", szBuffer); cout << "Message form server: " << szBuffer << endl; //關閉套接字 closesocket(sock); //終止使用 DLL WSACleanup(); system("pause"); return 0; }
客戶端代碼比服務器代碼簡單很多,因為少了綁定套接字到串口等等步驟。先運行服務器,然后在運行兩個客戶端(同一份exe文件)。具體整個流程我就不解釋了,相信來到這里的人都是了解了整個流程的。然后強調一點是這份代碼得在VS的環境下跑,我在dev無論怎么設置連接庫等等都不成功。
鄙人只是初出茅廬的菜鳥,如有不足,多多見諒。
