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 ...
随机推荐
- 搭建了一个在线的机器学习webshell检测RESTful API
# 地址: http://118.190.147.89:5001/ 如果不能访问,联系sevck#jdsec.com # 说明: 简单的基于机器学习检测webshell:目前只支持php的检测 #使用 ...
- 第一章 Spring整体架构和环境搭建(待续)
········
- 委托小结及Func用法
首先,委托是一种类型,由关键字delegate声明.确切的说,委托是一种可用于封装命名或者匿名方法的引用类型. 它类似于 C++ 中的函数指针,而且是类型安全和可靠的. 委托类型的声明与 ...
- java中链表的数据(对象)位置交换
用LinkedList类的set方法把引用 对象换了就行 ,如 import java.util.LinkedList; public class Tffdsafsdafsad { public st ...
- codeforeces:Mister B and Astronomers分析和实现
题目很长,稍微翻译一下: 外星球每隔T秒中只有一秒可以被观测到,其它T-1秒无法被观测.n个天文学家(分别编号为1,...,n)轮流观测天空1秒,且第i+1个科学家在第i个天文学家后ai+1秒后才执行 ...
- Nginx配置之基于域名的虚拟主机
1.配置好DNS解析 大家好,今天我给大家讲解下在Linux系统下DNS服务器的基本架设,正向解析,反向解析,负载均衡,还有从域以及一个服务器两个域或者多个域的情况. 实验环境介绍:1.RHEL5.1 ...
- __sync_fetch_and_add系列
__sync_fetch_and_add系列一共有十二个函数,有加/减/与/或/异或/等函数的原子性操作函数,__sync_fetch_and_add,顾名思义,先fetch,然后自加,返回的是自加以 ...
- git获取网上的项目
这里是从coding.net上下载项目至本地phpstorm并配置好相关环境. 这里url地址正是项目路径.获取的地方是: 下面那个url直接复制粘贴. 自己选择一个目录,然后clone. 下面便是前 ...
- java简单的测试方法执行了多少时间
(1)以毫秒为单位的 long startTime = System.currentTimeMillis(); // 获取开始时间 // doThing(); // 测试的代码段 long endTi ...
- 665. Non-decreasing Array只允许修改一位数的非递减数组
[抄题]: Given an array with n integers, your task is to check if it could become non-decreasing by mod ...