一、epoll简单实现 单线程实现多路链接与多路通信
/* 开始epoll流程 */
int epollfd;
struct epoll_event events[EPOLLEVENTS];// 并发100个事件
//创建一个描述符
epollfd = epoll_create(FDSIZE);
//添加监听描述符事件
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = sock_fd;
epoll_ctl(epollfd, EPOLL_CTL_ADD, sock_fd, &ev);
//获取已经准备好的描述符事件
ret = epoll_wait(epollfd, events, EPOLLEVENTS, -1);
int i;
int fd;
//进行选好遍历
for (i = 0; i < ret; i++)
{
fd = events[i].data.fd;
//根据描述符的类型和事件类型进行处理
if ((fd == sock_fd) && (events[i].events & EPOLLIN))
{
handle_accpet(epollfd, sock_fd);
}
else if (events[i].events & EPOLLIN)
{
memset(recv_buf, 0, sizeof(recv_buf));
do_read(epollfd, fd, recv_buf);
}
}
二、 epoll封装:单线程实现多路链接与多路通信
epoll封装类:
一、地址类CHostAddress:包含服务器socket地址信息
CHostAddress.h
#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
//功能:完成地址相关信息的赋值(struct sockaddr_in s_addr;)
class CHostAddress {
public:
CHostAddress(unsigned short port);
~CHostAddress();
unsigned short getport();
struct sockaddr_in* getaddr_in();
struct sockaddr* getaddr();
int getlength();
private:
unsigned short port;
struct sockaddr_in s_addr;
int length;
};
CHostAddress.cpp
#include "CHostAddress.h"
CHostAddress::CHostAddress(unsigned short port)
{
this->port = port;
this->s_addr.sin_family = AF_INET;
this->s_addr.sin_addr.s_addr = INADDR_ANY;
this->s_addr.sin_port = htons(10086);
this->length = sizeof(this->s_addr);
}
CHostAddress::~CHostAddress()
{
}
unsigned short CHostAddress::getport()
{
return this->port;
}
sockaddr_in* CHostAddress::getaddr_in()
{
return &(this->s_addr);
}
sockaddr* CHostAddress::getaddr()
{
return (struct sockaddr*)&(this->s_addr);
}
int CHostAddress::getlength()
{
return this->length;
}
二、基于socket的通信基类CBaseSocket
CBaseSocket.h
#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include<stdio.h>
#include<iostream>
using namespace std;
//功能:进行socket,返回fd,并提供继承的接口
class CBaseSocket
{
public:
CBaseSocket(unsigned short port);
virtual ~CBaseSocket();
int getSocketfd();
void Start();//可能会有TCP和UDP
virtual void Stop() = 0;//纯虚函数
virtual void Run() = 0;
protected:
int socketfd;
};
CBaseSocket.cpp
#include "CBaseSocket.h"
CBaseSocket::CBaseSocket(unsigned short port)
{
this->socketfd = 0;
}
CBaseSocket::~CBaseSocket()
{
}
int CBaseSocket::getSocketfd()
{
return this->socketfd;
}
void CBaseSocket::Start()
{
//this->socketfd = socket(PF_INET, SOCK_STREAM,IPPROTO_TCP );//有点不一样
this->socketfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
//错误的判断
if (this->socketfd < 0) {
perror("socket error:");
}
else {
cout << "socket success" << endl;
this->Run();
}
}
三、 继承socket通信基类:TCP式通信
CTcpServer.h
#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <vector>
#include <algorithm>
#include "CBaseSocket.h"
#include "CHostAddress.h"
/*
父类::Start():socket
构造:socket、bind、listen
RUN:accpet相关
*/
#define LISTEN_MAX 10
class CTcpServer:
public CBaseSocket
{
public:
CTcpServer(unsigned short port);//子类的参数一
~CTcpServer();
void addAcceptVector(int newfd);
void subAcceptVector(int newfd);
void Stop();
void Run();
private:
CHostAddress *Add;//地址
vector<int> v_accfd;
};
CTcpServer.cpp
#include "CTcpServer.h"
#include<iostream>
using namespace std;
CTcpServer::CTcpServer(unsigned short port):CBaseSocket(port)
{
this->Add = new CHostAddress(port);
}
CTcpServer::~CTcpServer()
{
delete this->Add;//子类的析构要执行,把父写成虚
}
void CTcpServer::addAcceptVector(int newfd)
{
this->v_accfd.push_back(newfd);
cout << "v_accfd len = " << this->v_accfd.size() << endl;
}
void CTcpServer::subAcceptVector(int newfd)
{
//vt.erase( remove( vt.begin() , vt.end() , k ) , vt.end() )
this->v_accfd.erase(std::remove(v_accfd.begin(), v_accfd.end(), newfd), v_accfd.end());
cout << "v_accfd len = " << this->v_accfd.size() << endl;
}
void CTcpServer::Stop()
{
if (this->socketfd != 0) {
close(this->socketfd);
this->socketfd = 0;
}
}
void CTcpServer::Run()
{
int opt_val = 1;
if (setsockopt(this->socketfd, SOL_SOCKET, SO_REUSEADDR, (const void*)&opt_val, sizeof(opt_val)) == -1) {
perror("setsockopt error");
}
if (bind(this->socketfd, this->Add->getaddr(),this->Add->getlength()) == -1) {
perror("bind error");
}
if (listen(this->socketfd, 5) == -1) {
perror("listen error");
}
cout << "setsockopt、bind、listen Success 服务器启动……(" <<this->socketfd <<")" << endl;
}
四、 epoll封装:利用成员实现socket前几个步骤,依靠epoll实现单线程
CEpollServer.h
#pragma once
#include <sys/epoll.h>
#include <string.h>
#include "CTcpServer.h"
/*包含TCPserver
*
* 第一步:epoll_create(1)
* 第二步:ADD
* 第三步epoll_wait
*
*
*
*
*/
class CEpollServer
{
public:
CEpollServer(unsigned short port);//对象初始化
~CEpollServer();
void Start();
void Run();
void Stop();
private:
int epollfd;
struct epoll_event epollevent;
struct epoll_event epolleventArray[5];
CTcpServer *Tcp;//完成到listen的类对象
};
CEpollServer.cpp
#include "CEpollServer.h"
CEpollServer::CEpollServer(unsigned short port)
{
this->Tcp = new CTcpServer(port);
this->epollfd = 0;
bzero(&epollevent, sizeof(epollevent));
}
CEpollServer::~CEpollServer()
{
}
void CEpollServer::Start()
{
this->Tcp->Start();
this->epollevent.data.fd = Tcp->getSocketfd();
this->epollevent.events = EPOLLIN; //有事件进入
this->epollfd = epoll_create(5);
if (this->epollfd == -1) {
perror("epoll_create error");
}
else {
cout << "epoll_create success" << endl;
}
int res = epoll_ctl(this->epollfd, EPOLL_CTL_ADD, Tcp->getSocketfd(), &(this->epollevent));
if (res == -1) {
perror("epoll_ctl error");
}
else {
cout << "epoll_ctl success" << endl;
}
}
//wait利用epoll accept新的客户端、接收消息
void CEpollServer::Run()
{
char buf[300] = {0};
int nReady = epoll_wait(this->epollfd, this->epolleventArray, 5, -1);//-1:永远等待
cout << "就绪队列取出" << nReady << "组事件" << endl;
for (int i = 0; i < nReady; i++) {
if (this->epolleventArray[i].data.fd == Tcp->getSocketfd()) {
int acceptfd = accept(Tcp->getSocketfd(), NULL, NULL);
cout << "新用户连接 acceptfd = " << acceptfd << endl;
this->epollevent.data.fd = acceptfd;
this->epollevent.events = EPOLLIN;
epoll_ctl(this->epollfd, EPOLL_CTL_ADD, acceptfd, &(this->epollevent));
Tcp->addAcceptVector(acceptfd);
}
else if (this->epolleventArray[i].events & EPOLLIN) {
int res = read(this->epolleventArray[i].data.fd, buf, sizeof(buf));
if (res > 0) {
cout << "收到了来自fd:" << this->epolleventArray[i].data.fd << "的信息:" << buf << endl;
bzero(buf,sizeof(buf));
}
else {
//从epoll中删除
Tcp->subAcceptVector(epolleventArray[i].data.fd);
this->epollevent.data.fd = this->epolleventArray[i].data.fd;
this->epollevent.events = EPOLLIN;
epoll_ctl(this->epollfd, EPOLL_CTL_DEL, this->epolleventArray[i].data.fd, &(this->epollevent));
//关闭这个fd对应的网络通道
close(this->epolleventArray[i].data.fd);
}
}
}
}
void CEpollServer::Stop()
{
close(this->epollfd);
}
五、 项目入口
main.cpp
#include<iostream>
using namespace std;
#include "CEpollServer.h"
int main() {
CEpollServer* ep = new CEpollServer(10086);
ep->Start();
while (1) {
cout << "!" << endl;
ep->Run();
}
return 0;
}