#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/epoll.h> #include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h> #include <vector>
#include <algorithm>
#include <iostream> typedef std::vector<struct epoll_event> EventList; #define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while() int main(void)
{
// TCP是全双工的信道, 可以看作两条单工信道, TCP连接两端的两个端点各负责一条. 当对端调用close时, 虽然本意是关闭整个两条信道,
// 但本端只是收到FIN包. 按照TCP协议的语义, 表示对端只是关闭了其所负责的那一条单工信道, 仍然可以继续接收数据. 也就是说, 因为TCP协议的限制,
// 一个端点无法获知对端的socket是调用了close还是shutdown.
// 对一个已经收到FIN包的socket调用read方法,
// 如果接收缓冲已空, 则返回0, 这就是常说的表示连接关闭. 但第一次对其调用write方法时, 如果发送缓冲没问题, 会返回正确写入(发送).
// 但发送的报文会导致对端发送RST报文, 因为对端的socket已经调用了close, 完全关闭, 既不发送, 也不接收数据. 所以,
// 第二次调用write方法(假设在收到RST之后), 会生成SIGPIPE信号, 导致进程退出.
// 为了避免进程退出, 可以捕获SIGPIPE信号, 或者忽略它, 给它设置SIG_IGN信号处理函数:
// 这样, 第二次调用write方法时, 会返回-1, 同时errno置为SIGPIPE. 程序便能知道对端已经关闭.
signal(SIGPIPE, SIG_IGN);//防止进程退出
//忽略SIGCHLD信号,这常用于并发服务器的性能的一个技巧
//因为并发服务器常常fork很多子进程,子进程终结之后需要
//服务器进程去wait清理资源。如果将此信号的处理方式设为
//忽略,可让内核把僵尸子进程转交给init进程去处理,省去了
//大量僵尸进程占用系统资源。(Linux Only)
signal(SIGCHLD, SIG_IGN); int idlefd = open("/dev/null", O_RDONLY | O_CLOEXEC);
int listenfd;
//if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
if ((listenfd = socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP)) < )
ERR_EXIT("socket"); struct sockaddr_in servaddr;
memset(&servaddr, , sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons();
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); int on = ;
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < )
ERR_EXIT("setsockopt"); if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < )
ERR_EXIT("bind");
if (listen(listenfd, SOMAXCONN) < )
ERR_EXIT("listen"); //create epoll object
int epollfd;
epollfd = epoll_create1(EPOLL_CLOEXEC); //add EPOLLIN event to epoll
struct epoll_event event;
event.data.fd = listenfd;
event.events = EPOLLIN/* | EPOLLET*/;
epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &event); EventList events();
struct sockaddr_in peeraddr;
socklen_t peerlen;
int connfd; std::vector<int> clients; int nready;
while ()
{
//return active event
nready = epoll_wait(epollfd, &*events.begin(), static_cast<int>(events.size()), -);
if (nready == -)
{
if (errno == EINTR)
continue; ERR_EXIT("epoll_wait");
}
if (nready == ) // nothing happended
continue; //double capacity
if ((size_t)nready == events.size())
events.resize(events.size()*); //treat all active event
for (int i = ; i < nready; ++i)
{
//如果是主socket的事件的话,则表示有新连接进入了,进行新连接的处理
if (events[i].data.fd == listenfd)
{
peerlen = sizeof(peeraddr);
connfd = ::accept4(listenfd, (struct sockaddr*)&peeraddr,
&peerlen, SOCK_NONBLOCK | SOCK_CLOEXEC); if (connfd == -)
{
//防止文件句柄超过最大数量
if (errno == EMFILE)
{
close(idlefd);
idlefd = accept(listenfd, NULL, NULL);
close(idlefd);
idlefd = open("/dev/null", O_RDONLY | O_CLOEXEC);
continue;
}
else
ERR_EXIT("accept4");
} std::cout<<"ip="<<inet_ntoa(peeraddr.sin_addr)<<
" port="<<ntohs(peeraddr.sin_port)<<std::endl; clients.push_back(connfd); event.data.fd = connfd;
event.events = EPOLLIN/* | EPOLLET*/;
epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &event);
}
else if (events[i].events & EPOLLIN)
{
connfd = events[i].data.fd;
if (connfd < )
continue; char buf[] = {};
int ret = read(connfd, buf, );
if (ret == -)
ERR_EXIT("read");
if (ret == )
{
std::cout<<"client close"<<std::endl;
close(connfd);
event = events[i];
epoll_ctl(epollfd, EPOLL_CTL_DEL, connfd, &event);
clients.erase(std::remove(clients.begin(), clients.end(), connfd), clients.end());
continue;
} std::cout<<buf;
write(connfd, buf, strlen(buf));
} }
} return ;
}

服务器二:epoll的更多相关文章

  1. Android 上传图片到服务器二--------调用相机7.0以上权限问题

    [目录] (一)上传图片到服务器一 ---------------------------------Android代码 (二)上传图片到服务器二--------------------------- ...

  2. 【转】配置Exchange 2010 服务器(二)Exchange2010证书配置

    原文链接:http://blog.51cto.com/shubao/788562 (一)架设证书服务器 (二)Exchange2010申请证书 (三)证书服务器导入Exchange服务器受信任根证书 ...

  3. Python实现简单HTTP服务器(二)

    实现简单web框架 一.框架(MyWeb.py) # coding:utf-8 import time # 设置静态文件根目录 HTML_ROOT_DIR = "./html" c ...

  4. 从零开始一个http服务器(二)-请求request解析

    从零开始一个http服务器 (二) 代码地址 : https://github.com/flamedancer/cserver git checkout step2 解析http request 观察 ...

  5. JavaWeb(三)——Tomcat服务器(二)

    一.打包JavaWeb应用 在Java中,使用"jar"命令来对将JavaWeb应用打包成一个War包,jar命令的用法如下:

  6. Netty构建游戏服务器(二)--Hello World

    一,准备工作 1,netty-all-4.1.5.Final.jar(官网下载) 2,eclipse 二,步骤概要 1,服务器开发 (1),创建Server类 该类是程序的主入口,有main方法,服务 ...

  7. 18 11 27 高级的服务器连接 epoll

    ---恢复内容开始--- 之前的  http 服务器  都是采用 轮询的方式(就像 厨师挨个问谁饿了好做饭 一样  ) 而  epoll 用着高级的 方式  事件通知 (直接问谁饿了) 同时还和  计 ...

  8. Tornado WEB服务器框架 Epoll

    引言: 回想Django的部署方式 以Django为代表的python web应用部署时采用wsgi协议与服务器对接(被服务器托管),而这类服务器通常都是基于多线程的,也就是说每一个网络请求服务器都会 ...

  9. 搭建windows的solr6服务器(二)

    首先搭建solr环境,如:solr6.0学习(一)环境搭建 修改各种配置文件. 1.修改solrhome下的solr.xml文件 注解掉zookeeper搭建集群配置,我们后面会采用master-sl ...

随机推荐

  1. link/Extended dependency 无法显示连接

    把矩形控件先去掉,然后就能看到表与表之间的 link/Extended dependency 连线了.

  2. 基础测试jmeter5.0+badboy(从小白到入门)

    1]测试工具jmeter环境安装 1.1]安装jdk环境 1:必须安装jdk8.0(我尝试安装最新版本不行,好像当时没有配置好.之后安装8.0遍可以正常运行)下载地址:单击此段 配置jdk环境:鼠标右 ...

  3. [PHP]实体类基类和序列化__sleep问题

    1.构造函数传参2.__get和__set实现,当调用不存在的属性的时候,可以取值和赋值到data属性数组3.__sleep实现,当序列化对象的时候,只序列化data属性数组和类内初始化定义的字段4. ...

  4. Java_基础篇(数组的反转)

    数组反转也是Java的基础. 数组反转要求掌握的是: 1).创建一个数组,在内存中申请一块空间. 2).实例化数组. 3).对数组的了解.如:数组的长度,数组的下标,数组的表示方法. 4).数组的交换 ...

  5. ReactiveSwift源码解析(五) SignalProtocol的observe()、Map、Filter延展实现

    上篇博客我们对Signal的基本实现以及Signal的面向协议扩展进行了介绍, 详细内容请移步于<Signal中的静态属性静态方法以及面向协议扩展>.并且聊了Signal的所有的g功能扩展 ...

  6. 使用前端技术和MySQL+PHP制作自己的一个个人博客网站

    源代码地址:https://github.com/YauCheun/BlogCode 我的博客网站地址:http://www.yublog.fun/ 制作前景: 想拥有一个自己独自开发的一个小型博客网 ...

  7. 【深度学习】--GAN从入门到初始

    一.前述 GAN,生成对抗网络,在2016年基本火爆深度学习,所有有必要学习一下.生成对抗网络直观的应用可以帮我们生成数据,图片. 二.具体 1.生活案例 比如假设真钱 r 坏人定义为G  我们通过 ...

  8. linux 下搭建php环境

    linux 下搭建php环境 1.下载apache (http://httpd.apache.org/download.cgi) 下载php组件 ( http://cn2.php.net/get/ph ...

  9. 【重学计算机】计组D1章:计算机系统概论

    1.冯诺依曼计算机组成 主机(cpu+内存),外设(输入设备+输出设备+外存),总线(地址总线+数据总线+控制总线) 2.计算机层次结构 应用程序-高级语言-汇编语言-操作系统-指令集架构层-微代码层 ...

  10. windows系统下用python更新svn和Git

    转载请标明出处:http://www.cnblogs.com/zblade/ 最近在思考怎么实现python的一键打包,利用python的跨平台特性,可以实现在windows和mac下均可执行的特点. ...