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}elseepoll_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 VOL2fprintf(stderr, "%s: EOF on stdin\n", gf_time());
#endifstdineof = 1; /* all done with stdin */if (tooptr == toiptr)Shutdown(sockfd, SHUT_WR);/* send FIN */} else {
#ifdef VOL2fprintf(stderr, "%s: read %d bytes from stdin\n", gf_time(), n);
#endiftoiptr += 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 VOL2fprintf(stderr, "%s: EOF on socket\n", gf_time());
#endifif (stdineof)return; /* normal termination */elseerr_quit("str_cli: server terminated prematurely");} else {
#ifdef VOL2fprintf(stderr, "%s: read %d bytes from socket\n",gf_time(), n);
#endiffriptr += 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 VOL2fprintf(stderr, "%s: wrote %d bytes to socket\n",gf_time(), nwritten);
#endiftooptr += 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 VOL2fprintf(stderr, "%s: wrote %d bytes to stdout\n",gf_time(), nwritten);
#endiffroptr += nwritten; /* # just written */if (froptr == friptr)froptr = friptr = fr; /* back to beginning of buffer */}}}}}
}