1. 头文件

#ifndef __TCP_SERVER_H__
#define __TCP_SERVER_H__
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <errno.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h> #include <iostream>
#include <memory>
#include <thread>
#include <string>
#include <atomic>
using namespace std; class tcp_server
{
public:
class tcp_notify
{
public:
virtual size_t on_recv_data(const unsigned int clientid, const char* buf, const size_t len) = ;
}; public:
tcp_server(tcp_notify& notify);
virtual ~tcp_server();
public:
void start(const string& port);
void stop(); private:
int create_and_bind (const char *port);
int make_socket_non_blocking (int sfd); void thread_func();
private:
tcp_notify& m_notify; int sfd;
int efd;
static const int MAXEVENTS = ;
struct epoll_event *events; atomic<bool> m_thread_state_;
shared_ptr<thread> m_thread_func_;
}; #endif /* TCP_SERVER_H_ */

2. 定义文件

#include "tcp_server.h"

tcp_server::tcp_server(tcp_notify& notify)
: m_notify(notify),
efd(::epoll_create1(EPOLL_CLOEXEC)),
m_thread_state_(true),
m_thread_func_(nullptr)
{
} tcp_server::~tcp_server()
{
stop();
} void tcp_server::start(const string& port)
{
int ret;
struct epoll_event event; sfd = create_and_bind(port.c_str());
if (sfd == -) abort(); ret = make_socket_non_blocking(sfd);
if (ret == -) abort(); ret = listen(sfd, SOMAXCONN);
if (ret == -) {
perror("listen");
abort();
} event.data.fd = sfd;
event.events = EPOLLIN | EPOLLET;
ret = epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &event);
if (ret == -) {
perror("epoll_ctl");
abort();
} /* Buffer where events are returned */
events = (struct epoll_event*)calloc(MAXEVENTS, sizeof(event)); m_thread_func_ = make_shared < thread > (
bind(&tcp_server::thread_func, this));
m_thread_func_->join();
} void tcp_server::stop()
{
m_thread_state_ = false;
m_thread_func_->join();
free(events);
close(sfd);
} int tcp_server::create_and_bind(const char *port)
{
struct addrinfo hints;
struct addrinfo *result, *rp;
int ret, sfd; memset(&hints, , sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */
hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */
hints.ai_flags = AI_PASSIVE; /* All interfaces */ ret = getaddrinfo(NULL, port, &hints, &result);
if (ret != ) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
return -;
} for (rp = result; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -) continue;
ret = bind(sfd, rp->ai_addr, rp->ai_addrlen);
if (ret == ) {
/* We managed to bind successfully! */
break;
} close(sfd);
}
if (rp == NULL) {
fprintf(stderr, "Could not bind\n");
return -;
}
freeaddrinfo(result);
return sfd;
} int tcp_server::make_socket_non_blocking(int sfd)
{
int flags, ret; flags = fcntl(sfd, F_GETFL, );
if (flags == -) {
perror("fcntl");
return -;
} flags |= O_NONBLOCK;
ret = fcntl(sfd, F_SETFL, flags);
if (ret == -) {
perror("fcntl");
return -;
} return ;
} void tcp_server::thread_func()
{
int ret;
struct epoll_event event;
/* The event loop */
while (m_thread_state_) {
int n, i; n = epoll_wait(efd, events, MAXEVENTS, -);
for (i = ; i < n; i++) {
if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP)
|| (!(events[i].events & EPOLLIN))) {
/* An error has occured on this fd, or the socket is not
ready for reading (why were we notified then?) */
fprintf(stderr, "epoll error\n");
close(events[i].data.fd);
continue;
}
else if (sfd == events[i].data.fd) {
/* We have a notification on the listening socket, which
means one or more incoming connections. */
while () {
struct sockaddr in_addr;
socklen_t in_len;
int infd;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; in_len = sizeof in_addr;
infd = accept(sfd, &in_addr, &in_len);
if (infd == -) {
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
/* We have processed all incoming
connections. */
break;
}
else {
perror("accept");
break;
}
}
ret = getnameinfo(&in_addr, in_len, hbuf, sizeof hbuf, sbuf,
sizeof sbuf, NI_NUMERICHOST | NI_NUMERICSERV);
if (ret == ) {
printf("Accepted connection on descriptor %d "
"(host=%s, port=%s)\n", infd, hbuf, sbuf);
} /* Make the incoming socket non-blocking and add it to the
list of fds to monitor. */
ret = make_socket_non_blocking(infd);
if (ret == -) abort(); event.data.fd = infd;
event.events = EPOLLIN | EPOLLET;
ret = epoll_ctl(efd, EPOLL_CTL_ADD, infd, &event);
if (ret == -) {
perror("epoll_ctl");
abort();
}
}
continue;
}
else {
/* We have data on the fd waiting to be read. Read and
display it. We must read whatever data is available
completely, as we are running in edge-triggered mode
and won't get a notification again for the same
data. */
int done = ; while () {
ssize_t count;
char buf[]; count = read(events[i].data.fd, buf, sizeof buf);
if (count == -) {
/* If errno == EAGAIN, that means we have read all
data. So go back to the main loop. */
if (errno != EAGAIN) {
perror("read");
done = ;
}
break;
}
else if (count == ) {
/* End of file. The remote has closed the
connection. */
done = ;
break;
} /* Write the buffer to standard output */
// ret = write(1, buf, count);
// if (ret == -1) {
// perror("write");
// abort();
// }
m_notify.on_recv_data(events[i].data.fd, buf, count);
} if (done) {
printf("Closed connection on descriptor %d\n",
events[i].data.fd); /* Closing the descriptor will make epoll remove it
from the set of descriptors which are monitored. */
close(events[i].data.fd);
}
} // rec end
}// for
}//while(1)
}

3.main.cpp

#include <iostream>
#include "tcp_server.h"
using namespace std; class notify
: public tcp_server::tcp_notify
{
virtual size_t on_recv_data(const unsigned int clientid, const char* buf, const size_t len)
{
string str(buf, len);
cout << "on_recv_data:" << str << endl;
return len;
}
}; int main(int argc,char *argv[])
{
notify notify_inst;
tcp_server test(notify_inst);
test.start(""); cout << "Helloworld!" << endl;
return ;
}

使用epoll实现简单的服务器的更多相关文章

  1. Linux 用epoll实现的简单http服务器

    Linux 用epoll实现的简单http服务器 main.c #include <stdio.h> #include <sys/types.h> #include <s ...

  2. C#中使用Socket实现简单Web服务器

    上一篇博客中介绍了怎样使用socket访问web服务器.关键有两个: 熟悉Socket编程: 熟悉HTTP协议. 上一篇主要是通过socket来模拟浏览器向(任何)Web服务器发送(HTTP)请求,重 ...

  3. 用nodejs搭建一个简单的服务器

    使用nodejs搭建一个简单的服务器 nodejs优点:性能高(读写文件) 数据操作能力强 官网:www.nodejs.org 验证是否安装成功:cmd命令行中输入node -v 如果显示版本号表示安 ...

  4. 初学Node(六)搭建一个简单的服务器

    搭建一个简单的服务器 通过下面的代码可以搭建一个简单的服务器: var http = require("http"); http.createServer(function(req ...

  5. 搭建无限制权限的简单git服务器使用git-daemon脚本

    如果想要用ubantu架设无限制权限(即不适用gitosis)的简单git服务器,实现git库下载clone,push等简单的基本功能, 可以直接使用git-daemon脚本(非常不安全,建议项目代码 ...

  6. 运用socket实现简单的服务器客户端交互

    Socket解释: 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. Socket的英文原义是“孔”或“插座”.作为BSD UNIX的进程通信机制,取后一种意 ...

  7. Ubuntu 14.04搭建简单git服务器

    /****************************************************************************** * Ubuntu 14.04搭建简单gi ...

  8. tomcat解析之简单web服务器(图)

    链接地址:http://gogole.iteye.com/blog/587163 之前有javaeyer推荐了一本书<how tomcat works>,今天晚上看了看,确实不错,第一眼就 ...

  9. Linux 下 简单客户端服务器通讯模型(TCP)

    原文:Linux 下 简单客户端服务器通讯模型(TCP) 服务器端:server.c #include<stdio.h> #include<stdlib.h> #include ...

随机推荐

  1. 中断描述符表 IDT

    保护模式下三个重要的系统表——GDT.LDT和IDT 这里主要是解释中断描述符表 中断描述符表IDT将每个异常或中断向量分别与它们的处理过程联系起来.与GDT和LDT表类似,IDT也是由8字节长描述符 ...

  2. HTML5属性

    HTML5同时增加和废除了很多属性.下面介绍一些常用的属性. 1.表单属性 为input(type=text).select.textarea与button元素新增了autofocus属性.(它以指定 ...

  3. linux压缩打包

    linux下的压缩命令有tar.gzip.gunzip.bzip2.bunzip2. compress.uncompress.zip.unzip.rar.unrar等等,压缩后的扩展名有.tar..g ...

  4. 洛谷P1006 NOIP提高组2008 传纸条

    P1006 传纸条 题目描述 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n 列的矩阵,而小渊和小轩被安排在矩阵对角线的两端,因此,他们就无 ...

  5. 【并查集模板】 【洛谷P2978】 【USACO10JAN】下午茶时间

    P2978 [USACO10JAN]下午茶时间Tea Time 题目描述 N (1 <= N <= 1000) cows, conveniently numbered 1..N all a ...

  6. 洛谷P1082 同余方程 [2012NOIP提高组D2T1] [2017年6月计划 数论06]

    P1082 同余方程 题目描述 求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数解. 输入输出格式 输入格式: 输入只有一行,包含两个正整数 a, b,用一个空格隔开. 输出格式: 输 ...

  7. 避免闲置云资源浪费 | 阿里云轻量级分布式应用服务 SAE 邀您公测

    您是否遇到过: 资源利用率低,多数服务器CPU平均利用率在10%以下,用户需为大量闲置资源买单. 感知 IaaS 购买和集群运维,人员技能要求高,运维效率低. 想拥抱 Kubernetes.微服务架构 ...

  8. excel怎么制作三维圆环图表

    excel怎么制作三维圆环图表 excel怎么制作三维圆环图表?excel中想要制作一个三维圆环图表,该怎么制作呢?下面我们就来看看详细的教程,很简单,在Excel中,可以通过自带的圆环图功能生成二维 ...

  9. R语言基础画图/绘图/作图

    R语言基础画图/绘图/作图 R语言基础画图 R语言免费且开源,其强大和自由的画图功能,深受广大学生和可视化工作人员喜爱,这篇文章对如何使用R语言作基本的图形,如直方图,点图,饼状图以及箱线图进行简单介 ...

  10. [新手必看] 17个常见的Python运行时错误

    对于刚入门的Pythoner在学习过程中运行代码是或多或少会遇到一些错误,刚开始可能看起来比较费劲.随着代码量的积累,熟能生巧当遇到一些运行时错误时能够很快的定位问题原题.下面整理了常见的17个错误, ...