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 ...
随机推荐
- java中求输入一个数,并计算其平方根~~~
总结:函数 Math.pow(x,0.5); package com.badu; import java.util.Scanner; // 输入一个数,并计算出平方根 public class AA ...
- mysql实战优化之三:表优化
对于大多数的数据库引擎来说,硬盘操作可能是最重大的瓶颈.所以,把你的数据变得紧凑会对这种情况非常有帮助,因为这减少了对硬盘的访问. 如果一个表只会有几列罢了(比如说字典表,配置表),那么,我们就没有理 ...
- 二 mysql容量规划,性能测试
何为基线- 当前运行状态记录.快照- 用于和未来的状态进行对比- 未来时刻产生关键事件后的新状态,作为下一个基线基线数据收集,关注哪些要点- 系统负载- MySQL运行状态- 相应的业务指标1.系统& ...
- 事件调度器及C++中的使用
转自:http://blog.ch-wind.com/ue4-event-dispatcher-and-delegate/ 事件调度器非常的适合在各个蓝图之间实现通信功能. 当前UE4版本4.8.3. ...
- js(react.js) button click 事件无法触发
今天遇到一个诡异的问题.button 上的点击事件触发不了. 找个几个小时,原因是 js 报错了. <Button type="primary" htmlType=" ...
- VirtualBox 桥接
1.设置Virtual box,取消DHCP服务 管理->全局设定->网络->Host-Only->网络明细->DHCP服务器->启用服务器选项取消 2.宿机设置 ...
- Linux批量“解压”JAR文件
当你需要”解压“很多jar文件时,可以通过很多方式进行,比如下面这种 1,列出每一个jar文件名,逐个展开 for i in $(ls *sour*.jar);do jar xvf $i;done
- Django中favicon.ico文件的配置
默认情况下,浏览器访问一个网站的时候,同时还会向服务器请求“/favicon.ico”这个URL,目的是获取网站的图标. 若没有配置的话,Django就会返回一个404错误,并且浏览器接收到这个404 ...
- Leetcode:ZigZag Conversion分析和实现
问题的大意就是将字符串中的字符按锯齿状(倒N形)垂直由上向下放置,最后水平从左向右读取.比如 ABCDEFGHIJKLMN,4表示 A G M B F H ...
- c++之继承与派生
再来回顾下继承派生的语法. 继承方式显示有三种(public, protected, privatez),隐式默认private.所谓继承方式,是指派生类对基类成员的访问权限控制. 派生类构造函数定义 ...