使用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 ...
随机推荐
- [转]深入理解ajax系列——头部消息
每个HTTP请求和响应都会带有相应的头部信息,其中有的对开发人员有用.XHR对象提供了操作头部信息的方法.本文将详细介绍HTTP的头部信息 默认信息 默认情况下,在发送XHR请求的同时,还会发送下列头 ...
- PHP获取搜索引擎关键词
有时候我们需要知道用户通过哪个搜索引擎,通过拿个关键词访问我们页面,当然js也可以实现,这里介绍下php的实现代码,包含(百度.谷歌.雅虎.搜狗.搜搜.必应.有道)几大搜索引擎的获取方法. //获取来 ...
- 爬取简书图片(使用BeautifulSoup)
import requests from bs4 import BeautifulSoup url_list = [] kv = {'User-Agent':'Mozilla/5.0'} r = re ...
- JSON和JSONP,原来ajax引用这个来实现跨域访问的
由于Sencha Touch 2这种开发模式的特性,基本决定了它原生的数据交互行为几乎只能通过AJAX来实现. 当然了,通过调用强大的PhoneGap插件然后打包,你可以实现100%的Socket通讯 ...
- (转载)http压缩 Content-Encoding: gzip
(内容转自http://liuviphui.blog.163.com/blog/static/20227308420141843933379/) HTTP内容编码和HTTP压缩的区别 HTTP压缩,在 ...
- jmeter 通过csv data set config 设置参数化后,执行结果显示为<EOF>
通过csv data set config 设置参数化后,执行结果显示为<EOF>: 反复确认相应的参数的设置均没有问题,其中csv文件编码方式采用uft-8.在csv data set ...
- golang数组 排序和查找
package main import "fmt" func BubbleSort(arr *[5]int){ fmt.Println("排序前arr=",(* ...
- 拦截导弹 (最长上升子序列LIS)
#include <iostream> #include <stdio.h> #include <algorithm> using namespace std; ] ...
- HTML 实体字符
有些字符,像(<)这类的,对HTML来说是有特殊意义的,所以这些字符是不允许在文本中使用的.要在HTML中显示(<)这个字符,我们就必须使用实体字符. 实体字符 有一些字符对HTML来讲是 ...
- CSS:命名规范心得分享
一个好的命名习惯(当然这里指的并不仅仅是CSS命名).不仅可以提高开发效率,而且有益于后期修改和维护. 假设我们当前使用的命名方式都是约定成俗的,所有人都是这样写,那么你去到一个新团队,或者别人来接手 ...