第十四章 高级I/O函数:
#include <sys/socket.h> ssize_t recv(int sockfd, void * buff, size_t nbytes, int flags); success return recv-byte-count, error return -1 ssize_t send(int sockfd, const void * buff, size_t nbytes, int flags); success return send-byte-count, error return -1 flags: MSG_DONTROUTE, MSG_DONTWAIT, MSG_OOB, MSG_PEEK, MSG_WAITALL /* if system support MSG_WAITALL */ #define readn(fd, ptr, n) recv(fd, ptr, n, MSG_WAITALL) #include <sys/uio.h> ssize_t readv(int fileds, const struct iovec * iov, int iovcnt); success return total-read-byte-count, error return -1 ssize_t writev(int fileds, const struct iovec * iov, int iovcnt); success return total-write-byte-count, error return -1 struct iovec { void * iov_base; /* starting address of buffer */ size_t iov_len; /* size of buffer */ }; #include <sys/socket.h> ssize_t recvmsg(int sockfd, struct msghdr * msg, int flags); success return recv-byte-count, error return -1 ssize_t sendmsg(int sockfd, struct msghdr * msg, int flags); success return send-byte-count, error return -1 struct msghdr { void * msg_name; /* protocol address */ socklen_t msg_namelen; /* size of protocol address (val-ret)*/ struct iovec * msg_iov; /* scatter/gather array */ int msg_iovlen; /* element-count in msg_iov */ void * msg_control; /* ancillary data (cmsghdr struct) */ socklen_t msg_controllen; /* length of ancillary data */ int msg_flags; /* flags returned by recvmsg() */ ... }; flags: MSG_DONTROUTE, MSG_DONTWAIT, MSG_OOB, MSG_PEEK, MSG_WAITALL msg_flags: MSG_DONTROUTE, MSG_DONTWAIT, MSG_OOB, MSG_PEEK, MSG_WAITALL MSG_BCAST, MSG_MCAST, MSG_TRUNC, MSG_CTRUNC, MSG_EOR, MSG_NOTIFICATION struct cmsghdr { socklen_t cmsg_len; /* length in bytes, including this structure */ int cmsg_level; /* originating protocol */ int cmsg_type; /* protocol-specific type */ /* followed by unsigned char cmsg_data[] */ }; #include <sys/socket.h> #include <sys/param.h> /* for ALIGN macro on many implementations */ struct cmsghdr * CMSG_FIRSTHDR(struct msghdr * mhdrptr); struct cmsghdr * CMSG_NXTHDR(struct msghdr * mhdrptr, struct cmsghdr * cmsgptr); unsigned char * CMSG_DATA(struct cmsghdr * cmsgptr); unsigned int CMSG_LENGTH(unsigned int length); unsigned int CMSG_SPACE(unsigned int length); usage: struct msghdr msg; struct cmsghdr * cmsgptr; /* fill in msg structure */ /* call recvmsg() */ for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { if (cmsgptr->cmsg_level == ... && cmsgptr->cmsg_type == ...) { u_char * ptr = CMSG_DATA(cmsgptr); /* process data */ } } /dev/poll - interface: #include <sys/devpoll.h> struct dvpoll { struct pollfd * dp_fds; int dp_nfds; int dp_timeout; }; #include <sys/types.h> #include <sys/event.h> #include <sys/time.h> int kqueue(void); int kevent(int kq, const struct kevent * changelist, int nchanges, struct kevent * eventlist, int nevents, const struct timespec * timeout); void EV_SET(struct kevent * kev, uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t data, void * udata); struct kevent { uintptr_t ident; short filter; u_short flags; u_int fflags; intptr_t data; void * udata; }; flags: EV_ADD, EV_CLEAR, EV_DELETE, (value) EV_DISABLE, EV_ENABLE, EV_ONESHOT, (value) EV_EOF, EV_ERROR (result) filter: EVFILT_AIO, EVFILT_PROC, EVFILT_READ, EVFILT_SIGNAL, EVFILT_TIMER, EVFILT_VNODE, EVFILT_WRITE
示例:
#include <netinet/in.h> #include "err_exit.h" #include "my_signal.h" #define MAXLINE 4096 void sig_alrm(int signo) { return; /* just interrupt the recvfrom() */ } void dg_cli(FILE * fp, int sockfd, const struct sockaddr * pservaddr, socklen_t servlen) { int n; char sendline[MAXLINE]; char recvline[MAXLINE + 1]; if (my_signal(SIGALRM, sig_alrm) == SIG_ERR) { err_exit("my_signal error"); } while (fgets(sendline, MAXLINE, fp) != NULL) { n = strlen(sendline); if (sendto(sockfd, sendline, n, 0, pservaddr, servlen) != n) { err_exit("sendto error"); } alarm(5); if ((n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) { if (errno == EINTR) { fprintf(stderr, "socket timeout\n"); } else { err_exit("recvfrom error"); } } else { alarm(0); recvline[n] = 0; /* null terminate */ if (fputs(recvline, stdout) == EOF) { err_exit("fputs error"); } } } if (ferror(fp)) { err_exit("fgets error"); } }
#include <netinet/in.h> #include "err_exit.h" #include "my_signal.h" void connect_alarm(int signo) { return; /* just interrupt the connect() */ } int connect_timeo(int sockfd, const struct sockaddr * saptr, socklen_t salen, int nsec) { Sigfunc * sigfunc; int n; if ((sigfunc = my_signal(SIGALRM, connect_alarm)) == SIG_ERR) { err_exit("my_signal error"); } if (alarm(nsec) != 0) { printf("connect_timeo: alarm was already set\n"); } if ((n = connect(sockfd, saptr, salen)) < 0) { if (errno == EINTR) { errno = ETIMEDOUT; } if (close(sockfd) == -1) { err_exit("close error"); } } alarm(0); /* turn off the alarm */ /* restore previous signal handler */ if (my_signal(SIGALRM, sigfunc) == SIG_ERR) { err_exit("my_signal error"); } return(n); }
#include <stdio.h> #include <sys/select.h> int readable_timeo(int fd, int sec) { fd_set rset; struct timeval tv; FD_ZERO(&rset); FD_SET(fd, &rset); tv.tv_sec = sec; tv.tv_usec = 0; return(select(fd + 1, &rset, NULL, NULL, &tv)); }
#include <stdio.h> #include <sys/select.h> int writeable_timeo(int fd, int sec) { fd_set wset; struct timeval tv; FD_ZERO(&wset); FD_SET(fd, &wset); tv.tv_sec = sec; tv.tv_usec = 0; return(select(fd + 1, NULL, &wset, NULL, &tv)); }
#include <netinet/in.h> #include "err_exit.h" #include "readable_timeo.h" #define MAXLINE 4096 void dg_cli(FILE * fp, int sockfd, const struct sockaddr * pservaddr, socklen_t servlen) { int n; char sendline[MAXLINE]; char recvline[MAXLINE + 1]; while (fgets(sendline, MAXLINE, fp) != NULL) { n = strlen(sendline); if (sendto(sockfd, sendline, n, 0, pservaddr, servlen) != n) { err_exit("sendto error"); } if ((n = readable_timeo(sockfd, 5)) < 0) { err_exit("readable_timeo error"); } else if (n == 0) { fprintf(stderr, "socket timeout\n"); } else { if ((n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) { err_exit("recvfrom error"); } recvline[n] = 0; /* null terminate */ if (fputs(recvline, stdout) == EOF) { err_exit("fputs error"); } } } if (ferror(fp)) { err_exit("fgets error"); } }
#include <netinet/in.h> #include "err_exit.h" #define MAXLINE 4096 void dg_cli(FILE * fp, int sockfd, const struct sockaddr * pservaddr, socklen_t servlen) { int n; char sendline[MAXLINE]; char recvline[MAXLINE + 1]; struct timeval tv; tv.tv_sec = 5; tv.tv_usec = 0; if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { err_exit("setsockopt error"); } while (fgets(sendline, MAXLINE, fp) != NULL) { n = strlen(sendline); if (sendto(sockfd, sendline, n, 0, pservaddr, servlen) != n) { err_exit("sendto error"); } if ((n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) { if (errno == EWOULDBLOCK) { fprintf(stderr, "socket timeout\n"); } else { err_exit("recvfrom error"); } } else { recvline[n] = 0; /* null terminate */ if (fputs(recvline, stdout) == EOF) { err_exit("fputs error"); } } } if (ferror(fp)) { err_exit("fgets error"); } }
#include "err_exit.h" #define MAXLINE 4096 /* * we'd better not use standant IO functions with socket */ void str_echo(int sockfd) { char line[MAXLINE]; FILE * fpin; FILE * fpout; if ((fpin = fdopen(sockfd, "r")) == NULL) { err_exit("fdopen to read error"); } if ((fpout = fdopen(sockfd, "w")) == NULL) { err_exit("fdopen to write error"); } while (fgets(line, MAXLINE, fpin) != NULL) { if (fputs(line, fpout) == EOF) { err_exit("fputs error"); } fflush(fpout); /* default full buffered */ } if (ferror(fpin)) { err_exit("fgets error"); } }
#include "err_exit.h" #define MAXLINE 4096 /* * we'd better not use standant IO functions with socket */ void str_echo(int sockfd) { char line[MAXLINE]; FILE * fpin; FILE * fpout; if ((fpin = fdopen(sockfd, "r")) == NULL) { err_exit("fdopen to read error"); } if ((fpout = fdopen(sockfd, "w")) == NULL) { err_exit("fdopen to write error"); } if (setvbuf(fpin, NULL, _IOLBF, 0) != 0) { /* line buffered */ err_exit("setvbuf fpin error"); } if (setvbuf(fpout, NULL, _IOLBF, 0) != 0) { /* line buffered */ err_exit("setvbuf fpout error"); } while (fgets(line, MAXLINE, fpin) != NULL) { if (fputs(line, fpout) == EOF) { err_exit("fputs error"); } } if (ferror(fpin)) { err_exit("fgets error"); } }
#include <sys/devpoll.h> /* no such file */ #include "writen.h" #include "err_exit.h" void str_cli(FILE * fp, int sockfd) { int stdineof; char buf[MAXLINE]; int n; int wfd; int i; int result; struct pollfd pofd[2]; struct dvpoll dopoll; if ((wfd = open("/dev/poll", O_RDWR, 0)) == -1) { err_exit("open error"); } pofd[0].fd = fileno(fp); pofd[0].events = POLLIN; pofd[0].revents = 0; pofd[1].fd = sockfd; pofd[1].events = POLLIN; pofd[1].revents = 0; if (write(wfd, pofd, sizeof(pofd) != sizeof(pofd)) { err_exit("write error"); } stdineof = 0; for ( ; ; ) { /* block until /dev/poll says something is ready */ dopoll.dp_timeout = -1; /* blocking */ dopoll.dp_nfds = 2; dopoll.dp_fds = pofd; if ((result = ioctl(wfd, DP_POLL, &dopoll)) == -1) { err_exit("ioctl error"); } /* loop through ready file descriptors */ for (i = 0; i < result; ++i) { if (dopoll.dp_fds[i].fd == sockfd) { /* socket is readable */ if ((n = read(sockfd, buf, MAXLINE)) < 0) { err_exit("read error"); } else if (n == 0) { if (stdineof == 1) { return; /* normal termination */ } else { err_exit("str_cli: server terminated prematurely"); } } if (write(fileno(stdout), buf, n) != n) { err_exit("write error"); } } else { /* input is readable */ if ((n = read(fileno(fp), buf, MAXLINE)) < 0) { err_exit("read error"); } else if (n == 0) { stdineof = 1; if (shutdown(sockfd, SHUT_WR) == -1) { /* send FIN */ err_exit("shutdown error"); } continue; } if (writen(sockfd, buf, n) != n) { err_exit("writen error"); } } } } }
#include <sys/types.h> #include <sys/event.h> /* no such file */ #include <sys/time.h> #include "writen.h" #include "err_exit.h" #define MAXLINE 4096 void str_cli(FILE * fp, int sockfd) { int kq; int i; int n; int nev; int stdineof = 0; int isfile; char buf[MAXLINE]; struct kevent kev[2]; struct timespec ts; struct stat st; isfile = ((fstat(fileno(fp), &st) == 0) && (st.st_mode & S_IFMT) == S_IFREG); EV_SET(&kev[0], fileno(fp), EVFILT_READ, EV_ADD, 0, 0, NULL); EV_SET(&kev[1], sockfd, EVFILT_READ, EV_ADD, 0, 0, NULL); kq = kqueue(); ts.tv_sec = 0; ts.tv_nsec = 0; kevent(kq, kev, 2, NULL, 0, &ts); /* non-blocking */ for ( ; ; ) { nev = kevent(kq, NULL, 0, kev, 2, NULL); /* blocking */ for (i = 0; i < nev; ++i) { if (kev[i].ident == sockfd) { /* socket is readable */ if ((n = read(sockfd, buf, MAXLINE)) < 0) { err_exit("read error"); } else if (n == 0) { if (stdineof == 1) { return; /* normal termination */ } else { err_quit("str_cli: server terminated prematurely"); } } if (write(fileno(stdout), buf, n) != n) { err_exit("write error"); } } else if (kev[i].ident == fileno(fp)) { /* input is readable */ if ((n = read(fileno(fp), buf, MAXLINE)) < 0) { err_exit("read error"); } else if (n > 0) { if (writen(sockfd, buf, n) != n) { err_exit("writen error"); } } if (n == 0 || (isfile && n == kev[i].data)) { stdineof = 1; if (shutdown(sockfd, SHUT_WR) == -1) { /* send FIN */ err_exit("shutdown error"); } kev[i].flags = EV_DELETE; kevent(kq, &kev[i], 1, NULL, 0, &ts); /* remove kevent */ } } } } }