C++ 网络编程 socket(结构化数据传输)

mac2025-09-18  36

结构化数据传输

server

// ctrl + k + c // Ctrl + K+ U #define WIN32_LEAN_AND_MEAN #include <iostream> #include <Windows.h> #include <WinSock2.h> using namespace std; //加入静态连接库 #pragma comment(lib,"ws2_32.lib") //输出目录 $(SolutionDir)..bin/$(Platform)/$(Configuration)\ //中间目录 $(SolutionDir)../temp/$(Platform)/$(Configuration)/$(ProjectName)\ struct DataPackage { int age; char name[32]; //在客户端声明时也要保持该格式,字节对齐 }; int main() { //启动windows socket 2.x环境 WORD ver = MAKEWORD(2, 2); WSADATA dat; WSAStartup(ver, &dat); //--------------------------- //TCP 服务端 //启动windows scoket编程环境 //1.建立一个socket SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //ipv4 数据流 TCP //2.绑定接受客户端连接的端口号bind sockaddr_in _sin = {};// _sin.sin_family = AF_INET;//网络类型 ipv4 _sin.sin_port = htons(4567);// host to net unsigned short 端口号 主机数据转换到网络数据,无符号数据类型 _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");// 服务器的ip地址 //当不知道自己的本机ip地址时可以写为 INADDR_ANY if (bind(_sock, (sockaddr*)&_sin, sizeof(_sin)) == SOCKET_ERROR) { cout << "绑定用于接收客户端连接的网络端口失败" << endl; } else { cout << "绑定网络端口成功..." << endl; }//网络端口是否被占用 //3.监听网络端口listen if (listen(_sock, 5) == SOCKET_ERROR)//等待连接的队列的长度 { cout << "监听网络端口失败..." << endl; } else { cout << "监听网络端口成功..." << endl; } //4.等待接受客户端连接accept sockaddr_in clientAddr = {};//客户端的地址和端口 int nAddrLen = sizeof(sockaddr_in); SOCKET _cSock = INVALID_SOCKET; _cSock = accept(_sock, (sockaddr *)&clientAddr, &nAddrLen); if (_cSock == INVALID_SOCKET) { cout << "错误,接收到无效客户端SOCKET..." << endl; } else { cout << "接收数据客户端有效..." << endl; } cout << "新客户端加入:socket = " << _cSock << ", IP = " << inet_ntoa(clientAddr.sin_addr) /*转换为 字符串 刻度的字符串数字*/ << endl; char _recvBuf[128] = {};//接收缓存区 while (true) { //5.接收客户端的请求数据 int nLen = recv(_cSock, _recvBuf, 128, 0); if (nLen <= 0) { cout << "客户端已退出,任务结束" << endl; break; } cout << "收到命令:" << _recvBuf << endl; //6.处理请求 if (strcmp(_recvBuf, "getInfo") == 0) { //7.向客户端发送一条数据send DataPackage dp = {80,"张国荣"}; send(_cSock, (const char*)&dp, sizeof(DataPackage), 0);//strlen(msgBuf) + 1 将结尾符一并发送过去 } //if (strcmp(_recvBuf, "getName") == 0) { // char msgBuf[] = "Xiao Qiang!"; // //7.向客户端发送一条数据send // send(_cSock, msgBuf, strlen(msgBuf) + 1, 0);//strlen(msgBuf) + 1 将结尾符一并发送过去 //} //else if (strcmp(_recvBuf, "getAge") == 0) { // char msgBuf[] = "18"; // send(_cSock, msgBuf, strlen(msgBuf) + 1, 0);//strlen(msgBuf) + 1 将结尾符一并发送过去 //} else { char msgBuf[] = "hello ,I'm server!"; send(_cSock, msgBuf, strlen(msgBuf) + 1, 0);//strlen(msgBuf) + 1 将结尾符一并发送过去 } } //8.关闭socket closesocket closesocket(_sock); //---------------------------- //清除windows socket环境 WSACleanup(); getchar(); return 0; }

client

#define WIN32_LEAN_AND_MEAN #include <iostream> #include <Windows.h> #include <WinSock2.h> using namespace std; //加入静态连接库 #pragma comment(lib,"ws2_32.lib") //输出目录 $(SolutionDir)..bin/$(Platform)/$(Configuration)\ //中间目录 $(SolutionDir)../temp/$(Platform)/$(Configuration)/$(ProjectName)\ struct DataPackage { int age; char name[32]; //在客户端声明时也要保持该格式,字节对齐 }; int main() { //启动windows socket 2.x环境 WORD ver = MAKEWORD(2, 2); WSADATA dat; WSAStartup(ver, &dat); //----------------------------- //TCP客户端 //1.建立一个socket SOCKET _sock = socket(AF_INET, SOCK_STREAM, 0); if (_sock == INVALID_SOCKET) { cout << "连接服务器失败..." << endl; } else { cout << "连接服务器成功.." << endl; } //2.连接服务器connect sockaddr_in _sin = {}; _sin.sin_family = AF_INET; _sin.sin_port = htons(4567); _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//声明服务端地址 int ret = connect(_sock, (sockaddr*)(&_sin), sizeof(sockaddr_in)); if (ret == SOCKET_ERROR) { cout << "连接服务器失败" << endl; } else { cout << "连接服务器成功" << endl; } while (true) { //3.输入请求命令 char cmdBuf[128] = {}; //cin >> cmdBuf; scanf("%s", cmdBuf); //4.处理请求 if (strcmp(cmdBuf, "exit") == 0) { cout << "已退出客户端,任务结束!" << endl; break; } else { //5.把命令发送给服务端 send(_sock, cmdBuf, strlen(cmdBuf) + 1, 0); } //6.接受服务器信息recv char recBuf[256] = {};//创建数据缓冲区 int nlen = recv(_sock, recBuf, 256, 0); if (nlen > 0) { DataPackage *dp = (DataPackage *)recBuf; cout << "接受的数据为:age: " << dp->age << ", name: "<< dp->name << endl; } else { cout << "接受数据失败" << endl; } } //7.关闭socket closesocket closesocket(_sock); //---------------------------- //清除windows socket环境 WSACleanup(); getchar(); return 0; }

以上命名格式输入错误的时,强制类型转换带来的不安全;

2. 网络数据报文

* 报文有两个部分,包头和包体,是网络消息的基本单元;
* 包头:描述本次消息包的大小,描述数据的作用;
*包体:数据;

2.1 server

// ctrl + k + c // Ctrl + K+ U #define WIN32_LEAN_AND_MEAN #include <iostream> #include <Windows.h> #include <WinSock2.h> using namespace std; //加入静态连接库 #pragma comment(lib,"ws2_32.lib") //输出目录 $(SolutionDir)..bin/$(Platform)/$(Configuration)\ //中间目录 $(SolutionDir)../temp/$(Platform)/$(Configuration)/$(ProjectName)\ enum CMD{ CMD_LOGIN, CMD_LOGOUT, LOG_ERROR }; //消息头 struct DataHeader{ short dataLength;//数据长度 short cmd;// }; //DataPackage struct Login{ char userName[32]; char PassWord[32]; }; struct LoginResult { int result; }; struct LogOut { char userName[32]; }; struct LogOutResult { int result; }; int main() { //启动windows socket 2.x环境 WORD ver = MAKEWORD(2, 2); WSADATA dat; WSAStartup(ver, &dat); //--------------------------- //TCP 服务端 //启动windows scoket编程环境 //1.建立一个socket SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //ipv4 数据流 TCP //2.绑定接受客户端连接的端口号bind sockaddr_in _sin = {};// _sin.sin_family = AF_INET;//网络类型 ipv4 _sin.sin_port = htons(4567);// host to net unsigned short 端口号 主机数据转换到网络数据,无符号数据类型 _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");// 服务器的ip地址 //当不知道自己的本机ip地址时可以写为 INADDR_ANY if (bind(_sock, (sockaddr*)&_sin, sizeof(_sin)) == SOCKET_ERROR) { cout << "绑定用于接收客户端连接的网络端口失败" << endl; } else { cout << "绑定网络端口成功..." << endl; }//网络端口是否被占用 //3.监听网络端口listen if (listen(_sock, 5) == SOCKET_ERROR)//等待连接的队列的长度 { cout << "监听网络端口失败..." << endl; } else { cout << "监听网络端口成功..." << endl; } //4.等待接受客户端连接accept sockaddr_in clientAddr = {};//客户端的地址和端口 int nAddrLen = sizeof(sockaddr_in); SOCKET _cSock = INVALID_SOCKET; _cSock = accept(_sock, (sockaddr *)&clientAddr, &nAddrLen); if (_cSock == INVALID_SOCKET) { cout << "错误,接收到无效客户端SOCKET..." << endl; } else { cout << "接收数据客户端有效..." << endl; } cout << "新客户端加入: socket = " << _cSock << ", IP = " << inet_ntoa(clientAddr.sin_addr) /*转换为 字符串 刻度的字符串数字*/ << endl; while (true) { DataHeader header = {}; //5.接收客户端的请求数据 int nLen = recv(_cSock,(char*)&header, sizeof(DataHeader), 0); if (nLen <= 0) { cout << "客户端已退出,任务结束" << endl; break; } cout << "收到命令:数据命令:" << header.cmd<< ",数据长度:"<< header.dataLength << endl; //6.处理请求 switch (header.cmd) { case CMD_LOGIN: { Login login = {}; recv(_cSock, (char*)&login, sizeof(Login), 0); LoginResult ret = {1}; //忽略判断用户名和密码是否正确 send(_cSock, (char*)&header, sizeof(DataHeader), 0); send(_cSock, (char*)&ret, sizeof(LoginResult), 0); } break; case CMD_LOGOUT: { LogOut logOut = {}; recv(_cSock, (char*)&logOut, sizeof(LogOut), 0); LogOutResult ret = { 1 }; //忽略判断用户名和密码是否正确 send(_cSock, (char*)&header, sizeof(DataHeader), 0); send(_cSock, (char*)&ret, sizeof(LogOutResult), 0); } break; default: { header.cmd = LOG_ERROR; header.dataLength = 0; send(_cSock, (char *)&header, sizeof(header), 0);//strlen(msgBuf) + 1 将结尾符一并发送过去 break; } } } //8.关闭socket closesocket closesocket(_sock); //---------------------------- //清除windows socket环境 WSACleanup(); getchar(); return 0; }

2.2 client

#define WIN32_LEAN_AND_MEAN #include <iostream> #include <Windows.h> #include <WinSock2.h> using namespace std; //加入静态连接库 #pragma comment(lib,"ws2_32.lib") //输出目录 $(SolutionDir)..bin/$(Platform)/$(Configuration)\ //中间目录 $(SolutionDir)../temp/$(Platform)/$(Configuration)/$(ProjectName)\ enum CMD { CMD_LOGIN, CMD_LOGOUT, LOG_ERROR }; //消息头 struct DataHeader { short dataLength;//数据长度 short cmd;// }; //DataPackage struct Login { char userName[32]; char PassWord[32]; }; struct LoginResult { int result; }; struct LogOut { char userName[32]; }; struct LogOutResult { int result; }; int main() { //启动windows socket 2.x环境 WORD ver = MAKEWORD(2, 2); WSADATA dat; WSAStartup(ver, &dat); //----------------------------- //TCP客户端 //1.建立一个socket SOCKET _sock = socket(AF_INET, SOCK_STREAM, 0); if (_sock == INVALID_SOCKET) { cout << "连接服务器失败..." << endl; } else { cout << "连接服务器成功.." << endl; } //2.连接服务器connect sockaddr_in _sin = {}; _sin.sin_family = AF_INET; _sin.sin_port = htons(4567); _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//声明服务端地址 int ret = connect(_sock, (sockaddr*)(&_sin), sizeof(sockaddr_in)); if (ret == SOCKET_ERROR) { cout << "连接服务器失败" << endl; } else { cout << "连接服务器成功" << endl; } while (true) { //3.输入请求命令 char cmdBuf[128] = {}; //cin >> cmdBuf; scanf("%s", cmdBuf); //4.处理请求 //5.把命令发送给服务端 if (strcmp(cmdBuf, "exit") == 0) { cout << "已退出客户端,任务结束!" << endl; break; } else if (strcmp(cmdBuf, "login") == 0) { Login login = { "jmm","lovely" }; DataHeader dh = {sizeof(login),CMD_LOGIN }; //5.把命令发送给服务端 send(_sock, (char*)&dh, sizeof(dh), 0); send(_sock, (char *)&login, sizeof(login), 0); // 接受服务器返回的数据 DataHeader retHeader = {}; LoginResult loginRet = {}; recv(_sock, (char*)&retHeader, sizeof(retHeader), 0); recv(_sock, (char*)&loginRet, sizeof(loginRet), 0); cout << "LoginResult: " << loginRet.result << endl; } else if (strcmp(cmdBuf, "logout") == 0) { LogOut logout = {}; DataHeader dh = {sizeof(logout),CMD_LOGOUT }; //5.把命令发送给服务端 send(_sock, (char *)&dh, sizeof(dh), 0); send(_sock, (char *)&logout, sizeof(logout), 0); // 接受服务器返回的数据 DataHeader retHeader = {}; LoginResult logoutRet = {}; recv(_sock, (char*)&retHeader, sizeof(retHeader), 0); recv(_sock, (char*)&logoutRet, sizeof(logoutRet), 0); cout << "LogOutResult: " << logoutRet.result << endl; } else { cout << "不支持该命令,请重新输入!" << endl; } } //7.关闭socket closesocket closesocket(_sock); //---------------------------- //清除windows socket环境 WSACleanup(); getchar(); return 0; }

2.3 运行结果

最新回复(0)