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

第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);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值