ネットワークインタフェース

付録 B 実際のコード例

実際のコード例

この付録では、基本的な IPv4 のクライアントおよびサーバーと、クライアントおよびサーバーのさまざまな IPv6 ポートについて例を示して説明します。それぞれの例は、コンパイルと実行ができることがわかっています。各クライアントは、各サーバーと自由に組み合わせて使用できます。これらの例は情報目的のためだけに提供されているので、Sun は、これらの例の使用に対して責任を負いません。

第 1 の例は、オリジナルで無修正の IPv4 クライアント、myconnect です。


例 B-1 IPv4 クライアント

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>

int
myconnect(char *hostname, int port)
{
	struct sockaddr_in	sin;
	struct hostent		*hp;
	int			sock;

	/* ソケットを開く */
	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock == -1) {
		perror("socket");
		return (-1);
	}

	/* ホストアドレスの取得 */
	hp = gethostbyname(hostname);
	if (hp == NULL || hp->h_addrtype != AF_INET || hp->h_length != 4) {
		(void) fprintf(stderr, "Unknown host ¥"%s¥"¥n", hostname);
		(void) close(sock);
		return (-1);
	}

	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	(void) memcpy((void *)&sin.sin_addr, (void *)hp->h_addr,
	    hp->h_length);

	/* ホストに接続 */
	if (connect(sock, (struct sockaddr *)&sin, sizeof (sin)) == -1) {
		perror("connect");
		(void) close(sock);
		return (-1);
	}
	return (sock);
}

main(int argc, char *argv[])
{
	int		sock;
	char		buf[BUFSIZ];
	int		cc;

	switch (argc) {
	case 2:
		sock = myconnect(argv[1], IPPORT_ECHO);
		break;
	case 3:
		sock = myconnect(argv[1], atoi(argv[2]));
		break;
	default:
		(void) fprintf(stderr,
		    "Usage: %s <hostname> <port>¥n", argv[0]);
		exit(1);
	}
	if (sock == -1)
		exit(1);

	if (write(sock, "hello world", strlen("hello world") + 1) == -1) {
		perror("write");
		exit(1);
	}
	cc = read(sock, buf, sizeof (buf));
	if (cc == -1) {
		perror("read");
		exit(1);
	}
	(void) printf("Read <%s>¥n", buf);
	return (0);
}

第 2 の例は、IPv4 と IPv6 の両方のサーバーに接続できる、myconnect の最小のポート、myconnect2 です。


例 B-2 IPv4 と IPv6 のクライアントへの最小ポート

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>

int
myconnect2(char *hostname, int port)
{
	struct sockaddr_in6	sin;
	struct hostent		*hp;
	int			sock, errnum;

	/* ソケットを開く */
	sock = socket(AF_INET6, SOCK_STREAM, 0);
	if (sock == -1) {
		perror("socket");
		return (-1);
	}

	/* ホストアドレスの取得。IPv4 射影 IPv6 アドレス可 */
	hp = getipnodebyname(hostname, AF_INET6, AI_DEFAULT, &errnum);
	if (hp == NULL) {
		(void) fprintf(stderr, "Unknown host ¥"%s¥"¥n", hostname);
		(void) close(sock);
		return (-1);
	}

	/* すべての sockaddr_in6 フィールドが 0 であることを確認 */
	bzero(&sin, sizeof (sin));
	sin.sin6_family = hp->h_addrtype;
	sin.sin6_port = htons(port);
	(void) memcpy((void *)&sin.sin6_addr, (void *)hp->h_addr,
	    hp->h_length);
	freehostent(hp);

	/* ホストに接続 */
	if (connect(sock, (struct sockaddr *)&sin, sizeof (sin)) == -1) {
		perror("connect");
		(void) close(sock);
		return (-1);
	}
	return (sock);
}

main(int argc, char *argv[])
{
	int		sock;
	char		buf[BUFSIZ];
	int		cc;

	switch (argc) {
	case 2:
		sock = myconnect2(argv[1], IPPORT_ECHO);
		break;
	case 3:
		sock = myconnect2(argv[1], atoi(argv[2]));
		break;
	default:
		(void) fprintf(stderr,
		    "Usage: %s <hostname> <port>¥n", argv[0]);
		exit(1);
	}
	if (sock == -1)
		exit(1);

	if (write(sock, "hello world", strlen("hello world") + 1) == -1) {
		perror("write");
		exit(1);
	}
	cc = read(sock, buf, sizeof (buf));
	if (cc == -1) {
		perror("read");
		exit(1);
	}
	(void) printf("Read <%s>¥n", buf);
	return (0);
}

第 3 の例は、第 2 の例の拡張版で、1 つが接続するまですべてのアドレスを試行しようとします。これは myconnect2all です。第 3 の例は、同一の機能を持つ第 4 の例よりも複雑であることに注意してください。


例 B-3 IPv4 と IPv6 のクライアントへの拡張最小ポート

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
int
myconnect2all(char *hostname, int port)
{
	struct sockaddr_in6	sin;
	struct hostent		*hp;
	int			sock, errnum;
	int			h_addr_index;

	/* ソケットを開く */
	sock = socket(AF_INET6, SOCK_STREAM, 0);
	if (sock == -1) {
		perror("socket");
		return (-1);
	}

	/* ホストアドレスの取得。IPv4 射影 IPv6 アドレスが可 */
	hp = getipnodebyname(hostname, AF_INET6, AI_DEFAULT|AI_ALL, &errnum);
	if (hp == NULL) {
		(void) fprintf(stderr, "Unknown host ¥"%s¥"¥n", hostname);
		(void) close(sock);
		return (-1);
	}

	/* すべての sockaddr_in6 フィールドが 0 であることを確認 */
	bzero(&sin, sizeof (sin));
	sin.sin6_family = hp->h_addrtype;
	sin.sin6_port = htons(port);

	/* 1 つが接続するまで戻されたすべてのアドレスを試行 */
	h_addr_index = 0;
	while (hp->h_addr_list[h_addr_index] != NULL) {
		bcopy(hp->h_addr_list[h_addr_index], &sin.sin6_addr,
		    hp->h_length);
		/* ホストに接続 */
		if (connect(sock, (struct sockaddr *)&sin,
		    sizeof (sin)) == -1) {
			if (hp->h_addr_list[++h_addr_index] != NULL) {
				/* 次のアドレスを試行 */
				continue;
			}
			perror("connect");
			freehostent(hp);
			(void) close(sock);
			return (-1);
		}
		break;
	}
	freehostent(hp);
	return (sock);
}

main(int argc, char *argv[])
{
	int		sock;
	char		buf[BUFSIZ];
	int		cc;

	switch (argc) {
	case 2:
		sock = myconnect2all(argv[1], IPPORT_ECHO);
		break;
	case 3:
		sock = myconnect2all(argv[1], atoi(argv[2]));
		break;
	default:
		(void) fprintf(stderr,
		    "Usage: %s <hostname> <port>¥n", argv[0]);
		exit(1);
	}
	if (sock == -1)
		exit(1);

	if (write(sock, "hello world", strlen("hello world") + 1) == -1) {
		perror("write");
		exit(1);
	}
	cc = read(sock, buf, sizeof (buf));
	if (cc == -1) {
		perror("read");
		exit(1);
	}
	(void) printf("Read <%s>¥n", buf);
	return (0);
}

第 4 の例は、新しい getaddrinfo(3SOCKET) インタフェースを使用する myconnect のポートです。このルーチンは、1 つが接続するまですべてのアドレスを試行しようとします。これは myconnect3 です。このプログラムは、myconnect2all よりも単純であり、IPv4 から IPv6 へこのポートを実行する方法としてお奨めします


例 B-4 IPv6 クライアントへの推奨ポート

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>

int
myconnect3(char *hostname, char *servicename)
{
	struct addrinfo		*res, *aip;
	struct addrinfo		hints;
	int			sock = -1;
	int			error;

	/* ホストアドレスの取得。どのタイプのアドレスも可 */
	bzero(&hints, sizeof (hints));
	hints.ai_flags = AI_ALL|AI_ADDRCONFIG;
	hints.ai_socktype = SOCK_STREAM;

	error = getaddrinfo(hostname, servicename, &hints, &res);
	if (error != 0) {
		(void) fprintf(stderr,
		    "getaddrinfo: %s for host %s service %s¥n",
		    gai_strerror(error), hostname, servicename);
		return (-1);
	}
	/* 1 つが接続するまですべてのアドレスを試行 */
	for (aip = res; aip != NULL; aip = aip->ai_next) {
		/*
		 * ソケットを開く。このアドレスタイプは、
		 * getaddrinfo() の返す値に依存
		 */
		sock = socket(aip->ai_family, aip->ai_socktype,
		    aip->ai_protocol);
		if (sock == -1) {
			perror("socket");
			freeaddrinfo(res);
			return (-1);
		}

		/* ホストに接続 */
		if (connect(sock, aip->ai_addr, aip->ai_addrlen) == -1) {
			perror("connect");
			(void) close(sock);
			sock = -1;
			continue;
		}
		break;
	}
	freeaddrinfo(res);
	return (sock);
}

main(int argc, char *argv[])
{
	int		sock;
	char		buf[BUFSIZ];
	int		cc;

	switch (argc) {
	case 1:
		sock = myconnect3(NULL, NULL);
		break;
	case 2:
		sock = myconnect3(argv[1], "echo");
		break;
	case 3:
		sock = myconnect3(argv[1], argv[2]);
		break;
	default:
		(void) fprintf(stderr,
		    "Usage: %s <hostname> <port>¥n", argv[0]);
		exit(1);
	}
	if (sock == -1)
		exit(1);

	if (write(sock, "hello world", strlen("hello world") + 1) == -1) {
		perror("write");
		exit(1);
	}
	cc = read(sock, buf, sizeof (buf));
	if (cc == -1) {
		perror("read");
		exit(1);
	}
	(void) printf("Read <%s>¥n", buf);
	return (0);
}

第 5 の例は、オリジナルで無修正の IPv4 サーバー、myserver です。


例 B-5 IPv4 サーバー

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>

#define	BACKLOG	1024				/* 保留状態の接続の最大数 */

void do_work(int sock);

int
myserver(int port)
{
	struct sockaddr_in	laddr, faddr;
	int			sock, new_sock, sock_opt;
	socklen_t		faddrlen;

	/* 接続待機するソケットの設定 */
	laddr.sin_family = AF_INET;
	laddr.sin_port = htons(port);
	laddr.sin_addr.s_addr = INADDR_ANY;

	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock == -1) {
		perror("socket");
		return (-1);
	}

	/* ローカルアドレスを再使用できるようにシステムに通知 */
	sock_opt = 1;
	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt,
	    sizeof (sock_opt)) == -1) {
		perror("setsockopt(SO_REUSEADDR)");
		(void) close(sock);
		return (-1);
	}

	if (bind(sock, (struct sockaddr *)&laddr, sizeof (laddr)) == -1) {
		perror("bind");
		(void) close(sock);
		return (-1);
	}

	if (listen(sock, BACKLOG) == -1) {
		perror("listen");
		(void) close(sock);
		return (-1);
	}

	/* 接続要求のための待機 */
	for (;;) {
		faddrlen = sizeof (faddr);
		new_sock = accept(sock, (struct sockaddr *)&faddr, &faddrlen);
		if (new_sock == -1) {
			if (errno != EINTR && errno != ECONNABORTED) {
				perror("accept");
			}
			continue;
		}

		(void) printf("Connection from %s/%d¥n",
		    inet_ntoa(faddr.sin_addr), ntohs(faddr.sin_port));

		do_work(new_sock);		/* 作業の実行 */
	}
	/*NOTREACHED*/
}

void
do_work(int sock)
{
	char		buf[BUFSIZ];
	int		cc;

	while (1) {
		cc = read(sock, buf, sizeof (buf));
		if (cc == -1) {
			perror("read");
			exit(1);
		}
		if (cc == 0) {
			/* EOF */
			(void) close(sock);
			(void) printf("Connection closed¥n");
			return;
		}
		buf[cc + 1] = '¥0';
		(void) printf("Read <%s>¥n", buf);

		if (write(sock, buf, cc) == -1) {
			perror("write");
			exit(1);
		}
	}
}

main(int argc, char *argv[])
{
	if (argc != 2) {
		(void) fprintf(stderr,
		    "Usage: %s <port>¥n", argv[0]);
		exit(1);
	}
	(void) myserver(htons(atoi(argv[1])));
	return (0);
}

第 6 の例は、IPv4 と IPv6 の両方のクライアントとの接続を処理する myserver の最小ポートです。この例では単一のソケットを使うので、IPv4 接続は IPv4 射影アドレスとして表示されます。


例 B-6 IPv6 サーバーへの最小ポート

include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>

#define	BACKLOG	1024				/* 保留状態の接続の最大数 */

void do_work(int sock);

int
myserver2(int port)
{
	struct sockaddr_in6	laddr, faddr;
	int			sock, new_sock, sock_opt;
	socklen_t		faddrlen;
	char			addrbuf[INET6_ADDRSTRLEN];

	/*
	 * 接続待機するソケットの設定
	 * すべての sockaddr_in6 フィールドが 0 であることを確認
	 */
	bzero(&laddr, sizeof (laddr));
	laddr.sin6_family = AF_INET6;
	laddr.sin6_port = htons(port);
	laddr.sin6_addr = in6addr_any;	/* 構造体割り当て */

	sock = socket(AF_INET6, SOCK_STREAM, 0);
	if (sock == -1) {
		perror("socket");
		return (-1);
	}

	/* ローカルアドレスを再使用できるようにシステムに通知 */
	sock_opt = 1;
	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt,
	    sizeof (sock_opt)) == -1) {
		perror("setsockopt(SO_REUSEADDR)");
		(void) close(sock);
		return (-1);
	}

	if (bind(sock, (struct sockaddr *)&laddr, sizeof (laddr)) == -1) {
		perror("bind");
		(void) close(sock);
		return (-1);
	}

	if (listen(sock, BACKLOG) == -1) {
		perror("listen");
		(void) close(sock);
		return (-1);
	}

	/* 接続要求のための待機 */
	for (;;) {
		faddrlen = sizeof (faddr);
		new_sock = accept(sock, (struct sockaddr *)&faddr, &faddrlen);
		if (new_sock == -1) {
			if (errno != EINTR && errno != ECONNABORTED) {
				perror("accept");
			}
			continue;
		}

		if (IN6_IS_ADDR_V4MAPPED(&faddr.sin6_addr)) {
			struct in_addr ina;

			IN6_V4MAPPED_TO_INADDR(&faddr.sin6_addr, &ina);
			(void) printf("Connection from %s/%d¥n",
			    inet_ntop(AF_INET, (void *)&ina,
			    addrbuf, sizeof (addrbuf)),
			    ntohs(faddr.sin6_port));
		} else {
			(void) printf("Connection from %s/%d¥n",
			    inet_ntop(AF_INET6, (void *)&faddr.sin6_addr,
			    addrbuf, sizeof (addrbuf)),
			    ntohs(faddr.sin6_port));
		}
		do_work(new_sock);		/* 作業の実行 */
	}
	/*NOTREACHED*/
}

void
do_work(int sock)
{
	char		buf[BUFSIZ];
	int		cc;

	while (1) {
		cc = read(sock, buf, sizeof (buf));
		if (cc == -1) {
			perror("read");
			exit(1);
		}
		if (cc == 0) {
			/* EOF */
			(void) close(sock);
			(void) printf("Connection closed¥n");
			return;
		}
		buf[cc + 1] = '¥0';
		(void) printf("Read <%s>¥n", buf);

		if (write(sock, buf, cc) == -1) {
			perror("write");
			exit(1);
		}
	}
}

main(int argc, char *argv[])
{
	if (argc != 2) {
		(void) fprintf(stderr,
		    "Usage: %s <port>¥n", argv[0]);
		exit(1);
	}
	(void) myserver2(htons(atoi(argv[1])));
	return (0);
}

第 7 の例は、getnameinfo(3SOCKET) を使って対等アドレスと対等名のログを単純化する、IPv6 への myserver のポートです。これは、IPv4 から IPv6 へこのポートを実行する方法としてお奨めします


例 B-7 IPv6 サーバーへの推奨ポート

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>

#define	BACKLOG	1024				/* 保留状態の接続の最大数 */

void do_work(int sock);

int
myserver3(char *servicename)
{
	struct addrinfo		*aip;
	struct addrinfo		hints;
	struct sockaddr_storage	faddr;
	int			sock, new_sock, sock_opt;
	socklen_t		faddrlen;
	int			error;
	char			hname[NI_MAXHOST];
	char			sname[NI_MAXSERV];

	/* 接続待機するソケットの設定 */
	bzero(&hints, sizeof (hints));
	hints.ai_flags = AI_ALL|AI_ADDRCONFIG|AI_PASSIVE;
	hints.ai_socktype = SOCK_STREAM;

	error = getaddrinfo(NULL, servicename, &hints, &aip);
	if (error != 0) {
		(void) fprintf(stderr, "getaddrinfo: %s for service %s¥n",
		    gai_strerror(error), servicename);
		return (-1);
	}
	sock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
	if (sock == -1) {
		perror("socket");
		return (-1);
	}

	/* ローカルアドレスを再使用できるようにシステムに通知 */
	sock_opt = 1;
	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt,
	    sizeof (sock_opt)) == -1) {
		perror("setsockopt(SO_REUSEADDR)");
		(void) close(sock);
		return (-1);
	}

	if (bind(sock, aip->ai_addr, aip->ai_addrlen) == -1) {
		perror("bind");
		(void) close(sock);
		return (-1);
	}

	if (listen(sock, BACKLOG) == -1) {
		perror("listen");
		(void) close(sock);
		return (-1);
	}

	/* 接続要求のための待機 */
	for (;;) {
		faddrlen = sizeof (faddr);
		new_sock = accept(sock, (struct sockaddr *)&faddr, &faddrlen);
		if (new_sock == -1) {
			if (errno != EINTR && errno != ECONNABORTED) {
				perror("accept");
			}
			continue;
		}
		error = getnameinfo((struct sockaddr *)&faddr, faddrlen,
		    hname, sizeof (hname), sname, sizeof (sname),
		    NI_NUMERICHOST|NI_NUMERICSERV);
		if (error) {
			(void) fprintf(stderr, "getnameinfo: %s¥n",
			    gai_strerror(error));
		} else {
			(void) printf("Connection from (addr) %s/%s¥n",
			    hname, sname);
		}
		error = getnameinfo((struct sockaddr *)&faddr, faddrlen,
		    hname, sizeof (hname), sname, sizeof (sname), 0);
		if (error) {
			(void) fprintf(stderr, "getnameinfo: %s¥n",
			    gai_strerror(error));
		} else {
			(void) printf("Connection from (name) %s/%s¥n",
			    hname, sname);
		}
		do_work(new_sock);		/* 作業の実行 */
	}
	/*NOTREACHED*/
}

void
do_work(int sock)
{
	char		buf[BUFSIZ];
	int		cc;

	while (1) {
		cc = read(sock, buf, sizeof (buf));
		if (cc == -1) {
			perror("read");
			exit(1);
		}
		if (cc == 0) {
			/* EOF */
			(void) close(sock);
			(void) printf("Connection closed¥n");
			return;
		}
		buf[cc + 1] = '¥0';
		(void) printf("Read <%s>¥n", buf);

		if (write(sock, buf, cc) == -1) {
			perror("write");
			exit(1);
		}
	}
}

main(int argc, char *argv[])
{
	if (argc != 2) {
		(void) fprintf(stderr,
		    "Usage: %s <servicename>¥n", argv[0]);
		exit(1);
	}
	(void) myserver3(argv[1]);
	return (0);
}

第 8 の例は、射影アドレスの代わりに IPv4 と IPv6 用の個別のソケットを使用する myserver のポートです。この設定は poll(2) を使う必要があるので、さらに複雑です。


例 B-8 IPv4 ソケットと IPv6 ソケットを使った myserver のポート

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>

#define	BACKLOG	1024				/* 保留状態の接続の最大数 */
#define	NUMSOCKS	2			/* ポーリングするソケット数 */

void do_work(int sock);

int
myserver4(int port)
{
	struct sockaddr_in	laddr4, faddr4;
	struct sockaddr_in6	laddr6, faddr6;
	int			sock4, sock6, new_sock, sock_opt;
	socklen_t		faddrlen;
	char			addrbuf[INET6_ADDRSTRLEN];
	struct pollfd		pfd[NUMSOCKS];

	/*
	 * 接続待機するソケットの設定。1 つは IPv4 に、
	 * もう 1 つは IPv6 に。
	 */
	laddr4.sin_family = AF_INET;
	laddr4.sin_port = htons(port);
	laddr4.sin_addr.s_addr = INADDR_ANY;

	sock4 = socket(AF_INET, SOCK_STREAM, 0);
	if (sock4 == -1) {
		perror("socket");
		return (-1);
	}

	/* すべての sockaddr_in6 フィールドが 0 であることを確認 */
	bzero(&laddr6, sizeof (laddr6));
	laddr6.sin6_family = AF_INET6;
	laddr6.sin6_port = htons(port);
	laddr6.sin6_addr = in6addr_any;	/* 構造体割り当て */

	sock6 = socket(AF_INET6, SOCK_STREAM, 0);
	if (sock6 == -1) {
		perror("socket");
		(void) close(sock4);
		return (-1);
	}

	/* ローカルアドレスを再使用できるようにシステムに通知 */
	sock_opt = 1;
	if (setsockopt(sock4, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt,
	    sizeof (sock_opt)) == -1 ||
	    setsockopt(sock6, SOL_SOCKET, SO_REUSEADDR, (void *)&sock_opt,
	    sizeof (sock_opt))) {
		perror("setsockopt(SO_REUSEADDR)");
		(void) close(sock4);
		(void) close(sock6);
		return (-1);
	}

	if (bind(sock4, (struct sockaddr *)&laddr4, sizeof (laddr4)) == -1 ||
	    bind(sock6, (struct sockaddr *)&laddr6, sizeof (laddr6)) == -1) {
		perror("bind");
		(void) close(sock4);
		(void) close(sock6);
		return (-1);
	}

	if (listen(sock4, BACKLOG) == -1 || listen(sock6, BACKLOG) == -1) {
		perror("listen");
		(void) close(sock4);
		(void) close(sock6);
		return (-1);
	}

	/* 接続要求のための待機 */
	pfd[0].fd = sock4;
	pfd[1].fd = sock6;
	pfd[0].events = pfd[1].events = POLLIN;

	for (;;) {
		if (poll(pfd, NUMSOCKS, -1) == -1) {
			if (errno != EINTR) {
				perror("poll");
				(void) close(sock4);
				(void) close(sock6);
				return (-1);
			}
			continue;
		}

		if (pfd[0].revents & POLLIN) {		/* IPv4 */
			faddrlen = sizeof (faddr4);
			new_sock = accept(sock4, (struct sockaddr *)&faddr4,
			    &faddrlen);
			if (new_sock == -1) {
				if (errno != EINTR && errno != ECONNABORTED) {
					perror("accept");
				}
				continue;
			}
			(void) printf("Connection from %s/%d¥n",
			    inet_ntop(AF_INET, (void *)&faddr4.sin_addr,
			    addrbuf, sizeof (addrbuf)),
			    ntohs(faddr4.sin_port));
			do_work(new_sock);		/* 作業の実行 */
		}

		if (pfd[1].revents & POLLIN) {		/* IPv6 */
			faddrlen = sizeof (faddr6);
			new_sock = accept(sock6, (struct sockaddr *)&faddr6,
			    &faddrlen);
			if (new_sock == -1) {
				if (errno != EINTR && errno != ECONNABORTED) {
					perror("accept");
				}
				continue;
			}
			(void) printf("Connection from %s/%d¥n",
			    inet_ntop(AF_INET6, (void *)&faddr6.sin6_addr,
			    addrbuf, sizeof (addrbuf)),
			    ntohs(faddr6.sin6_port));
			do_work(new_sock);		/* 作業の実行 */
		}
	}
	/*NOTREACHED*/
}

void
do_work(int sock)
{
	char		buf[BUFSIZ];
	int		cc;

	while (1) {
		cc = read(sock, buf, sizeof (buf));
		if (cc == -1) {
			perror("read");
			exit(1);
		}
		if (cc == 0) {
			/* EOF */
			(void) close(sock);
			(void) printf("Connection closed¥n");
			return;
		}
		buf[cc + 1] = '¥0';
		(void) printf("Read <%s>¥n", buf);

		if (write(sock, buf, cc) == -1) {
			perror("write");
			exit(1);
		}
	}
}

main(int argc, char *argv[])
{
	if (argc != 2) {
		(void) fprintf(stderr,
		    "Usage: %s <port>¥n", argv[0]);
		exit(1);
	}
	(void) myserver4(htons(atoi(argv[1])));
	return (0);
}

この make ファイルは、この付録の例の一部またはすべてをコンパイルおよびリンクします。また、lint も行います。

SRC	 = myconnect.c myconnect2.c myconnect3.c myconnect2all.c ¥
	   myserver.c myserver2.c myserver3.c myserver4.c

EXES	 = $(SRC:%.c=%)
LINTOUT  = $(SRC:%.c=%.lint)

#TOOLSDIR = /ws/on28-tools/SUNWspro/SC5.0/bin
#CC       = $(TOOLSDIR)/cc
#LINT.c   = $(TOOLSDIR)/lint

CFLAGS   = -g
LDLIBS   = -lsocket -lnsl
LFLAGS   = $(CFLAGS) 
LINTOPTS = $(LFLAGS) $(LIBS)

all: $(EXES)
lint: $(LINTOUT)

myconnect.o: myconnect.c 
	$(CC) -c -o $@ $(CFLAGS) myconnect.c

myconnect2.o: myconnect2.c 
	$(CC) -c -o $@ $(CFLAGS) myconnect2.c
	
myconnect2all.o: myconnect2all.c 
	$(CC) -c -o $@ $(CFLAGS) myconnect2all.c
	
myconnect3.o: myconnect3.c 
	$(CC) -c -o $@ $(CFLAGS) myconnect3.c

myserver.o: myserver.c 
	$(CC) -c -o $@ $(CFLAGS) myserver.c

myserver2.o: myserver2.c 
	$(CC) -c -o $@ $(CFLAGS) myserver2.c

myserver3.o: myserver3.c 
	$(CC) -c -o $@ $(CFLAGS) myserver3.c

myconnect.lint:
	$(LINT.c) $(LINTOPTS) myconnect.c

myconnect2.lint:
	$(LINT.c) $(LINTOPTS) myconnect2.c

myconnect2all.lint:
	$(LINT.c) $(LINTOPTS) myconnect2all.c

myconnect3.lint:
	$(LINT.c) $(LINTOPTS) myconnect3.c

myserver.lint:
	$(LINT.c) $(LINTOPTS) myserver.c

myserver2.lint:
	$(LINT.c) $(LINTOPTS) myserver2.c

myserver3.lint:
	$(LINT.c) $(LINTOPTS) myserver3.c

myserver4.lint:
	$(LINT.c) $(LINTOPTS) myserver4.c

clean:
	rm -f *.o core