#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. 使用ocelot作为api网关

    新建网站项目然后添加ocelot 的nuget包 新建ocelot.json的网关的配置文件 { "GlobalConfiguration": { "BaseUrl&qu ...

  2. 解决js跨域使用nginx配置问题

    在server域中加入以下配置: #解决跨域问题 add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-C ...

  3. 使用自定义View

    1 关于自定义的View的构造函数 java中对构造函数只是调用,不继承.因为整个UI是android系统提供的框架,因此构造函数需要写成它要求的格式,即和View的构造函数一样. 自定义的View中 ...

  4. Servlet概念及与Jsp的区别

    一.Servlet概念 Servlet是在服务器上运行的小程序.一个Servlet就是一个Java类,并且可以通过”请求-响应”编程模型来访问这个驻留在服务器内存里的Servlet程序 二.Servl ...

  5. 洛谷 P1169 棋盘制作 题解

    题面 这道题可以分成两部分来处理: 第一部分: 设f[i][j]表示右下角以(i,j)结尾的最大正方形的边长. 显然f[i][j]=min(f[i][j-1],f[i-1][j-1],f[i-1][j ...

  6. C#实现Web链接启动应用程序

    C#实现Web链接启动应用程序 最近需要配合Web端实现用户点击链接来启动应用程序并且需要能够传参数给应用程序. 那么就可以使用注册表来实现这个功能 编写注册表可以在软件安装程序中加入,也可以在软件启 ...

  7. KNN-机器学习算法

    ''' Created on Sep 16, 2010 kNN: k Nearest Neighbors Input: inX: vector to compare to existing datas ...

  8. css 超出部分显示省略号 汇总

    单行: 加宽度 overflow: hidden; text-overflow:ellipsis; white-space: nowrap; 多行: display: -webkit-box; -we ...

  9. java线程中的同步锁和互斥锁有什么区别?

    两者都包括对资源的独占. 区别是 1:互斥是通过竞争对资源的独占使用,彼此没有什么关系,也没有固定的执行顺序. 2:同步是线程通过一定的逻辑顺序占有资源,有一定的合作关系去完成任务.

  10. Pycharm新建第一个Django项目

    1:安装django 打开Pycharm,在creatproject那里选择新建django项目的时候,会自动帮你安装最新版的Django版本 2:进入Pycharmd的命令窗口,在下方Termina ...