代码拉取完成,页面将自动刷新
#pragma once
#include <iostream>
#include <sys/poll.h>
#include <functional>
#include "Sock.hpp"
#include "Epoll.hpp"
namespace ns_epoll
{
class EpollServer
{
private:
const static int default_port = 8080;
const static int gnum = 64;
using func_t = std::function<void(string)>;
public:
EpollServer(func_t HandlerRequest, uint16_t port=default_port)
:_port(port), _revsNum(gnum), _HandlerRequest(HandlerRequest)
{
// 0. 申请对应的空间
_revs = new struct epoll_event[_revsNum];
// 1. 创建listensock
_listenSock = _sock.Socket();
_sock.Bind(_listenSock, _port);
_sock.Listen(_listenSock);
// 2. 创建epoll模型
_epollfd = _epoll.CreateEpoll();
// 3, 4 监听和epoll模型俩个套接字fd
LogMessage(DEBUG, "init success, listenSock: %d, epfd: %d", _listenSock, _epollfd);
// 3. 将listensock,先添加到epoll中,让epoll帮我们管理起来
if(!_epoll.CtlEpoll(_epollfd, EPOLL_CTL_ADD, _listenSock, EPOLLIN))
{
LogMessage(FATAL, "添加epoll中失败 %d:%s", errno, strerror(errno));
exit(6);
}
LogMessage(DEBUG, "add listensock to epoll success.");
}
void Start()
{
int timeout = 0; // -1: 资源未就绪就不提醒, 0资源未就绪就一直提醒, >0等待的时间
while(true)
{
LoopOnce(timeout);
}
}
~EpollServer()
{
if(_listenSock>0)
close(_listenSock);
}
private:
void LoopOnce(int timeout)
{
int n = _epoll.WaitEpoll(_epollfd, _revs, _revsNum, timeout);
switch (n)
{
case 0:
// 资源未就绪
//LogMessage(DEBUG, "time out...");
break;
case -1:
LogMessage(WARNING, "select error: %d : %s", errno, strerror(errno));
break;
default:
// 成功的, 资源就绪
LogMessage(DEBUG, "get a new link event...");
HandlerEvent(n);
break;
}
}
void HandlerEvent(int n)
{
assert(n>0);
for(int i=0; i<_revsNum; ++i)
{
uint32_t revents = _revs[i].events;
int sock = _revs[i].data.fd;
// 读事件就绪
if(revents & EPOLLIN)
{
if(sock == _listenSock) Accepter(); // 1. listensock 就绪
else Recver(sock); // 2. 一般sock 就绪 - read
}
// 写事件就绪
if(revents & EPOLLOUT)
{
//TODO?
}
}
}
void Accepter()
{
// 建立链接
string clientip;
uint16_t clientport = 0;
int serverSock = _sock.Accept(_listenSock, &clientip, &clientport);
LogMessage(DEBUG, "get a new link success : [%s:%d] : %d", clientip.c_str(), clientport, serverSock);
// 将新的sock,添加给epoll
if(!_epoll.CtlEpoll(_epollfd, EPOLL_CTL_ADD, serverSock, EPOLLIN))
{
LogMessage(FATAL, "添加epoll中失败 %d:%s", errno, strerror(errno));
exit(6);
}
LogMessage(DEBUG, "add serverSock to epoll success. ");
}
void Recver(int sock)
{
// 1. 读取数据
char buffer[10240];
ssize_t n = recv(sock, buffer, sizeof(buffer)-1, 0);
if(n > 0)
{
//假设这里就是读到了一个完整的报文 // 如何保证??
buffer[n] = 0;
_HandlerRequest(buffer); // 2. 处理数据
}
else if(n == 0)
{
// 1. 先在epoll中去掉对sock的关心, 因为必须sock有效才能取消
bool res = _epoll.CtlEpoll(_epollfd, EPOLL_CTL_DEL, sock, 0);
assert(res);
(void)res;
// 2. 在close文件
close(sock);
LogMessage(NORMAL, "client %d quit, me too...", sock);
}
else
{
// 1. 先在epoll中去掉对sock的关心
bool res = _epoll.CtlEpoll(_epollfd, EPOLL_CTL_DEL, sock, 0);
assert(res);
(void)res;
// 2. 在close文件
close(sock);
LogMessage(NORMAL, "client recv %d error, close error sock", sock);
}
}
private:
int _listenSock; // 创建套接字返回的文件描述符,用于TCP监听
uint16_t _port; // 16位端口号
Sock _sock; // socket套接字封装;对象
int _epollfd; // Epoll模型,进程通过此文件描述符找到
Epoll _epoll; // epoll封装;对象
struct epoll_event *_revs; // 事件就绪后,epoll会把将要发生的事件赋值到这个数组里去、
int _revsNum; // 数组里事件最大可存的个数
func_t _HandlerRequest; // 服务器,处理的业务
};
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。