最近看了《linux高性能服务器编程》那本书, 上面描述Rector的一张图
对着这图,自己用c++封装了一下, 不知道有什么不足出,请大神们多多指点下。代码如下:
服务器端代码:
#include <iostream>
#include <unistd.h>
#include <cassert>
#include <cstdlib>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <vector>
#include <map>
#include <fcntl.h>
using namespace std;
#define MAX 100
int listenfd;
class Rector;
class Demultiplexer;
class Handle
{
public:
Handle(int fd = -1): m_fd(fd) {}
virtual ~Handle() {close(m_fd);}
virtual void call_back(int fd){}
int getfd() const
{
return m_fd;
}
protected:
int m_fd;
};
class TcpHandle : public Handle
{
public:
TcpHandle(int fd) : Handle(fd) {}
void call_back(int fd)
{
char buff[1024] = {0};
memset(buff, 0, 1024);
int n = recv(fd, buff, 1024, 0);
if(n < 0)
perror("recv error");
else if(n == 0)
cout << "one client over " << endl;
else
cout << "recv data: " << buff << endl;
send(fd, "OK", 2, 0);
}
};
class Demultiplexer
{
public:
Demultiplexer(int fd = -1) : epfd(fd){}
~Demultiplexer(){close(epfd);}
void Register(Handle* handle);
void Remove(Handle* handle);
void dispatch();
void start_listen(int fd, char *ip, int port);
private:
map<int, Handle*> m_dump;
int epfd;
struct epoll_event fds[MAX];
};
void Demultiplexer::start_listen(int fd, char *ip, int port)
{
epfd = epoll_create(MAX);
struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = inet_addr(ip);
assert(bind(fd, (struct sockaddr*)&saddr, sizeof(saddr)) != -1);
assert(listen(fd, 5) != -1);
}
void Demultiplexer::Register(Handle* handle)
{
int fd = handle->getfd();
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = fd;
if(epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1)
{
perror("epoll_ctl error");
return ;
}
int oldflag = fcntl(fd, F_GETFL);
int newflag = oldflag | O_NONBLOCK;
if(fcntl(fd, F_SETFL, newflag) == -1)
{
perror("fcntl error");
return ;
}
m_dump.insert(make_pair(fd, handle));
}
void Demultiplexer::Remove(Handle* handle)
{
int fd = handle->getfd();
if(epoll_ctl(epfd, EPOLL_CTL_DEL,fd, NULL) == -1)
{
perror("epoll_ctr error");
}
m_dump.erase(fd);
}
void Demultiplexer::dispatch()
{
while(1)
{
int n = epoll_wait(epfd, fds, MAX, -1);
switch(n)
{
case -1:
perror("epoll_wait error");
break;
case 0:
continue;
break;
default:
{
for(int i = 0; i < n; ++i)
{
if(fds[i].data.fd == listenfd)
{
struct sockaddr_in caddr;
socklen_t len = sizeof(caddr);
int c = accept(fds[i].data.fd, (struct sockaddr*)&caddr, &len);
cout << "one client connect ip: " << inet_ntoa(caddr.sin_addr) << " port: "
<< ntohs(caddr.sin_port) << endl;
Handle *p = new TcpHandle(c);
Register(p);
}
else if(fds[i].events & EPOLLIN)
{
int fd = fds[i].data.fd;
map<int, Handle*>::iterator it = m_dump.find(fds[i].data.fd);
if(it != m_dump.end())
{
(it->second)->call_back(fd);
}
else
{
m_dump.erase(fd);
Remove(new TcpHandle(fd));
}
}
}
}
break;
}
}
}
class Rector
{
public:
static Rector* getInstance()
{
if(m_rector == NULL)
{
m_rector = new Rector();
}
return m_rector;
}
void start(int fd, char *ip, int port)
{
m_demp.start_listen(fd, ip, port);
}
void Register(Handle *handle)
{
m_demp.Register(handle);
}
void Remove(Handle* handle)
{
m_demp.Remove(handle);
}
void handle_event()
{
m_demp.dispatch();
}
private:
Rector(){}
static Rector* m_rector;
Demultiplexer m_demp;
};
Rector* Rector::m_rector = NULL;
static Rector* rector = Rector::getInstance();
int main(int argc, char* argv[])
{
if(argc < 3)
{
cout << "invalid argument" << endl;
exit(0);
}
int port = atoi(argv[2]);
listenfd = socket(AF_INET, SOCK_STREAM, 0);
assert(listenfd != -1);
rector->start(listenfd, argv[1], port);
Handle *p = new TcpHandle(listenfd);
rector->Register(p);
rector->handle_event(); //循环
return 0;
}
客户端代码:
#include <iostream>
using namespace std;
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include <cassert>
#include <sys/epoll.h>
#include <fcntl.h>
#include <stdio.h>
#include <cstdlib>
#include <errno.h>
class Client
{
public:
Client(char *ip, int port)
{
sockfd = socket(AF_INET, SOCK_STREAM, 0);
assert(sockfd != -1);
struct sockaddr_in saddr;
bzero(&saddr, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = inet_addr(ip);
socklen_t len = sizeof(saddr);
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &saddr, len);
if(connect(sockfd, (struct sockaddr*)&saddr, len) < 0)
{
cout << errno << endl;
perror("connect error");
}
}
void sendData(char *buff)
{
send(sockfd, buff, strlen(buff), 0);
}
void recvData(char *buff)
{
recv(sockfd, buff, 1024, 0);
}
int getfd() const{
return sockfd;
}
private:
int sockfd;
};
int main(int argc, char *argv[])
{
if(argc < 3)
{
cout << "Invalid argument !" << endl;
exit(0);
}
int port = atoi(argv[2]);
Client cli(argv[1], port);
char buff[1024] = {0};
while(1)
{
memset(buff, 0, 1024);
cin.getline(buff, 1024);
cli.sendData(buff);
memset(buff, 0, 1024);
cli.recvData(buff);
cout << "recv data: " << buff << endl;
}
return 0;
}
本文分享了使用C++和Epoll实现的简单服务器端和客户端代码。通过封装Epoll事件处理过程,实现了高效的并发连接处理。服务器端采用面向对象的方式进行设计,包括Handle、TcpHandle、Demultiplexer和Rector等类。
357

被折叠的 条评论
为什么被折叠?



