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++百万并发网络通信引擎架构与实现(服务端.客户端.跨平台),重新复习下 ...
随机推荐
- lambda得用法
- 交换机安全学习笔记 第八章 针对POE的攻击
POE即 Power over Ethernet 借助于以太网供电.最初为了IP电话,目前主要用于功耗小于15.4w的设备例如Ap和视频监控设备.并且简化了相关设备的电力线布线. 英文缩写注释:PSE ...
- hue的load balance
参考: hue的load balance官网: https://www.cloudera.com/documentation/enterprise/6/6.2/topics/hue_use_add_l ...
- String.equals()方法、整理String类的Length()、charAt()、 getChars()、replace()、 toUpperCase()、 toLowerCase()、trim()、toCharArray()
equals 是比较的两个字符串是否一样 length() 返回字符串的长度 charAt (int index) 返回index所指定的字符 getChars(int srcBegin,int sr ...
- Deepin安装 ruby 包管理工具 RVM(适用于 Debian 系列)
1. 安装 GPG keys 先安装 gpg2 工具 sudo apt install gnupg2 再安装 keys gpg2 --recv-keys 409B6B1796C275462A17031 ...
- synchronize和lock的区别 & synchionzie与volatile的区别
synchronized与Lock的区别 https://www.cnblogs.com/iyyy/p/7993788.html Lock和synchronized和volatile的区别和使用 ht ...
- 关于在docker中配置elasticsearch容器的方法
一.关于docker的安装,注意几点 1.如果系统是Win10家庭版,是没有Hyper-V的,所以无法安装docker(运行docker安装包会报错),为此docker官网提供的解决方法是安装dock ...
- java线程间的通讯
主要通过wait()和notify()方法进行线程间的通讯 class Product extends Thread{ String name; float price; boolean flag = ...
- Librepilot-创建UAVObject及编译到飞机端和地面站端的步骤
1. 创建UAVObject描述文件(xx.xml),并存放到\librepilot\shared\uavobjectdefinition目录中:2. 在\librepilot\flight\targ ...
- Qualcomm_Mobile_OpenCL.pdf 翻译-8-kernel性能优化
这章将会说明一些kernel优化的小技巧. 8.1 kernel合并或者拆分 一个复杂的应用程序可能包含很多步骤.对于OpenCL的移植性和优化,可能会问需要开发有多少个kernel.这个问题很难回答 ...