Unix网络编程代码 第16章 非阻塞式I/O


Unix网络编程代码 第16章 非阻塞式I/O
2012年01月15日
   第16章 非阻塞式I/O
   16.2 非阻塞读和写:str_cli函数(修订版)
  //使用select#include/* sockaddr_in{} and other Internet defns */#include#include/* ANSI C header file */#include/* for syslog() */#include#include#include#i nclude#include#include#i nclude#include#include#defin eMAXLINE4096/* max text line length */#defineSERV_PORT 9877/* TCP and UDP */int daemon_proc;/* set nonzero by daemon_init() */#defineSAstruct sockaddr#definemax(a,b)((a) > (b) ? (a) : (b))void err_doit(int errnoflag, int level, const char *fmt, va_list ap){int errno_save, n;char buf[MAXLINE + 1];errno_save = errno;/* value caller might want printed */#ifdefHAVE_VSNPRINTFvsnprintf(buf, MAXLINE, fmt, ap);/* safe */#elsevsprintf(buf, fmt, ap);/* not safe */#endifn = strlen(buf);if (errnoflag)snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));strcat(buf, "\n");if (daemon_proc) {syslog(level, "%s", buf);} else {fflush(stdout);/* in case stdout and stderr are the same */fputs(buf, stderr);fflush(stderr);}return;}void err_quit(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(0, LOG_ERR, fmt, ap);va_end(ap);exit(1);}void err_sys(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(1, LOG_ERR, fmt, ap);va_end(ap);exit(1);}int Socket(int family, int type, int protocol){int n;if ((n = socket(family, type, protocol)) error");return (n);}void Inet_pton(int family, const char *strptr, void *addrptr){int n;if ((n = inet_pton(family, strptr, addrptr)) error for %s", strptr);/* errno set */else if (n == 0)err_quit("inet_pton error for %s", strptr);/* errno not set *//* nothing to return */}void Connect(int fd, const struct sockaddr *sa, socklen_t salen){if (connect(fd, sa, salen) error");}int Select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout){int n;do {n = select(nfds, readfds, writefds, exceptfds, timeout);if (n error");} while (n error");return (n);}void Write(int fd, void *ptr, int nbytes){if (write(fd, ptr, nbytes) != nbytes)err_sys("write error");}void Shutdown(int fd, int how){if (shutdown(fd, how) error");}int Fcntl(int fd, int cmd, int arg){int n;if ((n = fcntl(fd, cmd, arg)) == -1)err_sys("fcntl error");return (n);}char *gf_time(void){struct timeval tv;time_t t;static char str[30];char *ptr;if (gettimeofday(&tv, NULL) error");t = tv.tv_sec;/* POSIX says tv.tv_sec is time_t; some BSDs don't agree. */ptr = ctime(&t);strcpy(str, &ptr[11]);/* Fri Sep 13 00:00:00 1986\n\0 *//* 0123456789012345678901234 5 */snprintf(str + 8, sizeof(str) - 8, ".%06ld", tv.tv_usec);return (str);}void str_cli(int sockfd){int maxfdp1, val, stdineof;ssize_t n, nwritten;fd_set rset, wset;char to[MAXLINE], fr[MAXLINE];char *toiptr, *tooptr, *friptr, *froptr;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;maxfdp1 = max(max(STDIN_FILENO, STDOUT_FILENO), sockfd) + 1;for (;;) {FD_ZERO(&rset);FD_ZERO(&wset);if (stdineof == 0 && toiptr error on stdin");} else if (n == 0) {fprintf(stderr, "%s: EOF on stdin\n",gf_time());stdineof = 1;/* all done with stdin */if (tooptr == toiptr)Shutdown(sockfd, SHUT_WR);/* send FIN */} else {fprintf(stderr,"%s: read %d bytes from stdin\n",gf_time(), n);toiptr += n;/* # just read */FD_SET(sockfd, &wset);/* try and write to socket below */}}if (FD_ISSET(sockfd, &rset)) {if ((n = read(sockfd, friptr, &fr[MAXLINE] - friptr)) error on socket");} else if (n == 0) {fprintf(stderr, "%s: EOF on socket\n",gf_time());if (stdineof)return;/* normal termination */elseerr_quit ("str_cli: server terminated prematurely");} else {fprintf(stderr,"%s: read %d bytes from socket\n",gf_time(), n);friptr += n;/* # just read */FD_SET(STDOUT_FILENO, &wset);/* try and write below */}}/* end nonb2 *//* include nonb3 */if (FD_ISSET(STDOUT_FILENO, &wset) && ((n = friptr - froptr) > 0)) {if ((nwritten = write(STDOUT_FILENO, froptr, n)) error to stdout");} else {fprintf(stderr,"%s: wrote %d bytes to stdout\n",gf_time(), nwritten);froptr += nwritten;/* # just written */if (froptr == friptr)froptr = friptr = fr;/* back to beginning of buffer */}}if (FD_ISSET(sockfd, &wset) && ((n = toiptr - tooptr) > 0)) {if ((nwritten = write(sockfd, tooptr, n)) error to socket");} else {fprintf(stderr,"%s: wrote %d bytes to socket\n",gf_time(), nwritten);tooptr += nwritten;/* # just written */if (tooptr == toiptr) {toiptr = tooptr = to;/* back to beginning of buffer */if (stdineof)Shutdown(sockfd, SHUT_WR);/* send FIN */}}}}}int main(int argc, char **argv){int sockfd;struct sockaddr_in servaddr;if (argc != 2)err_quit("usage: tcpcli ");sockfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);Connect(sockfd, (SA *) & servaddr, sizeof(servaddr));str_cli(sockfd);/* do it all */exit(0);}
   16.2.1 非阻塞读和写:str_cli函数,使用epoll
  //使用epoll#include/* sockaddr_in{} and other Internet defns */#include#include#include/* ANSI C header file */#include/* for syslog() */#include#include#include#i nclude#include#include#i nclude#include#include#defin eMAX_EVENTS 10#defineMAXLINE4096/* max text line length */#defineSERV_PORT 9877/* TCP and UDP */int daemon_proc;/* set nonzero by daemon_init() */#defineSAstruct sockaddr#definemax(a,b)((a) > (b) ? (a) : (b))void err_doit(int errnoflag, int level, const char *fmt, va_list ap){int errno_save, n;char buf[MAXLINE + 1];errno_save = errno;/* value caller might want printed */#ifdefHAVE_VSNPRINTFvsnprintf(buf, MAXLINE, fmt, ap);/* safe */#elsevsprintf(buf, fmt, ap);/* not safe */#endifn = strlen(buf);if (errnoflag)snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));strcat(buf, "\n");if (daemon_proc) {syslog(level, "%s", buf);} else {fflush(stdout);/* in case stdout and stderr are the same */fputs(buf, stderr);fflush(stderr);}return;}void err_quit(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(0, LOG_ERR, fmt, ap);va_end(ap);exit(1);}void err_sys(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(1, LOG_ERR, fmt, ap);va_end(ap);exit(1);}int Socket(int family, int type, int protocol){int n;if ((n = socket(family, type, protocol)) error");return (n);}void Inet_pton(int family, const char *strptr, void *addrptr){int n;if ((n = inet_pton(family, strptr, addrptr)) error for %s", strptr);/* errno set */else if (n == 0)err_quit("inet_pton error for %s", strptr);/* errno not set *//* nothing to return */}void Connect(int fd, const struct sockaddr *sa, socklen_t salen){if (connect(fd, sa, salen) error");}ssize_t Read(int fd, void *ptr, size_t nbytes){ssize_t n;if ((n = read(fd, ptr, nbytes)) == -1)err_sys("read error");return (n);}void Write(int fd, void *ptr, int nbytes){if (write(fd, ptr, nbytes) != nbytes)err_sys("write error");}void Shutdown(int fd, int how){if (shutdown(fd, how) error");}int Fcntl(int fd, int cmd, int arg){int n;if ((n = fcntl(fd, cmd, arg)) == -1)err_sys("fcntl error");return (n);}char *gf_time(void){struct timeval tv;time_t t;static char str[30];char *ptr;if (gettimeofday(&tv, NULL) error");t = tv.tv_sec;/* POSIX says tv.tv_sec is time_t; some BSDs don't agree. */ptr = ctime(&t);strcpy(str, &ptr[11]);/* Fri Sep 13 00:00:00 1986\n\0 *//* 0123456789012345678901234 5 */snprintf(str + 8, sizeof(str) - 8, ".%06ld", tv.tv_usec);return (str);}void set_nonblock(int fd){int val = Fcntl(fd, F_GETFL, 0);Fcntl(fd, F_SETFL, val | O_NONBLOCK);}void Epoll_ctl(int epfd, int op, int fd, struct epoll_event *event){if (epoll_ctl(epfd, op, fd, event) error");}int Epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout){int n;do {n = epoll_wait(epfd, events, maxevents, timeout);if (n error");} while (n error on stdin");} else if (n == 0) {fprintf(stderr,"%s: EOF on stdin\n",gf_time());stdineof = 1;/* all done with stdin */if (tooptr == toiptr)Shutdown(sockfd, SHUT_WR);/* send FIN */} else {fprintf(stderr,"%s: read %d bytes from stdin\n",gf_time(), n);toiptr += n;/* # just read */}}if (revents[i].data.fd == sockfd) {if (revents[i].events & EPOLLIN) {n = read(sockfd, friptr, &fr[MAXLINE] - friptr);if (n error on socket");} else if (n == 0) {fprintf(stderr,"%s: EOF on socket\n",gf_time());if (stdineof)return;/* normal termination */elseerr_quit ("str_cli: server terminated prematurely");} else {fprintf(stderr,"%s: read %d bytes from socket\n",gf_time(), n);friptr += n;/* # just read */}}if (revents[i].events & EPOLLOUT) {n = toiptr - tooptr;if (n > 0) {nwritten = write(sockfd, tooptr, n);if (nwritten error to socket");} else {fprintf(stderr,"%s: wrote %d bytes to socket\n",gf_time(),nwritten);tooptr += nwritten;/* # just written */if (tooptr == toiptr) {toiptr = tooptr = to;/* back to beginning of buffer */if (stdineof)Shutdown(sockfd, SHUT_WR);/* send FIN */}}}}}if (revents[i].data.fd == STDOUT_FILENO) {n = friptr - froptr;if (n > 0) {nwritten = write(STDOUT_FILENO, froptr, n);if (nwritten error to stdout");} else {fprintf(stderr,"%s: wrote %d bytes to stdout\n",gf_time(), nwritten);froptr += nwritten;/* # just written */if (froptr == friptr)froptr = friptr = fr;/* back to beginning of buffer */}}}}}}int main(int argc, char **argv){int sockfd;struct sockaddr_in servaddr;if (argc != 2)err_quit("usage: tcpcli ");sockfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);Connect(sockfd, (SA *) & servaddr, sizeof(servaddr));str_cli(sockfd);/* do it all */exit(0);}
   16.2.2 str_cli函数的较简单版本
  #define_POSIX_SOURCE#include/* sockaddr_in{} and other Internet defns */#include#include#include/* ANSI C header file */#include/* for syslog() */#include#include#include#i nclude#include#include#i nclude#defineMAXLINE4096/* max text line length */#defineSERV_PORT 9877/* TCP and UDP */int daemon_proc;/* set nonzero by daemon_init() */#defineSAstruct sockaddr#definemax(a,b)((a) > (b) ? (a) : (b))void err_doit(int errnoflag, int level, const char *fmt, va_list ap){int errno_save, n;char buf[MAXLINE + 1];errno_save = errno;/* value caller might want printed */#ifdefHAVE_VSNPRINTFvsnprintf(buf, MAXLINE, fmt, ap);/* safe */#elsevsprintf(buf, fmt, ap);/* not safe */#endifn = strlen(buf);if (errnoflag)snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));strcat(buf, "\n");if (daemon_proc) {syslog(level, "%s", buf);} else {fflush(stdout);/* in case stdout and stderr are the same */fputs(buf, stderr);fflush(stderr);}return;}void err_quit(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(0, LOG_ERR, fmt, ap);va_end(ap);exit(1);}void err_sys(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(1, LOG_ERR, fmt, ap);va_end(ap);exit(1);}int Socket(int family, int type, int protocol){int n;if ((n = socket(family, type, protocol)) error");return (n);}void Inet_pton(int family, const char *strptr, void *addrptr){int n;if ((n = inet_pton(family, strptr, addrptr)) error for %s", strptr);/* errno set */else if (n == 0)err_quit("inet_pton error for %s", strptr);/* errno not set *//* nothing to return */}void Connect(int fd, const struct sockaddr *sa, socklen_t salen){if (connect(fd, sa, salen) error");}ssize_t writen(int fd, const void *vptr, size_t n){size_t nleft;ssize_t nwritten;const char *ptr;ptr = (const char *)vptr;nleft = n;while (nleft > 0) {if ((nwritten = write(fd, ptr, nleft)) error */}nleft -= nwritten;ptr += nwritten;}return (n);}void Writen(int fd, void *ptr, int nbytes){if (writen(fd, ptr, nbytes) != nbytes)err_sys("writen error");}char *Fgets(char *ptr, int n, FILE * stream){char *rptr;if ((rptr = fgets(ptr, n, stream)) == NULL && ferror(stream))err_sys("fgets error");return (rptr);}void Fputs(const char *ptr, FILE * stream){if (fputs(ptr, stream) == EOF)err_sys("fputs error");}void Write(int fd, void *ptr, int nbytes){if (write(fd, ptr, nbytes) != nbytes)err_sys("write error");}void Shutdown(int fd, int how){if (shutdown(fd, how) error");}int read_cnt;char *read_ptr;char read_buf[MAXLINE];ssize_t my_read(int fd, char *ptr){if (read_cnt error, errno set by read() */}*ptr = 0;/* null terminate like fgets() */return (n);}ssize_t Readline(int fd, void *ptr, size_t maxlen){ssize_t n;if ((n = readline(fd, ptr, maxlen)) error");return (n);}pid_t Fork(void){pid_t pid;if ((pid = fork()) == -1)err_sys("fork error");return (pid);}void str_cli(FILE * fp, int sockfd){pid_t pid;char sendline[MAXLINE], recvline[MAXLINE];if ((pid = Fork()) == 0) {/* child: server -> stdout */while (Readline(sockfd, recvline, MAXLINE) > 0)Fputs(recvline, stdout);kill(getppid(), SIGTERM);/* in case parent still running */exit(0);}/* parent: stdin -> server */while (Fgets(sendline, MAXLINE, fp) != NULL)Writen(sockfd, sendline, strlen(sendline));Shutdown(sockfd, SHUT_WR);/* EOF on stdin, send FIN */pause();return;}int main(int argc, char **argv){int sockfd;struct sockaddr_in servaddr;if (argc != 2)err_quit("usage: tcpcli ");sockfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(SERV_PORT);Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);Connect(sockfd, (SA *) & servaddr, sizeof(servaddr));str_cli(stdin, sockfd);/* do it all */exit(0);}
   16.4 非阻塞connect:时间获取客户程序
  #include/* sockaddr_in{} and other Internet defns */#include#include#include/* ANSI C header file */#include/* for syslog() */#include#include#include#i nclude#include#include#i nclude#include#defineMAXLINE4096/* max text line length */#defineSAstruct sockaddrvoid err_doit(int errnoflag, const char *fmt, va_list ap){int errno_save;char buf[MAXLINE];errno_save = errno;/* value caller might want printed */vsprintf(buf, fmt, ap);if (errnoflag)sprintf(buf + strlen(buf), ": %s", strerror(errno_save));strcat(buf, "\n");fflush(stdout);/* in case stdout and stderr are the same */fputs(buf, stderr);fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */return;}void err_quit(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(0, fmt, ap);va_end(ap);exit(1);}void err_sys(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(1, fmt, ap);va_end(ap);exit(1);}int Fcntl(int fd, int cmd, int arg){int n;if ((n = fcntl(fd, cmd, arg)) == -1)err_sys("fcntl error");return (n);}int Select(int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval *timeout){int n;do {n = select(nfds, readfds, writefds, exceptfds, timeout);if (n error");} while (n error;socklen_t len;fd_set rset, wset;struct timeval tval;flags = Fcntl(sockfd, F_GETFL, 0);Fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);error = 0;if ((n = connect(sockfd, saptr, salen)) error);if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) error */} elseerr_quit("select error: sockfd not set"); done:Fcntl(sockfd, F_SETFL, flags);/* restore file status flags */if (error) {close(sockfd);/* just in case */errno = error;return (-1);}return (0);}int main(int argc, char **argv){int sockfd, n;char recvline[MAXLINE + 1];struct sockaddr_in servaddr;if (argc != 2)err_quit("usage: a.out ");if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) error");bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_port = htons(13);/* daytime server */if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) error for %s", argv[1]);if (connect_nonb(sockfd, (SA *) & servaddr, sizeof(servaddr), 5) error");while ((n = read(sockfd, recvline, MAXLINE)) > 0) {recvline[n] = 0;/* null terminate */if (fputs(recvline, stdout) == EOF)err_sys("fputs error");}if (n error");exit(0);}
  学习设计模式感悟 
  
  
  

猜你喜欢

转载自dai137hh.iteye.com/blog/1359406