select服务器端模型封装——回调方式快速建立服务端
#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服务器端模型封装——回调方式快速建立服务端的更多相关文章
- select客户端模型封装——回调方式快速建立客户端
SockClient.h #pragma once #include<functional> #define _WINDOWS #ifdef _WINDOWS #define _WINSO ...
- webservice - 使用JAX-WS注解的方式快速搭建服务端和客户端
1.Define the interface import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebRe ...
- 子进程回收资源两种方式,僵尸进程与孤儿进程,守护进程,进程间数据隔离,进程互斥锁,队列,IPC机制,线程,守护线程,线程池,回调函数add_done_callback,TCP服务端实现并发
子进程回收资源两种方式 - 1) join让主进程等待子进程结束,并回收子进程资源,主进程再结束并回收资源. - 2) 主进程 “正常结束” ,子进程与主进程一并被回收资源. from multipr ...
- 如何创建一个客户端回调:js获得服务端的内容?
答案:表面上看去就是前端的js调用服务的C#方法,本质就是ajax,通过XMLHttpRequest对象和服务端进行交互.回调:就说回过头来调用,按理说js是一种脚本语言,怎么能用来调用服务端的呢?就 ...
- Qt 访问网络的 HttpClient(封装QNetworkAccessManager,且有服务端)
Qt 使用 QNetworkAccessManager 访问网络,这里对其进行了简单的封装,访问网络的代码可以简化为: 1 2 3 HttpClient("http://localhost: ...
- webservice系统学习笔记9-使用契约优先的方式的一个服务端demo(隐式传Header信息)
服务器端: 1.编写wsdl文件 <?xml version="1.0" encoding="UTF-8" standalone="no&quo ...
- Android客户端采用Http 协议Post方式请求与服务端进行数据交互(转)
http://blog.csdn.net/javanian/article/details/8194265
- window下命令行的方式安装svn服务端
下载Binary Packages类型的 安装文件 https://www.visualsvn.com/server/download/ 自己选择版本 第一步 :开始安装到 c:/software ...
- 基于Select模型的Windows TCP服务端和客户端程序示例
最近跟着刘远东老师的<C++百万并发网络通信引擎架构与实现(服务端.客户端.跨平台)>,Bilibili视频地址为C++百万并发网络通信引擎架构与实现(服务端.客户端.跨平台),重新复习下 ...
随机推荐
- 2019JAVA第五次实验报告
Java实验报告 班级 计科二班 学号 20188442 姓名 吴怡君 完成时间2019/10/11 评分等级 实验四 类的继承 实验目的 理解抽象类与接口的使用: 了解包的作用,掌握包的设计方法. ...
- Ubuntu 19.04 下使用Remmina连接window服务器部署maven项目
先将打包好的war包上传到tomcat的webapps目录下 如果配置了tomcat的虚拟路径,那就放进虚拟路径的webapps文件李 修改tomcat安装目录下的conf/server.xml文件 ...
- 【字符串大模拟】潜伏者—— NOIP2009原题
洛谷连接 就一道黄题没啥可以说的……就是要细心…… 学到了神奇的优化 ios::sync_with_stdio(false); cin优化,能跑的比scanf快!棒!(不过要开std) 这题真的还挺简 ...
- chromedriver.exe下载
淘宝的镜像地址可以下载: https://npm.taobao.org/mirrors/chromedriver/
- Linux等操作系统杂谈
这部分基本上都是感性认识,介绍一下发展历史什么的.所以基本上都不是我原创的,转载来源都标记在文中了,如果侵权的话请联系删除 操作系统发展历史吃瓜 <Unix.Windows.Mac OS.Lin ...
- android中的rn项目更新gradle及补充二
修改build.gradle的版本,com.android.tools.build:gradle:2.1.0, 改为更高的,然后更改gradle/wrapper/gradle-wrapper.prop ...
- vue点击出现蒙版
需求: 1.点击一个事件时弹出一个蒙版: 2.蒙版上有取消,删除事件:(点击取消时候蒙版消失,点击删除时,删除蒙版并消失): 3.点击空白地方,蒙版也消失: <template> ...
- Solr IK分词器配置
下载地址:https://search.maven.org/search?q=com.github.magese 分词器配置: 参考:https://www.cnblogs.com/mengjinlu ...
- 接口测试断言详解(Jmeter)
接口测试是目前最主流的自动化测试手段,它向服务器发送请求,接收和解析响应结果,通过验证响应报文是否满足需求规约来验证系统逻辑正确性.接口的响应类型通过Content-Type指定,常见的响应类型有: ...
- Eureka实现高可用及为Eureka设置登录账号和密码
本文通过两个eureka相互注册实现注册中心的高可用,同时为注册中心配置认证登录. 需要用到的maven配置 <dependency> <groupId>org.springf ...