(C++伺服器學習筆記):報文多次收發轉為一次收發
報文多次收發轉為一次收發
- 包頭和資料合在一起,一次傳送一次接收。
- 資料定義,服務端和客戶端共用
enum CMD //命令列舉 { CMD_LOGIN, CMD_LOGIN_RESULT, CMD_LOGOUT, CMD_LOGOUT_RESULT, CMD_ERROR }; //DataHeader struct DataHeader //資料包頭 { short dataLength; short cmd; }; //DataPackage struct Login:public DataHeader //登入 { Login() { dataLength = sizeof(Login); cmd = CMD_LOGIN; } char UserName[32]{}; char PassWord[32]{}; }; struct LoginResult : public DataHeader //登入結果 { LoginResult() { dataLength = sizeof(LoginResult); cmd = CMD_LOGIN_RESULT; lgResult = 0; } int lgResult; }; struct LogOut :public DataHeader //退出登入 { LogOut() { dataLength = sizeof(LogOut); cmd = CMD_LOGOUT; } char UserName[32]{}; }; struct LogOutResult :public DataHeader //退出結果 { LogOutResult() { dataLength = sizeof(LogOutResult); cmd = CMD_LOGOUT_RESULT; lgOutResult = 0; } int lgOutResult; };
【服務端資料收發處理】
while (true) { DataHeader dbHeader = {}; //讀取包頭資料 int nLen = recv(sockAccpt, (char*)&dbHeader, sizeof(DataHeader), 0); if (nLen < 0) { printf("客戶端已退出,任務結束\n"); break; } switch (dbHeader.cmd) { case CMD_LOGIN: { Login login = {}; recv(sockAccpt, (char*)&login + sizeof(DataHeader) , sizeof(Login)- sizeof(DataHeader), 0); printf("收到命令:CMD_LOGIN ,資料長度: %d, UserName = %s, \ PassWord = %s \n", login.dataLength, login.UserName, login.PassWord); //忽略對使用者密碼進行判斷 LoginResult lgRet = {}; send(sockAccpt, (char*)&lgRet, sizeof(LoginResult), 0); } break; case CMD_LOGOUT: { LogOut logout = {}; recv(sockAccpt, (char*)&logout + sizeof(DataHeader), sizeof(LogOut) - sizeof(DataHeader), 0); printf("收到命令:CMD_LOGOUT ,資料長度: %d, UserName = %s, \ \n", logout.dataLength, logout.UserName ); //忽略對使用者密碼進行判斷 LogOutResult lgOutRet = {}; send(sockAccpt, (char*)&lgOutRet, sizeof(LogOutResult), 0); } break; default: dbHeader.cmd = CMD_ERROR; dbHeader.dataLength = 0; send(sockAccpt, (char*)&dbHeader, sizeof(DataHeader), 0); break; } }
【客戶端資料收發處理】
while (true) { //3.輸入請求命令 char cmdBuff[128] = {}; scanf("%s", cmdBuff); //4.處理請求 if (0 == strcmp(cmdBuff, "exit")) { printf("接收到命令exit,退出 \n"); break; } else if (0 == strcmp(cmdBuff, "login")) { Login login {}; login.cmd = CMD_LOGIN; login.dataLength = sizeof(login); strcpy(login.UserName, "喜羊羊"); strcpy(login.PassWord,"123456"); //5.向伺服器傳送請求 send(sockCli, (const char *)&login, sizeof(login), 0); //接收伺服器返回的資料 LoginResult loginRet = {}; recv(sockCli, ( char*)&loginRet, sizeof(loginRet), 0); printf("LoginResult: %d\n", loginRet.lgResult); } else if (0 == strcmp(cmdBuff, "logout")) { LogOut logout{}; logout.cmd = CMD_LOGOUT; logout.dataLength = sizeof(logout); strcpy(logout.UserName, "灰太狼"); //5.向伺服器傳送請求 send(sockCli, (const char*)&logout, sizeof(logout), 0); //接收伺服器返回的資料 LogOutResult logOutRet = {}; recv(sockCli, (char*)&logOutRet, sizeof(logOutRet), 0); printf("LogOutResult: %d\n", logOutRet.lgOutResult); } else { printf("不支援該命令,請從新輸入 \n"); } }
原始碼
【服務端原始碼】
#define WIN32_LEAN_AND_MEAN #define _WINSOCK_DEPRECATED_NO_WARNINGS #include <windows.h> #include <WinSock2.h> #include <cstdio> #pragma comment(lib,"ws2_32.lib") enum CMD //命令列舉 { CMD_LOGIN, CMD_LOGIN_RESULT, CMD_LOGOUT, CMD_LOGOUT_RESULT, CMD_ERROR }; //DataHeader struct DataHeader //資料包頭 { short dataLength; short cmd; }; //DataPackage struct Login:public DataHeader //登入 { Login() { dataLength = sizeof(Login); cmd = CMD_LOGIN; } char UserName[32]{}; char PassWord[32]{}; }; struct LoginResult : public DataHeader //登入結果 { LoginResult() { dataLength = sizeof(LoginResult); cmd = CMD_LOGIN_RESULT; lgResult = 0; } int lgResult; }; struct LogOut :public DataHeader //退出登入 { LogOut() { dataLength = sizeof(LogOut); cmd = CMD_LOGOUT; } char UserName[32]{}; }; struct LogOutResult :public DataHeader //退出結果 { LogOutResult() { dataLength = sizeof(LogOutResult); cmd = CMD_LOGOUT_RESULT; lgOutResult = 0; } int lgOutResult; }; int main() { WORD ver = MAKEWORD(2, 2); WSAData dat; WSAStartup(ver, &dat); //1.建立socket套接字 SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //2,bind 繫結用於接收客戶端連線的埠 sockaddr_in sinAddr = {}; sinAddr.sin_family = AF_INET; sinAddr.sin_port = htons(5678); //host to net unsigned short sinAddr.sin_addr.S_un.S_addr = INADDR_ANY; //inet_addr("127.0.0.1") if (SOCKET_ERROR == bind(sock, (sockaddr*)&sinAddr, sizeof(sockaddr_in))) { printf("Bind Error\n"); } else { printf("Bind Success\n"); } //3. listen 監聽網路埠 if (SOCKET_ERROR == listen(sock, 5)) { printf("Listen Error\n"); } else { printf("Listen Success\n"); } //4.accept 接收客戶端連線 sockaddr_in clientAddr = {}; int clAddrLen = sizeof(sockaddr_in); SOCKET sockAccpt = INVALID_SOCKET; sockAccpt = accept(sock, (sockaddr*)&clientAddr, &clAddrLen); if (INVALID_SOCKET == sockAccpt) { printf("Accept Error\n"); } else { printf("Accept Success\n"); } printf("新客戶端加入:Socket = %d,IP = %s \n", (int)sockAccpt, inet_ntoa(clientAddr.sin_addr)); while (true) { DataHeader dbHeader = {}; //讀取包頭資料 int nLen = recv(sockAccpt, (char*)&dbHeader, sizeof(DataHeader), 0); if (nLen < 0) { printf("客戶端已退出,任務結束\n"); break; } switch (dbHeader.cmd) { case CMD_LOGIN: { Login login = {}; recv(sockAccpt, (char*)&login + sizeof(DataHeader) , sizeof(Login)- sizeof(DataHeader), 0); printf("收到命令:CMD_LOGIN ,資料長度: %d, UserName = %s, \ PassWord = %s \n", login.dataLength, login.UserName, login.PassWord); //忽略對使用者密碼進行判斷 LoginResult lgRet = {}; send(sockAccpt, (char*)&lgRet, sizeof(LoginResult), 0); } break; case CMD_LOGOUT: { LogOut logout = {}; recv(sockAccpt, (char*)&logout + sizeof(DataHeader), sizeof(LogOut) - sizeof(DataHeader), 0); printf("收到命令:CMD_LOGOUT ,資料長度: %d, UserName = %s, \ \n", logout.dataLength, logout.UserName ); //忽略對使用者密碼進行判斷 LogOutResult lgOutRet = {}; send(sockAccpt, (char*)&lgOutRet, sizeof(LogOutResult), 0); } break; default: dbHeader.cmd = CMD_ERROR; dbHeader.dataLength = 0; send(sockAccpt, (char*)&dbHeader, sizeof(DataHeader), 0); break; } } //closesocket 關閉套接字 closesocket(sock); closesocket(sockAccpt); WSACleanup(); printf("結束任務\n"); getchar(); return 0; }
【客戶端原始碼】
#define WIN32_LEAN_AND_MEAN #define _WINSOCK_DEPRECATED_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #include <windows.h> #include <WinSock2.h> #include <cstdio> #pragma comment(lib,"ws2_32.lib") enum CMD //命令列舉 { CMD_LOGIN, CMD_LOGIN_RESULT, CMD_LOGOUT, CMD_LOGOUT_RESULT, CMD_ERROR }; //DataHeader struct DataHeader //資料包頭 { short dataLength; short cmd; }; //DataPackage struct Login :public DataHeader //登入 { Login() { dataLength = sizeof(Login); cmd = CMD_LOGIN; } char UserName[32]{}; char PassWord[32]{}; }; struct LoginResult : public DataHeader //登入結果 { LoginResult() { dataLength = sizeof(LoginResult); cmd = CMD_LOGIN_RESULT; lgResult = 0; } int lgResult; }; struct LogOut :public DataHeader //退出登入 { LogOut() { dataLength = sizeof(LogOut); cmd = CMD_LOGOUT; } char UserName[32]{}; }; struct LogOutResult :public DataHeader //退出結果 { LogOutResult() { dataLength = sizeof(LogOutResult); cmd = CMD_LOGOUT_RESULT; lgOutResult = 0; } int lgOutResult; }; int main() { WORD ver = MAKEWORD(2, 2); WSAData dat; WSAStartup(ver, &dat); //1.建立一個socket SOCKET sockCli = socket(AF_INET, SOCK_STREAM, 0); if (INVALID_SOCKET == sockCli) { printf("Socket Error\n"); } else { printf("Socket Success\n"); } //2. connect連線伺服器 sockaddr_in servAddr = {}; servAddr.sin_family = AF_INET; servAddr.sin_port = htons(5678); servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); int ret = connect(sockCli, (sockaddr*)&servAddr, sizeof(sockaddr_in)); if (SOCKET_ERROR == ret) { printf("Connect Error\n"); } else { printf("Connect Success\n"); } while (true) { //3.輸入請求命令 char cmdBuff[128] = {}; scanf("%s", cmdBuff); //4.處理請求 if (0 == strcmp(cmdBuff, "exit")) { printf("接收到命令exit,退出 \n"); break; } else if (0 == strcmp(cmdBuff, "login")) { Login login {}; login.cmd = CMD_LOGIN; login.dataLength = sizeof(login); strcpy(login.UserName, "喜羊羊"); strcpy(login.PassWord,"123456"); //5.向伺服器傳送請求 send(sockCli, (const char *)&login, sizeof(login), 0); //接收伺服器返回的資料 LoginResult loginRet = {}; recv(sockCli, ( char*)&loginRet, sizeof(loginRet), 0); printf("LoginResult: %d\n", loginRet.lgResult); } else if (0 == strcmp(cmdBuff, "logout")) { LogOut logout{}; logout.cmd = CMD_LOGOUT; logout.dataLength = sizeof(logout); strcpy(logout.UserName, "灰太狼"); //5.向伺服器傳送請求 send(sockCli, (const char*)&logout, sizeof(logout), 0); //接收伺服器返回的資料 LogOutResult logOutRet = {}; recv(sockCli, (char*)&logOutRet, sizeof(logOutRet), 0); printf("LogOutResult: %d\n", logOutRet.lgOutResult); } else { printf("不支援該命令,請從新輸入 \n"); } } //7.關閉套接字 closesocket closesocket(sockCli); WSACleanup(); printf("結束任務\n"); getchar(); return 0; }
【執行結果】
服務端資料收發處理優化
while (true) { //緩衝區 char szRecv[1024] = {}; //讀取包頭資料 int nLen = recv(sockAccpt, (char*)&szRecv, sizeof(DataHeader), 0); DataHeader* dbHeader = (DataHeader*)szRecv; if (nLen < 0) { printf("客戶端已退出,任務結束\n"); break; } //if(nLen >= sizeof(DataHeader)) switch (dbHeader->cmd) { case CMD_LOGIN: { recv(sockAccpt, szRecv + sizeof(DataHeader) , dbHeader->dataLength- sizeof(DataHeader), 0); Login* login = (Login*)szRecv; printf("收到命令:CMD_LOGIN ,資料長度: %d, UserName = %s, \ PassWord = %s \n", login->dataLength, login->UserName, login->PassWord); //忽略對使用者密碼進行判斷 LoginResult lgRet = {}; send(sockAccpt, (char*)&lgRet, sizeof(LoginResult), 0); } break; case CMD_LOGOUT: { recv(sockAccpt, szRecv + sizeof(DataHeader), dbHeader->dataLength - sizeof(DataHeader), 0); LogOut* logout = (LogOut*)szRecv; printf("收到命令:CMD_LOGOUT ,資料長度: %d, UserName = %s, \ \n", logout->dataLength, logout->UserName ); //忽略對使用者密碼進行判斷 LogOutResult lgOutRet = {}; send(sockAccpt, (char*)&lgOutRet, sizeof(LogOutResult), 0); } break; default: DataHeader HeaderError = { 0, CMD_ERROR }; send(sockAccpt, (char*)&HeaderError, sizeof(HeaderError), 0); break; } }
- 測試
相關文章
- 串列埠收發字元轉換為整數串列埠字元
- repuest轉發學習筆記一筆記
- 射頻收發記錄儀
- GT收發器
- R/3 ABAP開發學習筆記(轉)筆記
- 【SEO知識】網站發文秒收錄技巧網站
- C++學習筆記C++筆記
- 觸發器學習筆記觸發器筆記
- c++學習筆記(三)C++筆記
- C++學習筆記——003C++筆記
- c++學習筆記(四)C++筆記
- c++學習筆記(五)C++筆記
- OI學習筆記(C++)筆記C++
- 利用python收發MQPythonMQ
- 《筆記》之學習高併發筆記
- JAVA 學習併發筆記(一)Java筆記
- (一)Java併發學習筆記Java筆記
- Rest API 開發 學習筆記RESTAPI筆記
- Android 開發學習筆記Android筆記
- C++學習筆記——C++ 繼承C++筆記繼承
- Salesforce開發「AI經濟學家」,用強化學習設計稅收策略SalesforceAI強化學習
- C/C++學習路線———學習筆記C++筆記
- C/C++學習筆記:字串C++筆記字串
- C++ 學習筆記之 引用C++筆記
- 【C++學習筆記】for迴圈C++筆記
- C++/C學習筆記(七)C++筆記
- C++學習筆記——001C++筆記
- 收發資料的原理(上)
- 收發資料的原理(下)
- Lazarus使用IPC收發訊息
- stm8系列--usart收發
- NDK學習筆記-NDK開發流程筆記
- JS開發步驟學習筆記JS筆記
- Web開發學習筆記——HTTP 概述Web筆記HTTP
- U-boot開發學習筆記boot筆記
- 【Go學習筆記11】併發(一)Go筆記
- Go 併發concurrency 學習筆記Go筆記
- [10.23]戴爾收購蘋果?黃金筆記本曝光(轉)蘋果筆記