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. hdu 5706 GirlCat(BFS)

    As a cute girl, Kotori likes playing ``Hide and Seek'' with cats particularly. Under the influence o ...

  2. 1046 Shortest Distance

    题意:给出一个环和结点之间的距离,求任意两结点之间的最近距离.如图: 思路:令数组dis[i]表示1号结点逆时针至i号结点的距离,初始化dis[1]=0,其他值在输入是确定,即 dis[i] 0 1 ...

  3. PHP函数htmlspecialchars_decode

    htmlspecialchars_decode() 函数把一些预定义的 HTML 实体转换为字符. <?php $str = "This is some <b>bold&l ...

  4. thinkphp实现多个子查询语句

    sql语句博大精深 理解好sql语句,就能用好thinkphp等框架中的数据库操作 原sql SELECT a.*,b.* from (SELECT a.id as opener_id,a.name, ...

  5. Oracle里的执行计划

    1 执行计划的查看 1 explan plan 2 dbms_xplan包 3 sqlplus中 set autot 4 10046 5 awr报告 6一些现成的脚本 7 10053 常见的就前4种 ...

  6. java成神之——Fork/Join基本使用

    Fork/Join 大任务分小任务,小任务结果合并 ForkJoinPool pool = new ForkJoinPool(); RecursiveTask<Integer> task1 ...

  7. 用CSS使图片上下左右都绝对居中于DIV

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. nat123软件windows版

    转自:http://www.nat123.com/pages_8_565.jsp 同时支持内网和公网IP.只要可以上网,即可将所有应用发布外网. >>nat123客户端windows版本软 ...

  9. ResponseUtil

    package util; import java.io.OutputStream; import java.io.PrintWriter; import javax.servlet.http.Htt ...

  10. Vulkan Tutorial 04 理解Validation layers

    操作系统:Windows8.1 显卡:Nivida GTX965M 开发工具:Visual Studio 2017 What are validation layers? Vulkan API的设计核 ...