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. iframe调用父页面各种方法

    HTML: <body>    <form id="form1" runat="server">       <div> & ...

  2. python基础(输出、变量、常量、数据类型、流程控制)

    输出 print print("Hello World!") # python2 和 python3 的区别 # python2 # coding:utf-8 print 123 ...

  3. python模拟浏览器文件上传,csrf放行

    服务器端视图函数 from django.shortcuts import render,HttpResponse from django.views.decorators.csrf import c ...

  4. div代码大全 DIV代码使用说明

    一.DIV代码语法 - TOP DIV代码是放入小于与大于符号内,即“<div>”. DIV是一对闭合标签,即“”开始,“结束”的盒子标签. 语法结构: <div>我是内容&l ...

  5. centos 安装redis2.8.9

    1没有安装gcc yum install gcc-c++ 2. 安装tcl yum install -y tcl 3.安装redis $ wget http://download.redis.io/r ...

  6. day36 05-Hibernate检索方式:离线条件查询

    图二 离线条件查询 Struts 2是web层的框架.session得在dao层才有.有的时候这些数据是没在你的对象里面的.像是否上传简历.这个字段不在我的数据库里面.例如是否上传简历这个条件不在我们 ...

  7. react仿豆瓣

    最近公司在做一个自己内部的图片上传系统,目的是帮助设计人员方便上传图片,用的是vue技术,但是说到vue,可能要提到更早出来的react,react是facebook搞的一套语法糖,也是革命性的用组件 ...

  8. 深入剖析Redis RDN持久化机制

    rdb是redis保存内存数据到磁盘数据的其中一种方式(另一种是AOF).Rdb的主要原理就是在某个时间点把内存中的所有数据的快照保存一份到磁盘上.在条件达到时通过fork一个子进程把内存中的数据写到 ...

  9. 【linux配置】VMware安装Redhat6.5

    VMware安装Redhat6.5 VMware安装Redhat6.5安装之前需要一些准备工作,首先,电脑上需要安装VMware(这个是废话),其次就是需要Redhat6.5的镜像文件(现在貌似都出R ...

  10. android studio离线打包mui应用

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/foolish0421/article/details/54618754首先从官网http://www ...