#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. Hive使用必知必会系列

    一.Hive的几种数据模型 内部表 (Table 将数据保存到Hive 自己的数据仓库目录中:/usr/hive/warehouse) 外部表 (External Table 相对于内部表,数据不在自 ...

  2. 在Unity中实现小地图(Minimap)

    小地图的基本概念众所周知,小地图(或雷达)是用于显示周围环境信息的.首先,小地图是以主角为中心的.其次,小地图上应该用图标来代替真实的人物模型,因为小地图通常很小,玩家可能无法看清真实的模型.大多数小 ...

  3. PageHelper分页异常(java.base/java.util.ArrayList cannot be cast to com.github.pagehelper.Page)

    在SqlMapConfig.xml里面配置分页插件 applicationContext-service.xml里面的配置,我出现问题谁因为,在salSessionFactory里没注入全局配置文件

  4. 折腾Java设计模式之解释器模式

    解释器模式 解释器模式是类的行为模式.给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器.客户端可以使用这个解释器来解释这个语言中的句子. 意图 给定一个语言,定义它的文法表 ...

  5. Git - git branch - 查看远端所有分支

    索引: 目录索引 一.示例: git branch -r 二.说明: 该命令将列出仓库中所有存在的远端分支,无论该分支是否已签出到本地. 蒙 2018-09-29 19:59 周六

  6. window下的nginx的安装和使用

    nginx功能之一可以启动一个本地服务器,通过配置server_name和root目录等来访问目标文件 一. 下载 http://nginx.org/en/download.html 下载后安装在你钟 ...

  7. Ubuntu 安装php+mysql+nginx

    0x01 安装PHP https://blog.csdn.net/Msmile_my/article/details/73647809   1.添加php的仓库 sudo apt-get instal ...

  8. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十八║Vue基础: 指令(下)+计算属性+watch

    回顾 今天来晚辣,给公司做了一个小项目,一个瀑布流+动态视频控制的DEMO,有需要的可以联系我,公司的项目就不对外展示了(一个后端程序员真的要干前端了哈哈哈). 书接上文,昨天正式的开始了Vue的代码 ...

  9. 【TensorFlow篇】--Tensorflow框架初始,实现机器学习中多元线性回归

    一.前述 TensorFlow是谷歌基于DistBelief进行研发的第二代人工智能学习系统,其命名来源于本身的运行原理.Tensor(张量)意味着N维数组,Flow(流)意味着基于数据流图的计算,T ...

  10. 【Spark篇】---SparkSql之UDF函数和UDAF函数

    一.前述 SparkSql中自定义函数包括UDF和UDAF UDF:一进一出  UDAF:多进一出 (联想Sum函数) 二.UDF函数 UDF:用户自定义函数,user defined functio ...