#pragma once #ifndef WINSOCK2_H #define _WINSOCK_DEPRECATED_NO_WARNINGS #include WinSock2.h #include Windows.h #pragma comment(lib, "ws2_32.lib") #endif #include iostream #include thread #include vector static bool ServerRun = true ; static
#pragma once #ifndef WINSOCK2_H #define _WINSOCK_DEPRECATED_NO_WARNINGS #include<WinSock2.h> #include<Windows.h> #pragma comment(lib, "ws2_32.lib") #endif #include<iostream> #include<thread> #include<vector> static bool ServerRun = true; static bool _isInit = false; //WSA是否初始化 struct ClientSock { SOCKET s; sockaddr_in addr; }; class SelectServer { private: int _lastError; //最后一次错误 sockaddr_in _addr; //服务器绑定的地址 SOCKET _sServer; //服务器监听套接字 int _maxClientNum = 5; //客户端最大连接数量 std::vector<ClientSock> ClientList; //客户端列表 //初始化WSA,成功返回1,失败返回0 int _Init(); public: SelectServer(int m_port); ~SelectServer(); //获取错误,返回错误码 inline int getLastError(); //设置绑定端口 void setHost(int m_port); //绑定地址 bool bindAddr(); //设置最多连接客户端数量 void setMaxClientNum(int n); //向客户端发送消息 int sendToClient(int id,char *buf,int len); //向所有客户端发送消息 void sendAllClient(char * buf, int len); //从客户端接收消息 int recvFromClient(int id, char *buf, int len); //获取客户端列表长度 int getClientListLen(); //获取客户端地址 sockaddr_in *getAddr(int id); //开始工作 void start( std::function<void(int clientId, SelectServer *server)> const &AcceptMethod, std::function<bool (int clientId, SelectServer *server) > const &ReadMethod, std::function<void(int clientId, SelectServer *server)> const &WriteMethod, std::function<void(int clientId, SelectServer *server)> const &ExpMethod ); //停止工作 void quit(); };
#include "pch.h" #include "SelectServer.h" SelectServer::SelectServer(int m_port) { this->_Init(); this->_lastError = 0; this->_addr.sin_port = htons(m_port); this->_addr.sin_family = AF_INET; this->_addr.sin_addr.S_un.S_addr = INADDR_ANY; this->_sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == this->_sServer) { this->_lastError = WSAGetLastError(); return; } //初始化WSA if (!_isInit) { if (this->_Init()) { _isInit = true; } } } SelectServer::~SelectServer() { for (std::vector<ClientSock>::iterator it = ClientList.begin(); it != ClientList.end();it++) { shutdown(it->s, 2); closesocket(it->s); } closesocket(this->_sServer); WSACleanup(); } int SelectServer::_Init() { WSADATA wsadata; int ret = WSAStartup(MAKEWORD(2, 2), &wsadata); if (0 == ret) { return 1; } this->_lastError = ret; return 0; } inline int SelectServer::getLastError() { return WSAGetLastError(); } void SelectServer::setHost(int m_port) { this->_addr.sin_port = htons(m_port); } bool SelectServer::bindAddr() { if (SOCKET_ERROR == bind(this->_sServer, (sockaddr *)&this->_addr, sizeof(sockaddr_in))) { this->_lastError = WSAGetLastError(); return false; } if (SOCKET_ERROR == listen(this->_sServer, this->_maxClientNum)) { this->_lastError = WSAGetLastError(); return false; } return true; } void SelectServer::setMaxClientNum(int n) { this->_maxClientNum = n; } int SelectServer::sendToClient(int id,char * buf, int len) { if (id < 0 || id >= ClientList.size()) { return -1; } return send(ClientList[id].s, buf, len, NULL); } void SelectServer::sendAllClient(char * buf, int len) { for (std::vector<ClientSock>::iterator it = ClientList.begin(); it != ClientList.end(); it++) { send(it->s, buf, len, 0); } } int SelectServer::recvFromClient(int id, char * buf, int len) { return recv(ClientList[id].s, buf, len, 0); } int SelectServer::getClientListLen() { return ClientList.size(); return 0; } sockaddr_in *SelectServer::getAddr(int id) { if (id < 0 && id >= ClientList.size()) { return NULL; } return &ClientList[id].addr; } void SelectServer::start( std::function<void(int clientId, SelectServer *server)> const &AcceptMethod, std::function<bool(int clientId, SelectServer *server)> const &ReadMethod, std::function<void(int clientId, SelectServer *server)> const &WriteMethod, std::function<void(int clientId, SelectServer *server)> const &ExpMethod ){ std::cout << "Start" << std::endl; fd_set fdRead, fdWrite, fdExp; //开始select轮询 while (true) { if (!ServerRun) { return; } FD_ZERO(&fdRead); FD_ZERO(&fdWrite); FD_ZERO(&fdExp); FD_SET(this->_sServer, &fdRead); FD_SET(this->_sServer, &fdWrite); FD_SET(this->_sServer, &fdExp); for (int i = 0; i < ClientList.size(); i++) { FD_SET(ClientList[i].s, &fdRead); } int ret = select(this->_sServer, &fdRead, &fdWrite, &fdExp, NULL); if (ret == -1) { std::cout << WSAGetLastError() << std::endl; } //返回错误退出 if (ret < 0){ break; } //fd_set没有变化 else if (ret == 0) { continue; } if (FD_ISSET(this->_sServer, &fdRead)) { FD_CLR(this->_sServer, &fdRead); ClientSock client; int len = sizeof(client.addr); client.s = accept(this->_sServer, (sockaddr *)&client.addr, &len); if (SOCKET_ERROR == client.s) { continue; } ClientList.push_back(client); AcceptMethod(ClientList.size()-1, this); } for (int i = 0; i < ClientList.size(); i++) { if (FD_ISSET(ClientList[i].s, &fdRead)) { FD_CLR(ClientList[i].s, &fdRead); if (ReadMethod != NULL) { if (!ReadMethod(i,this)) { ClientList.erase(ClientList.begin() + i); continue; } } } if (FD_ISSET(ClientList[i].s, &fdWrite)) { FD_CLR(ClientList[i].s, &fdWrite); if (WriteMethod != NULL) { WriteMethod(i, this); continue; } } if (FD_ISSET(ClientList[i].s, &fdExp)) { FD_CLR(ClientList[i].s, &fdExp); if (ExpMethod != NULL) { ExpMethod(i, this); continue; } } } } } void SelectServer::quit() { ServerRun = false; }
使用样例:
// select库.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #define _WINSOCK_DEPRECATED_NO_WARNINGS #include "pch.h" #include "SelectServer.h" #include <iostream> #include <vector> void acceptFun(int clientId, SelectServer *server) { std::cout << "客户端 "<<inet_ntoa(server->getAddr(clientId)->sin_addr)<<‘ ‘<<ntohs(server->getAddr(clientId)->sin_port)<<" 连接" << std::endl; } bool readFun(int clientId, SelectServer *server) { char buf[256]; //int len = recv(client.s, buf, 256, 0); int len = server->recvFromClient(clientId, buf, 256); if (len < 0) { std::cout << "客户端 " << inet_ntoa(server->getAddr(clientId)->sin_addr) << ‘ ‘ << ntohs(server->getAddr(clientId)->sin_port) << " 断开连接" << std::endl; return false; } buf[len] = 0; std::cout << "客户端 " << inet_ntoa(server->getAddr(clientId)->sin_addr) << ‘ ‘ << ntohs(server->getAddr(clientId)->sin_port) << "发送数据:" << std::endl; std::cout << buf << std::endl; return true; } int main() { SelectServer *server = new SelectServer(2059); //server->setHost(2059); if (server->bindAddr()==-1) { std::cout << "监听失败 Error code: " << WSAGetLastError() << std::endl; system("pause<nul"); return 0; } std::cout << "等待连接" << std::endl; server->start( acceptFun, readFun, NULL, NULL ); std::cout << WSAGetLastError() << std::endl; system("pause>nul"); return 0; }