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++百万并发网络通信引擎架构与实现(服务端.客户端.跨平台),重新复习下 ...
随机推荐
- 不用 Notepad++,还有更牛逼的选择!
来源:oschina.net/news/110987/no-notepad-plus-plus 这两天 Notepad++ 牛逼了,然后引发了大家的关注,具体事件内容请大家自行百度,其实作为文本编辑工 ...
- Zookeeper 和Eureka比较
作为服务注册中心,Eureka比Zookeeper好在哪里著名的CAP理论指出,一个分布式系统不可能同时满足C(一致性).A(可用性)和P(分区容错性).由于分区容错性P在是分布式系统中必须要保证的, ...
- 【洛谷P1886】滑动窗口——单调队列
没想到啊没想到,时隔两个月,我单调队列又懵了…… 调了一个小时,最后错在快读,啊!!!!(不过洛谷讨论真好啊,感谢大佬!) 考前就不推新东西了,好好写写那些学过的东西 题目点这里(我就不粘了自己点一下 ...
- PHP手册在7.1迁移页面给出了替代方案,就是用OpenSSL取代MCrypt.
/** * [AesSecurity aes加密,支持PHP7.1] */ class AesSecurity { /** * [encrypt aes加密] * @p ...
- [转载]Linux运行模式及紧急、救援模式
运行模式 在Linux中,存在一个叫init(initialize)的进程,其进程号是1,该进程存在一个对应的配置文件inittab,叫做系统的运行级别配置文件,位置在/etc/inittab.(但是 ...
- 剑指offer 数字翻译成字符串
0 -> 'a', 1->'b', ..., 11 -> 'l', ..., 25->'z'. 计算一个数有多少种不同的翻译方法. 分析:记f[i]表示从第i位起的不同翻译数目 ...
- luogu P4076 [SDOI2016]墙上的句子
luogu loj 题意看了我半天(逃 (应该是我语文太差了) 题意是要确定每一行和每一列的看单词的顺序,使得同时正着出现和反着出现在里面的单词数量最少,每行和每列的性质是这一行所有单词反过来的单词要 ...
- java 实现傅立叶变换算法 及复数的运算
最近项目需求,需要把python中的算法移植到java上,其中有一部分需要用到复数的运算和傅立叶变换算法,废话不多说 如下: package qrs; /** * 复数的运算 * */ public ...
- 10.css3动画--过渡动画--trasition
Transition简写属性. Transition-property规定应用过渡的css属性的名称. . Transition-timing-function过渡效果的时间曲线,默认是ease. L ...
- jQuery中outerWidth()方法
截图自:菜鸟教程https://www.runoob.com/jquery/html-outerwidth.html