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 非阻塞版本的更多相关文章

  1. unix网络编程str_cli使用epoll实现

    unix网络编程str_cli使用epoll实现 unix环境高级编程中也有这个函数,都是为了讲解IO多路转接.从本质上来看epoll就是一个改善了的select和poll,本质没发生任何变化,对于构 ...

  2. Linux 网络编程七(非阻塞socket:epoll--select)

    阻塞socket --阻塞调用是指调用结果返回之前,当前线程会被挂起.函数只有在得到结果之后才会返回. --对于文件操作 read,fread函数调用会将线程阻塞(平常使用read感觉不出来阻塞, 因 ...

  3. UNIX网络编程——非阻塞connect:时间获取客户程序

    #include "unp.h" int connect_nonb(int sockfd, const SA *saptr, socklen_t salen, int nsec) ...

  4. UNIX网络编程——epoll 的accept , read, write(重要)

    在一个非阻塞的socket上调用read/write函数,返回EAGAIN或者EWOULDBLOCK(注:EAGAIN就是EWOULDBLOCK). 从字面上看,意思是: EAGAIN: 再试一次 E ...

  5. 《Unix 网络编程》14:高级 I/O 函数

    高级 I/O 函数 ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ★ ...

  6. 【unix网络编程第三版】阅读笔记(五):I/O复用:select和poll函数

    本博文主要针对UNP一书中的第六章内容来聊聊I/O复用技术以及其在网络编程中的实现 1. I/O复用技术 I/O多路复用是指内核一旦发现进程指定的一个或者多个I/O条件准备就绪,它就通知该进程.I/O ...

  7. UNIX网络编程——并发服务器(TCP)

    在迭代服务器中,服务器只能处理一个客户端的请求,如何同时服务多个客户端呢?在未讲到select/poll/epoll等高级IO之前,比较老土的办法是使用fork来实现. 网络服务器通常用fork来同时 ...

  8. 网络IO-阻塞、非阻塞、IO复用、异步

    网络socket输入操作分为两个阶段:等待网络数据到达和将到达内核的数据复制到应用进程缓冲区.对这两个阶段不同的处理方式将网络IO分为不同的模型:IO阻塞模型.非阻塞模型.多路复用和异步IO. 一 阻 ...

  9. Unix网络编程--卷一:套接字联网API

    UNIX网络编程--卷一:套接字联网API 本书面对的读者是那些希望自己编写的程序能够使用成为套接字(socket)的API进行彼此通信的人. 目录: 0.准备环境 1.简介 2.传输层:TCP.UD ...

随机推荐

  1. composer 发布自己的开源软件

    首先创建一个github项目. 在项目中,创建一个composer.json文件. { "name": "jiqing9006/valid", "de ...

  2. Linux平台总线驱动设备模型

    platform总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver.Linux 2.6的设备驱动模型中,把I2C.RTC.LCD等都归纳为pl ...

  3. 解决:An internal error occurred during: "Launching New_configuration". Path for project must have only one segment.

    问题: 点击运行时eclipse报错如下: An internal error occurred during: "Launching New_configuration". Pa ...

  4. 0004-程序流程2之ui-router大意

    按照传统的操作方式,一般是点击某个按钮或者某个菜单项,我们将页面通过指定URL的方式跳转, 在HTML中,使用的是传统的a标签的href属性作跳转,在使用ui-router的情况下,我们对一个按钮 添 ...

  5. Canopy聚类算法

    Canopy聚类算法(经典,看图就明白) 聚类算法. 这个算法获得的并不是最终结果,它是为其他算法服务的,比如k-means算法.它能有效地降低k-means算法中计算点之间距离的复杂度. 图中有一个 ...

  6. 1.3Broker

    Celery需要一种解决消息的发送和接受的方式,我们把这种用来存储消息的的中间装置叫做message broker, 也可叫做消息中间人. 作为中间人,我们有几种方案可选择: 1.RabbitMQ R ...

  7. Oracle11gR2_ADG管理之恢复主库的truncate表实战

    备库开启flashback database #关闭备库的同步 SQL> alter database recover managed standby database cancel; Data ...

  8. MySQL高可用MHA实战

    MySQL高可用架构MHA介绍 简介: MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本DeNA公司youshimaton(现就职 ...

  9. JQuery实现瀑布流页面

    views.py from django.shortcuts import render,HttpResponse from app01 import models import json # Cre ...

  10. 浅谈块元素绝对定位的margin属性

    对于div的绝对定位一直以为margin属性是无效的,只是通过top,left,bottom,right定位,然而今天的却发现不是这样的,于是对其做了些实验: 使用的HTML原始测试文件: <! ...