使用epoll实现简单的服务器
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实现简单的服务器的更多相关文章
- Linux 用epoll实现的简单http服务器
Linux 用epoll实现的简单http服务器 main.c #include <stdio.h> #include <sys/types.h> #include <s ...
- C#中使用Socket实现简单Web服务器
上一篇博客中介绍了怎样使用socket访问web服务器.关键有两个: 熟悉Socket编程: 熟悉HTTP协议. 上一篇主要是通过socket来模拟浏览器向(任何)Web服务器发送(HTTP)请求,重 ...
- 用nodejs搭建一个简单的服务器
使用nodejs搭建一个简单的服务器 nodejs优点:性能高(读写文件) 数据操作能力强 官网:www.nodejs.org 验证是否安装成功:cmd命令行中输入node -v 如果显示版本号表示安 ...
- 初学Node(六)搭建一个简单的服务器
搭建一个简单的服务器 通过下面的代码可以搭建一个简单的服务器: var http = require("http"); http.createServer(function(req ...
- 搭建无限制权限的简单git服务器使用git-daemon脚本
如果想要用ubantu架设无限制权限(即不适用gitosis)的简单git服务器,实现git库下载clone,push等简单的基本功能, 可以直接使用git-daemon脚本(非常不安全,建议项目代码 ...
- 运用socket实现简单的服务器客户端交互
Socket解释: 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. Socket的英文原义是“孔”或“插座”.作为BSD UNIX的进程通信机制,取后一种意 ...
- Ubuntu 14.04搭建简单git服务器
/****************************************************************************** * Ubuntu 14.04搭建简单gi ...
- tomcat解析之简单web服务器(图)
链接地址:http://gogole.iteye.com/blog/587163 之前有javaeyer推荐了一本书<how tomcat works>,今天晚上看了看,确实不错,第一眼就 ...
- Linux 下 简单客户端服务器通讯模型(TCP)
原文:Linux 下 简单客户端服务器通讯模型(TCP) 服务器端:server.c #include<stdio.h> #include<stdlib.h> #include ...
随机推荐
- node学习记录之res,req处理方法
上一篇中,我们讲述了怎么去用node搭建一个服务器环境,然后设置路由 在路由中我们用了一些方法,req.query("id") , res.end() , res.send()这三 ...
- Eclipse安装Spket插件
Eclipse安装Spket插件 1.在线安装,地址:Spket - http://www.agpad.com/update 2.下载插件包安装, 地址:http://www.spket.com/
- 数据库----SQL基本查询
SQL基本查询 查表 :show create table 表名(show tables); describe 表名:(desc 表名)// 模糊查询:show table like '%c%';(查 ...
- 集训队日常训练20180518-DIV2
A.3232 n个物品,换取要花积分,问刚好花完积分能换最大多少价值的物品. 多重背包. #include <bits/stdc++.h> using namespace std; ]; ...
- Leetcode599.Minimum Index Sum of Two Lists
假设Andy和Doris想在晚餐时选择一家餐厅,并且他们都有一个表示最喜爱餐厅的列表,每个餐厅的名字用字符串表示. 你需要帮助他们用最少的索引和找出他们共同喜爱的餐厅. 如果答案不止一个,则输出所有答 ...
- 用Python的pandas框架操作Excel文件中的数据教程
用Python的pandas框架操作Excel文件中的数据教程 本文的目的,是向您展示如何使用pandas 来执行一些常见的Excel任务.有些例子比较琐碎,但我觉得展示这些简单的东西与那些你可以在其 ...
- CEF 框架使用集锦
CEF 框架使用集锦: 参考:〓https://github.com/NetDimension/NanUI/wiki/%E5%BC%80%E5%A7%8B%E4%BD%BF%E7%94%A8NanUI ...
- php 简单加密解密
<?php namespace App\Service; /* * @link http://kodcloud.com/ * @author warlee | e-mail:kodcloud@q ...
- python变量、变量属性
1.简述执行Python程序的两种方式以及他们的优缺点 答:交互型优点:马上就能看到结果,排错方便.交互型缺点:代码无法保存,断电即消失 命令型优点:代码永久保存.命令型缺点:不易排错 2.简述Pyt ...
- 官方支持的全新版Neo4j-JDBC驱动3.0
原文:The All-New, Officially Supported Neo4j-JDBC Driver 3.0 作者: Michael Hunger 译者:仲培艺,关注数据库领域,纠错.寻求报道 ...