#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 = ; //客户端最大连接数量 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 = ; 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, );
closesocket(it->s);
}
closesocket(this->_sServer);
WSACleanup();
} int SelectServer::_Init()
{
WSADATA wsadata;
int ret = WSAStartup(MAKEWORD(, ), &wsadata);
if ( == ret) {
return ;
}
this->_lastError = ret;
return ;
} 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 < || id >= ClientList.size()) {
return -;
}
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, );
}
} int SelectServer::recvFromClient(int id, char * buf, int len)
{
return recv(ClientList[id].s, buf, len, );
} int SelectServer::getClientListLen()
{
return ClientList.size();
return ;
} sockaddr_in *SelectServer::getAddr(int id)
{
if (id < && 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 = ; i < ClientList.size(); i++)
{
FD_SET(ClientList[i].s, &fdRead);
} int ret = select(this->_sServer, &fdRead, &fdWrite, &fdExp, NULL);
if (ret == -) {
std::cout << WSAGetLastError() << std::endl;
} //返回错误退出
if (ret < ){
break;
}
//fd_set没有变化
else if (ret == ) {
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()-, this);
}
for (int i = ; 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[];
//int len = recv(client.s, buf, 256, 0);
int len = server->recvFromClient(clientId, buf, );
if (len < ) {
std::cout << "客户端 " << inet_ntoa(server->getAddr(clientId)->sin_addr) << ' ' << ntohs(server->getAddr(clientId)->sin_port) << " 断开连接" << std::endl;
return false;
}
buf[len] = ;
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();
//server->setHost(2059); if (server->bindAddr()==-) {
std::cout << "监听失败 Error code: " << WSAGetLastError() << std::endl;
system("pause<nul");
return ;
}
std::cout << "等待连接" << std::endl;
server->start(
acceptFun,
readFun,
NULL,
NULL
);
std::cout << WSAGetLastError() << std::endl;
system("pause>nul");
return ;
}

select服务器端模型封装——回调方式快速建立服务端的更多相关文章

  1. select客户端模型封装——回调方式快速建立客户端

    SockClient.h #pragma once #include<functional> #define _WINDOWS #ifdef _WINDOWS #define _WINSO ...

  2. webservice - 使用JAX-WS注解的方式快速搭建服务端和客户端

    1.Define the interface import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebRe ...

  3. 子进程回收资源两种方式,僵尸进程与孤儿进程,守护进程,进程间数据隔离,进程互斥锁,队列,IPC机制,线程,守护线程,线程池,回调函数add_done_callback,TCP服务端实现并发

    子进程回收资源两种方式 - 1) join让主进程等待子进程结束,并回收子进程资源,主进程再结束并回收资源. - 2) 主进程 “正常结束” ,子进程与主进程一并被回收资源. from multipr ...

  4. 如何创建一个客户端回调:js获得服务端的内容?

    答案:表面上看去就是前端的js调用服务的C#方法,本质就是ajax,通过XMLHttpRequest对象和服务端进行交互.回调:就说回过头来调用,按理说js是一种脚本语言,怎么能用来调用服务端的呢?就 ...

  5. Qt 访问网络的 HttpClient(封装QNetworkAccessManager,且有服务端)

    Qt 使用 QNetworkAccessManager 访问网络,这里对其进行了简单的封装,访问网络的代码可以简化为: 1 2 3 HttpClient("http://localhost: ...

  6. webservice系统学习笔记9-使用契约优先的方式的一个服务端demo(隐式传Header信息)

    服务器端: 1.编写wsdl文件 <?xml version="1.0" encoding="UTF-8" standalone="no&quo ...

  7. Android客户端采用Http 协议Post方式请求与服务端进行数据交互(转)

    http://blog.csdn.net/javanian/article/details/8194265

  8. window下命令行的方式安装svn服务端

    下载Binary Packages类型的 安装文件  https://www.visualsvn.com/server/download/  自己选择版本 第一步 :开始安装到 c:/software ...

  9. 基于Select模型的Windows TCP服务端和客户端程序示例

    最近跟着刘远东老师的<C++百万并发网络通信引擎架构与实现(服务端.客户端.跨平台)>,Bilibili视频地址为C++百万并发网络通信引擎架构与实现(服务端.客户端.跨平台),重新复习下 ...

随机推荐

  1. 20191209 Linux就该这么学(4)

    4. Vim编辑器与Shell命令脚本 Vim 编辑器中设置了三种模式-命令模式.末行模式和编辑模式. 命令模式:控制光标移动,可对文本进行复制.粘贴.删除和查找等工作. 输入模式:正常的文本录入. ...

  2. (5.2)mysql高可用系列——测试环境部署

    关键词环境部署: ############## 测试环境机器架构 #########[1]策划[1.1]linux服务器A组 8台 192.168.1.200~192.168.1.207,主机名db, ...

  3. AKKA学习(二) 未完

    Actor调用 从上面的例子中,我们可以大概的对AKKA在JAVA中的使用有一个全局的概念.这里我们在稍微细致的讲解一下. 在JAVA中使用AKKA进行开发主要有这几个步骤: 定义消息模型. 创建Ac ...

  4. AppCan适配问题

    使用AppCan调试中心时,屏幕适配是个问题,经过多次调试总结出如下经验: 1,使用HD+(1560 x 720):显示错乱 2,使用FHD+ (2340 x 1080):显示错乱 3,HD (128 ...

  5. numpy-tile 数组复制

    tile(A, reps):把数组A复制成新数组 # 把 矩阵 看做一个整体,第二个参数代表把 矩阵 复制 m*n 次 b = np.arange(1, 5).reshape(2, 2) print( ...

  6. Android 调用摄像头功能【拍照与视频】

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/ma_hoking/article/details/28292973 应用场景: 在Android开发 ...

  7. git 版本回退方法

    ORIG_HEAD 某些操作,例如 merage / reset 会把 merge 之前的 HEAD 保存到 ORIG_HEAD 中,以便在 merge 之后可以使用 ORIG_HEAD 来回滚到合并 ...

  8. Java的duotaix

    今天看到博客园上一位原创的博文讲解Java多态性,觉得不错,不过没有解释,特此注释,侵删 public class MyTest { public static void main(String ar ...

  9. Linux crontab计划任务

    1.cron计划任务的描述        cron计划任务允许用户根据“时间表”自动周期的完成任务某些任务.        cron是一种system V服务,需要开启该服务才能使用.        ...

  10. horizon服务

    一.horizon 介绍: 理解 horizon Horizon 为 Openstack 提供一个 WEB 前端的管理界面 (UI 服务 )通过 Horizone 所提供的 DashBoard 服务 ...