赞
踩
目录
今日实现任务
1,客户端架构
即启动多个线程,然后在每个线程中建立客户端,然后与服务器进行连接,进行发送消息的活动。
eg:
之前的方法是在主线程中建立1000个客户端,然后进行连接和发送消息。
现在创立四个线程,然后将1000个客户端分散到四个线程中,每个线程处理250个从而减轻压力,并且提升速度。
2,服务器架构
启动多个线程,在客户端连接之后,将新连接的客户端分配到数量比较少的线程中,然后在每个线程中与客户端进行接收消息的活动。
eg:
之前的方法是在主线程中处理连接后的1000个客户端,然后进行连接和发送消息。
现在创立四个线程,然后将连接的1000个客户端分散到四个线程中,每个线程处理250个达到减轻压力,并且提升速度的目的。
3,整体架构
现在还有待提升的地方就是服务器连接客户端的过程,提升一秒接收客户端的连接数量。
- #include "EasyTcpClient.hpp"
- #include<thread>
- #include<mutex>
- bool g_bRun = true;
- mutex _mutexx;
- void cmdThread()//(EasyTcpClient* client)
- {
- while (1)
- {
- char cmdBuf[256] = {};
-
- cin >> cmdBuf;
- if (strcmp(cmdBuf, "exit") == 0){
- g_bRun = false;
- cout << "退出子线程" << endl;
- return;
- }
- else{
- cout << "不支持的命令" << endl;
- }
- }
- }
-
- //客户端数量
- const int cCount = 100;
- //发送线程数量
- const int tCount = 4;
- //客户端数组
- EasyTcpClient* client[cCount];
-
- void sendThread(int id)
- {
- {
- lock_guard<mutex> lock(_mutexx);
- cout << "thread " << id << " start" << endl;
- }
- //四个线程ID
- int c = cCount / tCount;
- int begin = (id - 1)*c;
- int end = id*c;
-
- for (int i = begin; i < end; i++)
- {
- client[i] = new EasyTcpClient();
- }
- for (int i = begin; i < end; i++)
- {
- client[i]->Connect((char *)"127.0.0.1", 4567); //192.168.247.128
- }
-
- cout << "thread=" << id << " Connect=" << begin << " end= " << end << endl;
-
-
- chrono::milliseconds t(3000);
- this_thread::sleep_for(t);
-
- Login login[1];
- for (int i = 0; i < 10; i++)
- {
- strcpy(login[i].userName, "lyd");
- strcpy(login[i].PassWord, "lydmm");
- }
- const int nLen = sizeof(login);
- int _true = 1;
- while (g_bRun && _true)
- {
- for (int i = begin; i < end; i++)
- {
- if (client[i]->SendData(login,nLen) == SOCKET_ERROR)
- {
- _true = 0;
- break;
- }
- client[i]->OnRun();
- }
- }
-
- for (int i = begin; i < end; i++)
- {
- delete client[i];
- client[i]->Close();
- }
- g_bRun = false;
- cout << "thread " << id << " exit" << endl;
-
- }
-
- int main()
- {
- //启动UI线程
- thread t1(cmdThread); //启动线程函数
- t1.detach();
-
- //启动发送线程
- for (int n = 0; n < tCount; n++)
- {
- thread t1(sendThread, n + 1);
- t1.detach();
- }
-
- while (g_bRun)
- {
- Sleep(100);
- }
-
- cout << "已退出" << endl;
- system("pause");
- return 0;
- }
-
- enum CMD
- {
- CMD_LOGIN, //登入
- CMD_LOGIN_RESULT,
- CMD_LOGOUT, //登出
- CMD_LOGOUT_RESULT,
- CMD_NEW_USER_JOIN, //新的用户加入
- CMD_ERROR, //错误
- };
-
- struct DataHeader
- {
- DataHeader()
- {
- dataLength = sizeof(DataHeader);
- cmd = CMD_ERROR;
- }
- short dataLength;
- short cmd;
- };
-
- //匹配四个消息结构体
- struct Login : public DataHeader
- {
- Login()
- {
- dataLength = sizeof(Login);
- cmd = CMD_LOGIN;
- }
- char userName[32];
- char PassWord[32];
- //char data[932];
- };
-
- struct LoginResult : public DataHeader
- {
- LoginResult()
- {
- dataLength = sizeof(LoginResult);
- cmd = CMD_LOGIN_RESULT;
- result = 0;
- }
- int result;
- //char data[992];
- };
-
- 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;
- };
- #include "EasyTcpClient.hpp"
- #include<thread>
- #include<mutex>
- bool g_bRun = true;
- mutex _mutexx;
- void cmdThread()//(EasyTcpClient* client)
- {
- while (1)
- {
- char cmdBuf[256] = {};
-
- cin >> cmdBuf;
- if (strcmp(cmdBuf, "exit") == 0){
- g_bRun = false;
- cout << "退出子线程" << endl;
- return;
- }
- else{
- cout << "不支持的命令" << endl;
- }
- }
- }
-
- //客户端数量
- const int cCount = 100;
- //发送线程数量
- const int tCount = 4;
- //客户端数组
- EasyTcpClient* client[cCount];
-
- void sendThread(int id)
- {
- {
- lock_guard<mutex> lock(_mutexx);
- cout << "thread " << id << " start" << endl;
- }
- //四个线程ID
- int c = cCount / tCount;
- int begin = (id - 1)*c;
- int end = id*c;
-
- for (int i = begin; i < end; i++)
- {
- client[i] = new EasyTcpClient();
- }
- for (int i = begin; i < end; i++)
- {
- client[i]->Connect((char *)"127.0.0.1", 4567); //192.168.247.128
- }
-
- cout << "thread=" << id << " Connect=" << begin << " end= " << end << endl;
-
-
- chrono::milliseconds t(3000);
- this_thread::sleep_for(t);
-
- Login login[1];
- for (int i = 0; i < 10; i++)
- {
- strcpy(login[i].userName, "lyd");
- strcpy(login[i].PassWord, "lydmm");
- }
- const int nLen = sizeof(login);
- int _true = 1;
- while (g_bRun && _true)
- {
- for (int i = begin; i < end; i++)
- {
- if (client[i]->SendData(login,nLen) == SOCKET_ERROR)
- {
- _true = 0;
- break;
- }
- client[i]->OnRun();
- }
- }
-
- for (int i = begin; i < end; i++)
- {
- delete client[i];
- client[i]->Close();
- }
- g_bRun = false;
- cout << "thread " << id << " exit" << endl;
-
- }
-
- int main()
- {
- //启动UI线程
- thread t1(cmdThread); //启动线程函数
- t1.detach();
-
- //启动发送线程
- for (int n = 0; n < tCount; n++)
- {
- thread t1(sendThread, n + 1);
- t1.detach();
- }
-
- while (g_bRun)
- {
- Sleep(100);
- }
-
- cout << "已退出" << endl;
- system("pause");
- return 0;
- }
- #ifndef CELLTimestamp_hpp_
- #define CELLTimestamp_hpp_
-
- #pragma once
- #include<chrono>
- using namespace std::chrono;
-
- class CELLTimestamp
- {
- public:
- CELLTimestamp()
- {
- update();
- }
- ~CELLTimestamp()
- {
-
- }
-
- void update()
- {
- _begin = high_resolution_clock::now();
- }
-
- //获取当前秒
- double getElapsedSecond()
- {
- return this->getElapsedTimeInMicroSec() * 0.000001;
- }
- //获取毫秒
- double getElapsedTimeInMilliSec()
- {
- return this->getElapsedTimeInMicroSec() * 0.001;
- }
- //获取微秒
- long long getElapsedTimeInMicroSec()
- {
- return duration_cast<microseconds>(high_resolution_clock::now() - _begin).count();
- }
- protected:
- time_point<high_resolution_clock> _begin;
- };
-
- #endif
- #ifndef _EasyTcpServer_hpp_
- #define _EasyTcpServer_hpp_
-
- #ifdef _WIN32
- #define FD_SETSIZE 10240
- #define WIN32_LEAN_AND_MEAN
- #include<windows.h>
- #include<Winsock2.h>
- #pragma comment(lib,"ws2_32.lib")
- #else
- #include<unistd.h>
- #include<arpa/inet.h>
- #include<string.h>
-
- #define SOCKET int
- #define INVALID_SOCKET (SOCKET)(~0)
- #define SOCKET_ERROR (-1)
- #endif
-
- #include<iostream>
- #include<vector>
- #include<thread>
- #include<mutex>
- #include<atomic>
-
- #include"MessageHeader.hpp"
- #include"CELLTimestamp.hpp"
- using namespace std;
-
- //缓冲区最小单元大小
- #ifndef RECV_BUFF_SIZE
- #define RECV_BUFF_SIZE 10240
- #endif
-
- //#define _CellServer_THREAD_COUNT 4
-
- //客户端数据类型
- class ClientSocket
- {
- public:
- ClientSocket(SOCKET sockfd = INVALID_SOCKET)
- {
- _sockfd = sockfd;
- memset(_szMsgBuf, 0, sizeof(_szMsgBuf));
- _lastPos = 0;
- }
-
- SOCKET sockfd()
- {
- return _sockfd;
- }
-
- char *msgBuf()
- {
- return _szMsgBuf;
- }
-
- int getLastPos()
- {
- return _lastPos;
- }
-
- void setLastPos(int pos)
- {
- _lastPos = pos;
- }
-
- //发送数据
- int SendData(DataHeader *header)
- {
- if (header)
- {
- return (int)send(_sockfd, (const char *)header, header->dataLength, 0);
- }
- return SOCKET_ERROR;
- }
- private:
- SOCKET _sockfd;
- //第二缓冲区,消息缓冲区
- char _szMsgBuf[RECV_BUFF_SIZE * 10];
- //消息缓冲区的数据尾部位置
- int _lastPos = 0;
- };
-
- //网络事件接口
- class INetEvent
- {
- public:
- //客户端加入事件
- virtual void OnNetJoin(ClientSocket *pClient) = 0;
- //客户端离开事件
- virtual void OnNetLeave(ClientSocket *pClient) = 0;
- //客户端消息事件
- virtual void OnNetMsg(ClientSocket *pClient, DataHeader *header) = 0;
- private:
-
- };
-
-
- class CellServer
- {
- public:
- CellServer(SOCKET sock = INVALID_SOCKET)
- {
- _sock = sock;
- _pNetEvent = nullptr;
- }
-
- ~CellServer()
- {
- Close();
- _sock = INVALID_SOCKET;
- }
-
- //是否工作中
- bool isRun()
- {
- return _sock != INVALID_SOCKET;
- }
-
- void setEventObj(INetEvent *event)
- {
- _pNetEvent = event;
- }
-
- //关闭Socket
- void Close()
- {
- if (_sock != INVALID_SOCKET)
- {
- #ifdef _WIN32
- for (int n = (int)_clients.size() - 1; n >= 0; n--)
- {
- closesocket(_clients[n]->sockfd());
- delete _clients[n];
- }
-
- //关闭套接字closesocket
- closesocket(_sock);
- //-----------
- //清除Windows socket环境
- //WSACleanup();
- #else
- for (int n = (int)_clients.size() - 1; n >= 0; n--)
- {
- close(_clients[n]->sockfd());
- delete _clients[n];
- }
- //关闭套接字closesocket
- close(_sock);
- #endif
- _clients.clear();
- }
- }
-
- //int mun = 0;
- //处理网络消息
- bool OnRun()
- {
- while (isRun())
- {
- //从缓冲区中取出客户数据
- if (_clientsBuff.size() >0)
- {
- lock_guard<mutex> lock(_mutex);
- for (auto pClient : _clientsBuff)
- {
- _clients.push_back(pClient);
- }
- _clientsBuff.clear();
- }
-
- //如果没有需要处理的客户端就跳过
- if (_clients.empty())
- {
- chrono::milliseconds t(1);
- this_thread::sleep_for(t);
- continue;
- //return true;
- }
-
- //伯克利套接字
- fd_set fdRead;
- //fd_set fdWrite;
- //fd_set fdExp;
-
- //清理集合
- FD_ZERO(&fdRead);
- //FD_ZERO(&fdWrite);
- //FD_ZERO(&fdExp);
-
- //将描述符(socket)加入集合
- //FD_SET(_sock, &fdRead);
- //FD_SET(_sock, &fdWrite);
- //FD_SET(_sock, &fdExp);
-
- //将描述符(socket)加入集合
- SOCKET maxSock = _clients[0]->sockfd();
- int nn = (int)_clients.size() - 1;
- for (int n = (int)_clients.size() - 1; n >= 0; n--)
- {
- FD_SET(_clients[n]->sockfd(), &fdRead);
- if (maxSock < _clients[n]->sockfd())
- {
- maxSock = _clients[n]->sockfd();
- }
- }
-
- //nfds 是一个整数值,是指fd_set集合中所有描述符(socket)的范围,而不是数量
- //即是所有文件描述符最大值+1,在Windows中这个参数可以写0
-
- //添加非阻塞
- //timeval t = { 1, 0 };
-
- int ret = select(maxSock + 1, &fdRead, 0, 0, nullptr);
-
- if (ret < 0)
- {
- //cout << "select任务结束 " <<nn<< endl;
- //Close();
- continue;
- }
-
- for (int n = (int)_clients.size() - 1; n >= 0; n--)
- {
- if (FD_ISSET(_clients[n]->sockfd(), &fdRead))
- {
- if (RecvData(_clients[n]) == -1)
- {
- auto iter = _clients.begin() + n;
- if (iter != _clients.end())
- {
- if (_pNetEvent)
- {
- _pNetEvent->OnNetLeave(_clients[n]);
- }
- ///顺序不能变
- delete _clients[n];
- _clients.erase(iter);
- }
- }
- }
- }
- }
- return true;
- }
-
- //缓冲区
- char _szRecv[RECV_BUFF_SIZE];// = {};
- //接收数据 处理粘包哦拆分包
- int RecvData(ClientSocket* pClient)
- {
- //5,接受客户端的请求数据
- int nLen = (int)recv(pClient->sockfd(), (char*)&_szRecv, RECV_BUFF_SIZE, 0);
- if (nLen <= 0)
- {
- //cout <<pClient->sockfd()<< " 客户端已经退出,任务结束" << endl;
- return -1;
- }
- //将收取到的消息拷贝到消息缓冲区
- memcpy(pClient->msgBuf() + pClient->getLastPos(), _szRecv, nLen);
- //消息缓冲区的数据尾部后移
- pClient->setLastPos(pClient->getLastPos() + nLen);
-
- //判断消息缓冲区的数据长度大于消息头DataHeader长度
- while (pClient->getLastPos() >= sizeof(DataHeader))
- {
- //这个时候就知道当前消息长度
- DataHeader *header = (DataHeader*)pClient->msgBuf();
- //判断消息缓冲区的长度大于消息长度
- if (pClient->getLastPos() >= header->dataLength)
- {
- //消息缓冲区剩余未处理数据的长度
- int nSize = pClient->getLastPos() - header->dataLength;
- //处理网络消息
- OnNetMsg(pClient, header);
- //将消息缓冲区剩余未处理数据前移
- memcpy(pClient->msgBuf(), pClient->msgBuf() + header->dataLength, nSize);
- pClient->setLastPos(nSize);
- }
- else{
- //消息缓冲区剩余数据不够一条完整消息
- break;
- }
- }
- return 0;
- }
-
- //响应网络消息
- virtual void OnNetMsg(ClientSocket *pClient, DataHeader *header)
- {
- _pNetEvent->OnNetMsg(pClient, header);
- }
-
- void addClient(ClientSocket *pClient)
- {
- lock_guard<mutex> lock(_mutex);
- //_mutex.lock();
- _clientsBuff.push_back(pClient);
- //_mutex.unlock();
- }
-
- void Start()
- {
- _thread = thread(mem_fn(&CellServer::OnRun), this);
- }
-
- size_t getClientCount()
- {
- return _clients.size()+_clientsBuff.size();
- }
- private:
- SOCKET _sock;
- //正式客户队列
- vector<ClientSocket*> _clients;
- //客户缓冲队列
- vector<ClientSocket*> _clientsBuff;
- //缓冲队列的锁
- mutex _mutex;
- thread _thread;
- //网络事件对象
- INetEvent *_pNetEvent;
- };
-
-
- class EasyTcpServer:public INetEvent
- {
- private:
- SOCKET _sock;
- //vector<ClientSocket*> _clients;
- //消息处理对象,内部会创建线程
- vector<CellServer*> _cellServers;
- //每秒消息计时
- CELLTimestamp _tTime;
- //收到消息计数
- public:
- atomic<int> _recvCount;
- //客户端计数
- atomic<int> _clientCount;
-
- public:
- EasyTcpServer()
- {
- _sock = INVALID_SOCKET;
- _recvCount = 0;
- _clientCount = 0;
- }
-
- virtual ~EasyTcpServer()
- {
- Close();
- }
-
- //初始化Socket
- SOCKET InitSocket()
- {
- #ifdef _WIN32
- //启动Windows socket 2.x环境
- WORD ver = MAKEWORD(2, 2);
- WSADATA dat;
- WSAStartup(ver, &dat);
- #endif
- //1,用Socket API建立建立TCP客户端
- if (_sock != INVALID_SOCKET)
- {
- cout << "_sock=" << (int)_sock << "关闭旧连接" << endl;
- Close();
- }
- _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
-
- if (_sock == INVALID_SOCKET)
- {
- cout << "建立socket失败" << endl;
- }
- else
- {
- cout << (int)_sock << " 建立socket成功" << endl;
- }
- return _sock;
- }
-
- //绑定IP和端口号
- int Bind(const char *ip, unsigned short port)
- {
- //if (_sock != INVALID_SOCKET)
- //{
- // InitSocket();
- //}
- //2,bind 绑定用于接受客户端连接的网络接口
- sockaddr_in _sin = {};
- _sin.sin_family = AF_INET;
- _sin.sin_port = htons(port);
- #ifdef _WIN32
- if (ip){
- _sin.sin_addr.S_un.S_addr = inet_addr(ip);
- }
- else{
- _sin.sin_addr.S_un.S_addr = INADDR_ANY;
- }
- #else
- if (ip){
- _sin.sin_addr.s_addr = inet_addr(ip);
- }
- else{
- _sin.sin_addr.s_addr = INADDR_ANY;
- }
- #endif
-
-
- int ret = ::bind(_sock, (sockaddr*)&_sin, sizeof(_sin));
- if (SOCKET_ERROR == ret)
- {
- cout << (int)_sock << "错误,绑定网络端口失败" << endl;
- }
- else
- {
- cout << "绑定网络端口成功" << port << endl;
- }
- return ret;
- }
-
- //监听端口号
- int Listen(int n)
- {
- int ret = listen(_sock, n);
- if (SOCKET_ERROR == ret)
- {
- cout << (int)_sock << " 错误,监听网络端口失败" << endl;
- }
- else
- {
- cout << (int)_sock << " 监听网络端口成功" << endl;
- }
- return ret;
- }
-
- //接受客户端连接
- SOCKET Accept()
- {
- //4,accept 等待客户端连接
- sockaddr_in clientAddr = {};
- int nAddrlen = sizeof(clientAddr);
- SOCKET cSock = INVALID_SOCKET;
-
- #ifdef _WIN32
- cSock = accept(_sock, (sockaddr *)&clientAddr, &nAddrlen);
- #else
- cSock = accept(_sock, (sockaddr *)&clientAddr, (socklen_t *)&nAddrlen);
- #endif
- if (INVALID_SOCKET == cSock)
- {
- cout << (int)_sock << " 错误,接受到无效的客户端连接" << endl;
- }
- else
- {
- //NewUserJoin userJoin;
- //SendDataToAll(&userJoin);
- //将新客户端分配给客户端数量最少的cellServer
- addClientToCellServer(new ClientSocket(cSock));
- //获取IP地址 inet_ntoa(clientAddr.sin_addr)
- }
- return _sock;
- }
-
-
- void addClientToCellServer(ClientSocket *pClient)
- {
- //_clients.push_back(pClient);
- //查找客户数量最少的CellServer消息处理对象
- auto pMinServer = _cellServers[0];
- for (auto pCellServer : _cellServers)
- {
- if (pMinServer->getClientCount() > pCellServer->getClientCount())
- {
- pMinServer = pCellServer;
- }
- }
- pMinServer->addClient(pClient);
- OnNetJoin(pClient);
- }
-
-
- void Start(int _CellServer_THREAD_COUNT)
- {
- for (int n = 0; n < _CellServer_THREAD_COUNT; n++)
- {
- auto ser = new CellServer(_sock);
- _cellServers.push_back(ser);
- //注册网络事件接收对象
- ser->setEventObj(this);
- //启动消息处理线程
- ser->Start();
- }
- }
-
- //关闭Socket
- void Close()
- {
- if (_sock != INVALID_SOCKET)
- {
- #ifdef _WIN32
- //for (int n = (int)_clients.size() - 1; n >= 0; n--)
- //{
- // closesocket(_clients[n]->sockfd());
- // delete _clients[n];
- //}
-
- //关闭套接字closesocket
- closesocket(_sock);
- //-------------
- //清除Windows socket环境
- WSACleanup();
- #else
- for (int n = (int)_clients.size() - 1; n >= 0; n--)
- {
- close(_clients[n]->sockfd());
- delete _clients[n];
- }
- //8,关闭套接字closesocket
- close(_sock);
- #endif
- //_clients.clear();
- }
- }
-
- //处理网络消息
- bool OnRun()
- {
- if (isRun())
- {
- time4msg();
- //伯克利套接字
- fd_set fdRead;
- //fd_set fdWrite;
- //fd_set fdExp;
-
- FD_ZERO(&fdRead);
- //FD_ZERO(&fdWrite);
- //FD_ZERO(&fdExp);
-
- FD_SET(_sock, &fdRead);
- //FD_SET(_sock, &fdWrite);
- //FD_SET(_sock, &fdExp);
-
- //nfds 是一个整数值,是指fd_set集合中所有描述符(socket)的范围,而不是数量
- //即是所有文件描述符最大值+1,在Windows中这个参数可以写0
-
- //添加非阻塞
- timeval t = { 0, 10 };
-
- int ret = select(_sock + 1, &fdRead, 0, 0, &t); //
-
- if (ret < 0)
- {
- cout << "Accept Select任务结束" << endl;
- Close();
- return false;
- }
-
- if (FD_ISSET(_sock, &fdRead))
- {
- FD_CLR(_sock, &fdRead);
- Accept();
- return true;
- }
-
- return true;
- }
- return false;
- }
-
- //是否工作中
- bool isRun()
- {
- return _sock != INVALID_SOCKET;
- }
-
- //响应网络消息
- void time4msg()
- {
- auto t1 = _tTime.getElapsedSecond();
- if (_tTime.getElapsedSecond() >= 1.0)
- {
- //cout << "thread "<<_cellServers.size()<<" tTime " << t1 <<" client " <<(int)_clients.size()<<" socket " << _sock << " _recvCount " << _recvCount<< endl;
- cout << "thread " << _cellServers.size() << " tTime " << t1 << " client " << (int)_clientCount << " socket " << _sock << " _recvCount " << _recvCount << endl;
- _recvCount = 0;
- _tTime.update();
- }
- }
-
- //群发消息
- //void SendDataToAll(DataHeader *header)
- //{
- // for (int n = (int)_clients.size() - 1; n >= 0; n--)
- // {
- // SendData(_clients[n]->sockfd(), header);
- // }
- //}
-
-
- //只会被一个线程调用 安全
- virtual void OnNetJoin(ClientSocket *pClient)
- {
- _clientCount++;
- }
- //4 多个线程触发不安全
- //如果只开启一个cellServer就是安全的
- virtual void OnNetLeave(ClientSocket *pClient)
- {
- _clientCount--;
- //for (int n = (int)_clients.size() - 1; n >= 0; n--)
- //{
- // if (_clients[n] == pClient)
- // {
- // auto iter = _clients.begin() + n;
- // if (iter != _clients.end())
- // {
- // _clients.erase(iter);
- // }
- // }
- //}
- }
- //4 多个线程触发不安全
- //如果只开启一个cellServer就是安全的
- virtual void OnNetMsg(ClientSocket *pClient, DataHeader *header)
- {
- _recvCount++;
- }
- };
-
- #endif
- enum CMD
- {
- CMD_LOGIN, //登入
- CMD_LOGIN_RESULT,
- CMD_LOGOUT, //登出
- CMD_LOGOUT_RESULT,
- CMD_NEW_USER_JOIN, //新的用户加入
- CMD_ERROR, //错误
- };
-
- struct DataHeader
- {
- DataHeader()
- {
- dataLength = sizeof(DataHeader);
- cmd = CMD_ERROR;
- }
- short dataLength;
- short cmd;
- };
-
- //匹配四个消息结构体
- struct Login : public DataHeader
- {
- Login()
- {
- dataLength = sizeof(Login);
- cmd = CMD_LOGIN;
- }
- char userName[32];
- char PassWord[32];
- //char data[932];
- };
-
- struct LoginResult : public DataHeader
- {
- LoginResult()
- {
- dataLength = sizeof(LoginResult);
- cmd = CMD_LOGIN_RESULT;
- result = 0;
- }
- int result;
- //char data[992];
- };
-
- 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;
- };
- #include"EasyTcpServer.hpp"
- #include<thread>
-
- class MyServer :public EasyTcpServer
- {
- public:
- //只会被一个线程调用 安全
- virtual void OnNetJoin(ClientSocket *pClient)
- {
- _clientCount++;
- //cout << "client " << pClient->sockfd() << "join" << endl;
- }
- //4 多个线程触发不安全
- //如果只开启一个cellServer就是安全的
- virtual void OnNetLeave(ClientSocket *pClient)
- {
- _clientCount--;
- //cout << "client " << pClient->sockfd() << "leave" << endl;
- }
- //4 多个线程触发不安全
- //如果只开启一个cellServer就是安全的
- virtual void OnNetMsg(ClientSocket *pClient, DataHeader *header)
- {
- _recvCount++;
- switch (header->cmd)
- {
- case CMD_LOGIN:
- {
- //做数据偏移
- Login *login = (Login*)header;
- //cout << "收到命令:CMD_LOGIN, 数据长度:" << login->dataLength;
- //cout << " UserName:" << login->userName << " PassWord:" << login->PassWord << endl;
- //忽略判断用户名密码是否正确的过程
- LoginResult ret;
- pClient->SendData(&ret);
- }
- break;
- case CMD_LOGOUT:
- {
- Login *logout = (Login*)header;
- cout << "收到命令:CMD_LOGIN, 数据长度:" << logout->dataLength;
- cout << " UserName:" << logout->userName << endl;
- //忽略判断用户名密码是否正确的过程
- LogoutResult ret;
- //SendData(_cSock, (DataHeader *)&ret);
- }
- break;
- default:
- {
- cout << pClient->sockfd() << " 收到未定义的消息,数据长度 " << header->dataLength;
- DataHeader ret;
- //SendData(_cSock, (DataHeader *)&ret);
- }
- break;
- }
- }
- private:
-
- };
- int main()
- {
- MyServer server;
- server.InitSocket();
- server.Bind(nullptr, 4567);
- server.Listen(5);
- server.Start(4);
-
- while (server.isRun())
- {
- server.OnRun();
- }
-
- server.Close();
- cout << "已退出" << endl;
- system("pause");
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。