第16章 非阻塞式I/O
16.2 非阻塞读和写:str_cli函数(修订版)
//使用select
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <strings.h>
#include <stdarg.h> /* ANSI C header file */
#include <syslog.h> /* for syslog() */
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <sys/time.h>
#define MAXLINE 4096 /* max text line length */
#define SERV_PORT 9877 /* TCP and UDP */
int daemon_proc; /* set nonzero by daemon_init() */
#define SA struct sockaddr
#define max(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 */
#ifdef HAVE_VSNPRINTF
vsnprintf(buf, MAXLINE, fmt, ap); /* safe */
#else
vsprintf(buf, fmt, ap); /* not safe */
#endif
n = 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)) < 0)
err_sys("socket error");
return (n);
}
void Inet_pton(int family, const char *strptr, void *addrptr)
{
int n;
if ((n = inet_pton(family, strptr, addrptr)) < 0)
err_sys("inet_pton 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) < 0)
err_sys("connect 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 < 0 && errno != EINTR)
err_sys("select error");
} while (n < 0);
return (n); /* can return 0 on timeout */
}
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) < 0)
err_sys("shutdown 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) < 0)
err_sys("gettimeofday 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 < &to[MAXLINE])
FD_SET(STDIN_FILENO, &rset); /* read from stdin */
if (friptr < &fr[MAXLINE])
FD_SET(sockfd, &rset); /* read from socket */
if (tooptr != toiptr)
FD_SET(sockfd, &wset); /* data to write to socket */
if (froptr != friptr)
FD_SET(STDOUT_FILENO, &wset); /* data to write to stdout */
Select(maxfdp1, &rset, &wset, NULL, NULL);
/* end nonb1 */
/* include nonb2 */
if (FD_ISSET(STDIN_FILENO, &rset)) {
if ((n =
read(STDIN_FILENO, toiptr,
&to[MAXLINE] - toiptr)) < 0) {
if (errno != EWOULDBLOCK)
err_sys("read 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)) < 0) {
if (errno != EWOULDBLOCK)
err_sys("read error on socket");
} else if (n == 0) {
fprintf(stderr, "%s: EOF on socket\n",
gf_time());
if (stdineof)
return; /* normal termination */
else
err_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)) < 0) {
if (errno != EWOULDBLOCK)
err_sys("write 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)) < 0) {
if (errno != EWOULDBLOCK)
err_sys("write 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 <IPaddress>");
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 <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <sys/epoll.h>
#include <strings.h>
#include <stdarg.h> /* ANSI C header file */
#include <syslog.h> /* for syslog() */
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <sys/time.h>
#define MAX_EVENTS 10
#define MAXLINE 4096 /* max text line length */
#define SERV_PORT 9877 /* TCP and UDP */
int daemon_proc; /* set nonzero by daemon_init() */
#define SA struct sockaddr
#define max(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 */
#ifdef HAVE_VSNPRINTF
vsnprintf(buf, MAXLINE, fmt, ap); /* safe */
#else
vsprintf(buf, fmt, ap); /* not safe */
#endif
n = 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)) < 0)
err_sys("socket error");
return (n);
}
void Inet_pton(int family, const char *strptr, void *addrptr)
{
int n;
if ((n = inet_pton(family, strptr, addrptr)) < 0)
err_sys("inet_pton 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) < 0)
err_sys("connect 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) < 0)
err_sys("shutdown 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) < 0)
err_sys("gettimeofday 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) < 0)
err_sys("epoll_ctl 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 < 0 && errno != EINTR)
err_sys("epoll_wait error");
} while (n < 0);
return (n);
}
void add_event(int epfd, int fd, unsigned int event)
{
struct epoll_event ev;
ev.data.fd = fd;
ev.events = event;
Epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
}
void str_cli(int sockfd)
{
int stdineof;
ssize_t n, nwritten;
char to[MAXLINE], fr[MAXLINE];
char *toiptr, *tooptr, *friptr, *froptr;
toiptr = tooptr = to; /* initialize buffer pointers */
friptr = froptr = fr;
set_nonblock(sockfd);
set_nonblock(STDIN_FILENO);
set_nonblock(STDOUT_FILENO);
int epfd = epoll_create(MAX_EVENTS);
add_event(epfd, STDIN_FILENO, EPOLLIN);
add_event(epfd, STDOUT_FILENO, EPOLLOUT);
add_event(epfd, sockfd, EPOLLIN | EPOLLOUT);
struct epoll_event revents[MAX_EVENTS]; //returned events
stdineof = 0;
for (;;) {
int nready = Epoll_wait(epfd, revents, MAX_EVENTS, -1);
for (int i = 0; i < nready; i++) {
if (revents[i].data.fd == STDIN_FILENO) {
n = read(STDIN_FILENO, toiptr,
&to[MAXLINE] - toiptr);
if (n < 0 && errno != EWOULDBLOCK) {
err_sys("read 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 < 0 && errno != EWOULDBLOCK) {
err_sys("read error on socket");
} else if (n == 0) {
fprintf(stderr,
"%s: EOF on socket\n",
gf_time());
if (stdineof)
return; /* normal termination */
else
err_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 < 0
&& errno != EWOULDBLOCK) {
err_sys
("write 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 < 0
&& errno != EWOULDBLOCK) {
err_sys
("write 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 <IPaddress>");
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 <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <signal.h>
#include <strings.h>
#include <stdarg.h> /* ANSI C header file */
#include <syslog.h> /* for syslog() */
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#define MAXLINE 4096 /* max text line length */
#define SERV_PORT 9877 /* TCP and UDP */
int daemon_proc; /* set nonzero by daemon_init() */
#define SA struct sockaddr
#define max(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 */
#ifdef HAVE_VSNPRINTF
vsnprintf(buf, MAXLINE, fmt, ap); /* safe */
#else
vsprintf(buf, fmt, ap); /* not safe */
#endif
n = 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)) < 0)
err_sys("socket error");
return (n);
}
void Inet_pton(int family, const char *strptr, void *addrptr)
{
int n;
if ((n = inet_pton(family, strptr, addrptr)) < 0)
err_sys("inet_pton 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) < 0)
err_sys("connect 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)) <= 0) {
if (nwritten < 0 && errno == EINTR)
nwritten = 0; /* and call write() again */
else
return (-1); /* 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) < 0)
err_sys("shutdown error");
}
int read_cnt;
char *read_ptr;
char read_buf[MAXLINE];
ssize_t my_read(int fd, char *ptr)
{
if (read_cnt <= 0) {
again:
if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
if (errno == EINTR)
goto again;
return (-1);
} else if (read_cnt == 0)
return (0);
read_ptr = read_buf;
}
read_cnt--;
*ptr = *read_ptr++;
return (1);
}
ssize_t readline(int fd, void *vptr, int maxlen)
{
ssize_t n, rc;
char c, *ptr;
ptr = (char *)vptr;
for (n = 1; n < maxlen; n++) {
if ((rc = my_read(fd, &c)) == 1) {
*ptr++ = c;
if (c == '\n')
break; /* newline is stored, like fgets() */
} else if (rc == 0) {
*ptr = 0;
return (n - 1); /* EOF, n - 1 bytes were read */
} else
return (-1); /* 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)) < 0)
err_sys("readline 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 <IPaddress>");
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 <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <strings.h>
#include <sys/select.h>
#include <stdarg.h> /* ANSI C header file */
#include <syslog.h> /* for syslog() */
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <signal.h>
#include <fcntl.h>
#define MAXLINE 4096 /* max text line length */
#define SA struct sockaddr
void 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 < 0 && errno != EINTR)
err_sys("select error");
} while (n < 0);
return (n); /* can return 0 on timeout */
}
int connect_nonb(int sockfd, const SA * saptr, socklen_t salen, int nsec)
{
int flags, 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)) < 0)
if (errno != EINPROGRESS)
return (-1);
/* Do whatever we want while the connect is taking place. */
if (n == 0)
goto done; /* connect completed immediately */
FD_ZERO(&rset);
FD_SET(sockfd, &rset);
wset = rset;
tval.tv_sec = nsec;
tval.tv_usec = 0;
if ((n = Select(sockfd + 1, &rset, &wset, NULL,
nsec ? &tval : NULL)) == 0) {
close(sockfd); /* timeout */
errno = ETIMEDOUT;
return (-1);
}
if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
len = sizeof(error);
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
return (-1); /* Solaris pending error */
} else
err_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 <IPaddress>");
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
err_sys("socket 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) <= 0)
err_quit("inet_pton error for %s", argv[1]);
if (connect_nonb(sockfd, (SA *) & servaddr, sizeof(servaddr), 5) < 0)
err_sys("connect error");
while ((n = read(sockfd, recvline, MAXLINE)) > 0) {
recvline[n] = 0; /* null terminate */
if (fputs(recvline, stdout) == EOF)
err_sys("fputs error");
}
if (n < 0)
err_sys("read error");
exit(0);
}