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. JavaScript的原型链

    首先介绍下原型~原型的作用:把方法放到原型中,就可以让同类型的对象共享 . 当我创建一个构造函数.构造函数里有原型.通过:构造函数名.prototype获取到当前构造函数的原型. function S ...

  2. 10分钟完成 mongodb replSet 部署

    开始: ------------------------------------------------------------------------------------------------ ...

  3. 1.1Jupyter notbook 的使用

    目录 目录 (一)安装Jupyter notebook 1.在控制台输入: 2.注意: 3.安装的过程: (二)启动Jupyter notebook (三)文件管理 (四)基本概念与操作 1.什么是C ...

  4. Django--多对多表的创建、contentType、ajax、ajax传输json数据格式、ajax传输文件数据、 自定义分页器

    MTV与MVC(了解): MTV模型(Django用的就是MTV): M:模型层(models.py) T:templates C:views MVC模型: M:模型层(models.py) V:视图 ...

  5. ROWID的使用——快速删除重复的记录

    ROWID是数据的详细地址,通过rowid,oracle可以快速的定位某行具体的数据的位置.ROWID可以分为物理rowid和逻辑rowid两种.普通的表中的rowid是物理rowid,索引组织表(I ...

  6. Spring_事务

    事务管理: 用来确保数据的完整性和一致性 事务就是一系列的动作,它们被当做一个单独的工作单元.这些动作要么全部完成,要么全部不起作用 事务的四个关键属性 原子性 一致性 隔离性 持久性 Spring两 ...

  7. python学习笔记09--线程、进程

    本节内容 一.进程与线程的概念 1.1进程 1.2线程 1.3进程与线程的区别 二.线程 2.1启一个线程 2.2线程的2种调用方式 2.3 join 2.4 守护线程Daemon 2.5线程锁 2. ...

  8. WEB性能测试用例设计

    性能测试用例主要分为预期目标用户测试,用户并发测试,疲劳强度与大数据量测试,网络性能测试,服务器性能测试五大部分,具体编写测试用例时要根据实际情况进行裁减,在项目应用中遵守低成本,策略为中心,裁减,完 ...

  9. day38 14-Spring的Bean的属性的注入:集合属性的注入

    集合:List.Set.Map. package cn.itcast.spring3.demo6; import java.util.List; import java.util.Map; impor ...

  10. 无线传感网络协议——Smart Mesh IP

    前言: SmartMesh IP 专为实现 IP 兼容性而设计,并基于 6LoWPAN 和 802.15.4e 标准.SmartMesh IP 产品线实现了网络适应性.可靠性和可扩展性水平,并拥有高级 ...