unix网络编程 str_cli epoll 非阻塞版本
unix网络编程 str_cli epoll 非阻塞版本
unix网络编程str_cli使用epoll实现讲了使用epoll配合阻塞io来实现str_cli,这个版本是配合非阻塞io.
可以看到采用非阻塞io以后复杂度大大提升了. 这个版本是在原书select版本基础之上修改而来,可以看出epoll又比select版本复杂了很多,每次都需要调用epoll_ctl三次,效率肯定比select还低.
存在一个问题!!就是epoll_wait对于重定向的stdin,始终阻塞,不晓得什么原因,以后再研究吧!
因为不能重定向stdin所以也不能测试性能,只能说是可以工作.
/* include nonb1 */
#include "../lib/unp.h"
#include <sys/epoll.h>
//epoll 非阻塞io, 采用了非阻塞io以后性能得到大幅提升,但是复杂度也飞速提升。
//确保events有足够的空间,这里足够了
//添加一个事件到队列中,可能会改变数组中的epoll_event数量。
static uint32_t addEvents(struct epoll_event * events,uint32_t nfds,int fd,uint32_t event){
int i=0;
for(i=0;i<nfds;i++){
if(events[i].data.fd==fd){
events[i].events|=event;
}
}
if(i==nfds){
events[i].data.fd=fd;
events[i].events=event;
nfds++;
}
return nfds;
}
#define VOL2
void str_cli(FILE *fp, int sockfd)
{
int val,stdineof=0;
ssize_t n, nwritten;
char to[MAXLINE], fr[MAXLINE];
char *toiptr, *tooptr, *friptr, *froptr;
struct epoll_event event;
struct epoll_event events[20];
int i,efd,nfds;
int noevent=0;
val = Fcntl(sockfd, F_GETFL, 0);
Fcntl(sockfd, F_SETFL, val | O_NONBLOCK);
val = Fcntl(STDIN_FILENO, F_GETFL, 0);
Fcntl(STDIN_FILENO, F_SETFL, val | O_NONBLOCK);
val = Fcntl(STDOUT_FILENO, F_GETFL, 0);
Fcntl(STDOUT_FILENO, F_SETFL, val | O_NONBLOCK);
toiptr = tooptr = to; /* initialize buffer pointers */
friptr = froptr = fr;
stdineof = 0;
efd = epoll_create (10);
if(efd<0){
err_sys("epoll create failed");
}
event.data.fd=fileno(fp);
event.events=EPOLLIN;
epoll_ctl(efd,EPOLL_CTL_ADD,fileno(fp),&event);
event.data.fd=sockfd;
event.events=EPOLLIN;
epoll_ctl(efd,EPOLL_CTL_ADD,sockfd,&event);
event.data.fd=STDOUT_FILENO;
event.events=EPOLLOUT;
epoll_ctl(efd,EPOLL_CTL_ADD,STDOUT_FILENO,&event);
for ( ; ; ) {
event.data.fd = fileno(fp);
event.events = 0;
//fprintf(stderr, "tooptr=0x%x,toiptr=0x%x,froptr=0x%x,friptr=0x%x \n", tooptr, toiptr, froptr, friptr);
if (stdineof == 0 && toiptr < &to[MAXLINE]) //并不能确定在不在里面,多做一次不是坏事
{
event.events = EPOLLIN;
epoll_ctl(efd, EPOLL_CTL_MOD, fileno(fp), &event); //read from stdin
}
else
epoll_ctl(efd, EPOLL_CTL_MOD, fileno(fp), &event);
event.data.fd = sockfd;
event.events = 0;
if (friptr < &fr[MAXLINE])
event.events |= EPOLLIN; /* read from socket */
if (tooptr != toiptr)
event.events |= EPOLLOUT; /* data to write to socket */
epoll_ctl(efd, EPOLL_CTL_MOD, sockfd, &event);
event.data.fd = STDOUT_FILENO;
event.events = 0;
if (froptr != friptr) {
event.events = EPOLLOUT;
epoll_ctl(efd, EPOLL_CTL_MOD, STDOUT_FILENO, &event); /* data to write to stdout */
}
else {
epoll_ctl(efd, EPOLL_CTL_MOD, STDOUT_FILENO, &event);
}
nfds = epoll_wait(efd, events, sizeof(events) / sizeof(struct epoll_event), -1);
//fprintf(stderr, "nfds return:%d, %d,0x%x,sockfd=%d\n", nfds, events[0].data.fd, events[0].events, sockfd);
startloop:
for (i = 0; i < nfds; i++) {
if (events[i].data.fd == STDIN_FILENO && events[i].events != 0) {
events[i].events = 0; //清除处理过的事件
if ((n = read(STDIN_FILENO, toiptr, &to[MAXLINE] - toiptr)) < 0) {
if (errno != EWOULDBLOCK)
err_sys("read error on stdin");
} else if (n == 0) {
#ifdef VOL2
fprintf(stderr, "%s: EOF on stdin\n", gf_time());
#endif
stdineof = 1; /* all done with stdin */
if (tooptr == toiptr)
Shutdown(sockfd, SHUT_WR);/* send FIN */
} else {
#ifdef VOL2
fprintf(stderr, "%s: read %d bytes from stdin\n", gf_time(), n);
#endif
toiptr += n; /* # just read */
int ret2=addEvents(events, nfds, sockfd, EPOLLOUT);
if(ret2!=nfds){
nfds=ret2;
goto startloop;
}
}
}
if (events[i].data.fd == sockfd && events[i].events != 0) {
if (events[i].events & EPOLLIN) {
printf("read socket\n");
if ((n = read(sockfd, friptr, &fr[MAXLINE] - friptr)) < 0) {
printf("read socket error");
if (errno != EWOULDBLOCK)
err_sys("read error on socket");
} else if (n == 0) {
#ifdef VOL2
fprintf(stderr, "%s: EOF on socket\n", gf_time());
#endif
if (stdineof)
return; /* normal termination */
else
err_quit("str_cli: server terminated prematurely");
} else {
#ifdef VOL2
fprintf(stderr, "%s: read %d bytes from socket\n",
gf_time(), n);
#endif
friptr += n; /* # just read */
int ret2 = addEvents(events, nfds, STDOUT_FILENO, EPOLLOUT);/* try and write for next loop */
if(ret2!=nfds){
nfds=ret2;
events[i].events&=~EPOLLIN; //清除已经处理过的in事件
goto startloop;
}
}
}
if (events[i].events & EPOLLOUT) {
if ((n = toiptr - tooptr) > 0) {
if ((nwritten = write(sockfd, tooptr, n)) < 0) {
if (errno != EWOULDBLOCK)
err_sys("write error to socket");
} else {
#ifdef VOL2
fprintf(stderr, "%s: wrote %d bytes to socket\n",
gf_time(), nwritten);
#endif
tooptr += nwritten; /* # just written */
if (tooptr == toiptr) {
toiptr = tooptr = to; /* back to beginning of buffer */
if (stdineof)
Shutdown(sockfd, SHUT_WR); /* send FIN */
}
}
}
}
events[i].events = 0; //清除处理过的事件
}
if (events[i].data.fd == STDOUT_FILENO) {
if ((n = friptr - froptr) > 0) {
if ((nwritten = write(STDOUT_FILENO, froptr, n)) < 0) {
if (errno != EWOULDBLOCK)
err_sys("write error to stdout");
} else {
#ifdef VOL2
fprintf(stderr, "%s: wrote %d bytes to stdout\n",
gf_time(), nwritten);
#endif
froptr += nwritten; /* # just written */
if (froptr == friptr)
froptr = friptr = fr; /* back to beginning of buffer */
}
}
}
}
}
}
unix网络编程 str_cli epoll 非阻塞版本的更多相关文章
- unix网络编程str_cli使用epoll实现
unix网络编程str_cli使用epoll实现 unix环境高级编程中也有这个函数,都是为了讲解IO多路转接.从本质上来看epoll就是一个改善了的select和poll,本质没发生任何变化,对于构 ...
- Linux 网络编程七(非阻塞socket:epoll--select)
阻塞socket --阻塞调用是指调用结果返回之前,当前线程会被挂起.函数只有在得到结果之后才会返回. --对于文件操作 read,fread函数调用会将线程阻塞(平常使用read感觉不出来阻塞, 因 ...
- UNIX网络编程——非阻塞connect:时间获取客户程序
#include "unp.h" int connect_nonb(int sockfd, const SA *saptr, socklen_t salen, int nsec) ...
- UNIX网络编程——epoll 的accept , read, write(重要)
在一个非阻塞的socket上调用read/write函数,返回EAGAIN或者EWOULDBLOCK(注:EAGAIN就是EWOULDBLOCK). 从字面上看,意思是: EAGAIN: 再试一次 E ...
- 《Unix 网络编程》14:高级 I/O 函数
高级 I/O 函数 ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ...
- 【unix网络编程第三版】阅读笔记(五):I/O复用:select和poll函数
本博文主要针对UNP一书中的第六章内容来聊聊I/O复用技术以及其在网络编程中的实现 1. I/O复用技术 I/O多路复用是指内核一旦发现进程指定的一个或者多个I/O条件准备就绪,它就通知该进程.I/O ...
- UNIX网络编程——并发服务器(TCP)
在迭代服务器中,服务器只能处理一个客户端的请求,如何同时服务多个客户端呢?在未讲到select/poll/epoll等高级IO之前,比较老土的办法是使用fork来实现. 网络服务器通常用fork来同时 ...
- 网络IO-阻塞、非阻塞、IO复用、异步
网络socket输入操作分为两个阶段:等待网络数据到达和将到达内核的数据复制到应用进程缓冲区.对这两个阶段不同的处理方式将网络IO分为不同的模型:IO阻塞模型.非阻塞模型.多路复用和异步IO. 一 阻 ...
- Unix网络编程--卷一:套接字联网API
UNIX网络编程--卷一:套接字联网API 本书面对的读者是那些希望自己编写的程序能够使用成为套接字(socket)的API进行彼此通信的人. 目录: 0.准备环境 1.简介 2.传输层:TCP.UD ...
随机推荐
- Tair ldb(leveldb存储引擎)实现介绍
简介 tair 是淘宝自己开发的一个分布式 key/value 存储引擎. tair 分为持久化和非持久化两种使用方式. 非持久化的 tair 可以看成是一个分布式缓存. 持久化的 tair 将数据存 ...
- 阿里云openapi接口使用,PHP,视频直播
1.下载sdk放入项目文件夹中 核心就是aliyun-php-sdk-core,它的配置文件会自动加载相应的类 2.引入文件 include_once LIB_PATH . 'ORG/aliyun-o ...
- maven项目依赖包问题
问题 maven传递依赖 解决方案 前段时间,开发中遇到一个关于maven依赖包的问题:由于业务需要,支付网关对账代码中的slf4j-api包需要更新,原包为1.5.8版本,需要更新到1.6.4版 ...
- js中,清空对象(删除对象的属性)
在项目中,有些对象用完后需要重置,下面简单介绍下JS中清除对象的方法.方法如下: 方法一:字面量定义对象 第一步,定义一个空对象并打印出来,代码和效果: 代码: var student = {};co ...
- 并发模型(一)——Future模式
多线程开发可以更好的发挥多核cpu性能,常用的多线程设计模式有:Future.Master-Worker.Guard Susperionsion.不变.生产者-消费者 模式: jdk除了定义了若干并发 ...
- 一.volatile关键字
一.volatile关键字的原理 使用volatile关键字增加了实例变量在多个线程之间的可见性.但volatile的最致命的缺点是不支持原子性. synchronized代码块具有volatile同 ...
- Betsy's Tour 漫游小镇(dfs)
Description 一个正方形的镇区分为 N2 个小方块(1 <= N <= 7).农场位于方格的左上角,集市位于左下角.贝茜穿过小镇,从左上角走到左下角,刚好经过每个方格一次.当 N ...
- axis调用webservice客户端开发
第一步:wsdl2Java.bat文件编写 Axis_Lib表示依赖的jar包路径 Output_Path表示生成的class路径 Package包名 还需要手动更改 -p %Package%表示we ...
- POJ1012(约瑟夫问题)
1.题目链接地址 http://poj.org/problem?id=1012 2k个人,前面k个是好人,后面k个是坏人,找一个数t,每数到第t时就去掉,使所有坏人在好人之前被杀掉. 思路:约瑟夫公式 ...
- 虚拟机安装CentOS以及SecureCRT设置【完美无错版】
一.CentOS简介 CentOS是Linux的发行版之一,它安全.稳定.高效,是我最喜欢的Linux发行版之一.CentOS根据Red Hat Enterprise Linux开放源代码编译而成,与 ...