客户端升级为select网路模型
作者:互联网
服务器端:
#include<WinSock2.h> #include<Windows.h> #include<vector> #include<stdio.h> #include<iostream> #pragma comment(lib,"ws2_32.lib") enum CMD { CMD_Login, CMD_Login_Result, CMD_Logout, CMD_Logout_Result, CMD_New_User_Join, CMD_ERROR }; //包头 struct DataHeader { short dataLength; short cmd; }; //包体 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; result = 0; } int result; }; 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; result = 0; } int result; }; struct NewUserJoin :public DataHeader { NewUserJoin() { dataLength = sizeof(NewUserJoin); cmd = CMD_New_User_Join; sock = 0; } int sock; }; std::vector<SOCKET> g_client; int process_solve(SOCKET _cSOCK) { //增加一个缓冲区 char szRecv[1024] = {}; //5.接收客户端新数据 int nLen = recv(_cSOCK, szRecv, sizeof(DataHeader), 0); DataHeader *header = (DataHeader*)szRecv; if (nLen <= 0) { printf("客户端已退出!任务结束!"); return -1; } switch (header->cmd){ case CMD_Login: { recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0); Login *login = (Login*)szRecv; printf("收到客户端<Socket=%d>请求:CMD_Login,数据长度:%d\nUserName:%s\nPassWord:%s\n", _cSOCK,login->dataLength, login->username, login->password); //忽略判断用户密码是否正确的过程 LoginResult ret; send(_cSOCK, (char *)&ret, sizeof(LoginResult), 0); //再发消息体 } case CMD_Logout: { recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0); Logout* logout = (Logout*)szRecv; printf("收到命令:CMD_Logout,数据长度:%d\nUserName:%s\n", logout->dataLength, logout->username); //忽略判断用户密码是否正确的过程 LogoutResult let; send(_cSOCK, (char *)&let, sizeof(let), 0); //再发消息体 } break; case CMD_New_User_Join: { recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0); NewUserJoin* UserJoin = (NewUserJoin*)szRecv; printf("收到命令:CMD_Logout,数据长度:%d\nUserName:%s\n", UserJoin->dataLength); //忽略判断用户密码是否正确的过程 NewUserJoin let; send(_cSOCK, (char *)&let, sizeof(let), 0); //再发消息体 } break; default: { DataHeader header = { 0 }; send(_cSOCK, (char *)&header.cmd, sizeof(header), 0); } break; } } int main() { WORD ver = MAKEWORD(2, 2); WSADATA dat; //WinSocket启动 WSAStartup(ver, &dat); //1、建立一个socket SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //AF_INET创建一个IPV4的套接字,SOCK_STREAM面向数据流的,IPPROTO_TCP TCP if (INVALID_SOCKET == _sock) { printf("ERROR:建立失败!\n"); } //2.绑定 sockaddr_in _sin = {}; //创建网络地址 _sin.sin_family = AF_INET; _sin.sin_port = htons(4567); //Host to Network Short _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // IP地址 if (bind(_sock, (sockaddr *)&_sin, sizeof(_sin)) == SOCKET_ERROR) { printf("ERROR:绑定失败!\n"); } else { printf("服务器端绑定成功......\n"); } //3.监听网络端口 if (listen(_sock, 5) == SOCKET_ERROR)//第二个参数为最大等待多少人可以同时连接 { printf("ERROR:监听失败!\n"); } else { printf("服务器端监听成功......\n"); } while (1) { //伯克利 socket fd_set fd_Read; fd_set fd_Write; fd_set fd_Exp; FD_ZERO(&fd_Read);//FD_ZERO 清空集合里的数据 FD_ZERO(&fd_Write); FD_ZERO(&fd_Exp); FD_SET(_sock, &fd_Read);//FD_SET 可以进行操作的宏 FD_SET(_sock, &fd_Write); FD_SET(_sock, &fd_Exp); for (int n = g_client.size() - 1; n >= 0; n--) { FD_SET(g_client[n], &fd_Read); } /* select( _In_ int nfds, _Inout_opt_ fd_set FAR * readfds, _Inout_opt_ fd_set FAR * writefds, _Inout_opt_ fd_set FAR * exceptfds, _In_opt_ const struct timeval FAR * timeout ); */ //nfds是一个整数值,是指fd_set集合所有的描述符(select里的第一个参数)的范围(而不是数量) //既是所有文件描述符最大值+1 timeval t = {1,0}; int ret = select(_sock + 1, &fd_Read, &fd_Write, &fd_Exp, &t); if (ret < 0) { printf("select任务结束!\n"); break; } if (FD_ISSET(_sock, &fd_Read)) { FD_CLR(_sock, &fd_Read); //4.等待接收客户端连接 sockaddr_in clientAddr = {}; int nAddrLen = sizeof(sockaddr_in); SOCKET _cSOCK = INVALID_SOCKET; _cSOCK = accept(_sock, (sockaddr *)&clientAddr, &nAddrLen); if (_cSOCK == INVALID_SOCKET) { printf("ERROR:无效客户端SOCKET!\n"); } for (int n = g_client.size() - 1; n >= 0; n--) { NewUserJoin UserJoin; send(g_client[n], (const char*)&UserJoin, sizeof(UserJoin), 0); } g_client.push_back(_cSOCK); printf("新客户端加入:Socket=%d,IP = %s\n", (int)_cSOCK, inet_ntoa(clientAddr.sin_addr));//inet_ntoa(clientAddr.sin_addr)将接收到的IP地址转化为字符串 } for (int n = 0; n < fd_Read.fd_count; n++) { if (process_solve(fd_Read.fd_array[n]) == -1) { auto iter = find(g_client.begin(), g_client.end(), process_solve(fd_Read.fd_array[n])); if (iter != g_client.end()) { g_client.erase(iter); } } } printf("空闲时间处理其他业务.......\n"); } for (int n = g_client.size(); n >= 0; n--) { //8.关闭自身的socket closesocket(g_client[n]); } //8.关闭自身的socket closesocket(_sock); //WinSocket关闭 WSACleanup(); system("pause"); return 0; }
客户端:
#include<WinSock2.h> #include<Windows.h> #include<stdio.h> #pragma comment(lib,"ws2_32.lib") enum CMD { CMD_Login, CMD_Login_Result, CMD_Logout, CMD_Logout_Result, CMD_New_User_Join, CMD_ERROR }; //包头 struct DataHeader { short dataLength; short cmd; }; //包体 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; result = 0; } int result; }; 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; result = 0; } int result; }; struct NewUserJoin :public DataHeader { NewUserJoin() { dataLength = sizeof(LogoutResult); cmd = CMD_New_User_Join; sock = 0; } int sock; }; int process_solve(SOCKET _cSOCK) { //增加一个缓冲区 char szRecv[1024] = {}; //5.接收客户端新数据 int nLen = recv(_cSOCK, szRecv, sizeof(DataHeader), 0); DataHeader *header = (DataHeader*)szRecv; if (nLen <= 0) { printf("与服务器断开连接!任务结束!"); return -1; } switch (header->cmd){ case CMD_Login_Result: { recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0); LoginResult *loginresult = (LoginResult*)szRecv; printf("收到服务端消息请求:CMD_Login_Result,数据长度:%d\nUserName:%s\nPassWord:%s\n", loginresult->dataLength); } break; case CMD_Logout_Result: { recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0); LogoutResult* logoutresult = (LogoutResult*)szRecv; printf("收到服务端消息请求:CMD_Logout_Result,数据长度:%d\nUserName:%s\n", logoutresult->dataLength); } break; case CMD_New_User_Join: { recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0); NewUserJoin* newuserjoin = (NewUserJoin*)szRecv; printf("收到服务端消息请求:CMD_New_User_Join,数据长度:%d\nUserName:%s\n", newuserjoin->dataLength); } break; } } int main() { WORD ver = MAKEWORD(2, 2); WSADATA dat; WSAStartup(ver, &dat); //1.建立一个socket SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == _sock) { printf("ERROR:建立失败!\n"); } else{ printf("客户端绑定成功......\n"); } //2.连接服务器 sockaddr_in _sin = {}; //创建网络地址 _sin.sin_family = AF_INET; _sin.sin_port = htons(4567); //Host to Network Short _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//inet_addr("127.0.0.1"); // IP地址 int ret = connect(_sock, (sockaddr *)&_sin, sizeof(sockaddr_in)); if (SOCKET_ERROR == ret) { printf("ERROR:连接失败!\n"); } else { printf("客户端连接成功......\n"); } while (true) { //伯克利 socket fd_set fd_Read; FD_ZERO(&fd_Read);//FD_ZERO 清空集合里的数据 FD_SET(_sock, &fd_Read);//FD_SET 可以进行操作的宏 timeval t = {1,0}; int ret = select(_sock, &fd_Read, 0, 0,&t); if (ret < 0) { printf("select任务结束1!"); break; } if (FD_ISSET(_sock,&fd_Read)) { FD_CLR(_sock, &fd_Read); if (process_solve(_sock) == -1) { printf("select任务结束2!"); break; } } printf("空闲时间处理其他业务.......\n"); Login login; strcpy(login.username, "sutaoyu"); strcpy(login.password, "sutaoyu01"); send(_sock, (const char*)&login, sizeof(Login),0); Sleep(1000); } //7.关闭套接字 closesocket(_sock); //WinSocket启动 WSAStartup(ver, &dat); //WinSocket关闭 WSACleanup(); printf("已退出!"); getchar(); return 0; }
标签:CMD,sock,fd,select,dataLength,DataHeader,sizeof,网路,客户端 来源: https://www.cnblogs.com/zhuifeng-mayi/p/10999752.html