情報工学実験2「IPv6プログラミング」

055738C 張 暁雪

*目次

*課題1*
*課題2*
*課題3*

*課題1*:tcpv6cはIPv4とIPv6の両方に対応しているにもかかわらず、tcpc(IPv4のみに対応)よりコードが短い。この理由は何故か説明せよ。
理由の説明

◎理由について
 tcpv6cとtcpcのコードの長さが同じくない原因は、アドレスとポート番号の取得に用いる関数である.
tcpv.cの方は、アドレスを調べることとポート番号を調べることの動作を別々で実行する。tcpv6c.cの方は、一
つの関数を用いることで両方の処理を行う。
◎使用している関数について
tcpv6c:
・getaddrinfo()関数:
getaddinfo()関数はgetipnodebyname()、Getipnodebyaddr()、getservbyname()、Getservbyport()
の4つの関数の機能をまとめて1つのインターフェースにしたものである。ネットワークホストのアドレスを取得とポー
ト番号を調べることができる。
tcpc.c:
・gethostbyname()関数:
与えられたホスト名に対応する構造体を返す。
・getservbyname()関数:
プロトコルを用いるサービスの名前にマッチする行を/etc/servicesから探し、その行の内容を含めたservent構
造体を返す.
・atoi()関数:
nptrによって指示される文字列のはじめの部分をint型に変換する。

*課題2*:tcpv6sはAF_INET6でソケットをオープンしているにもかかわらず、IPv4
でも通信できる。この理由は何故か説明せよ。
理由の説明

◎理由について
 IPv6アドレス体系の中には、IPv4射影アドレスと呼ばれるIPv6アドレスが存在する。IPv4射影アドレスはIPv6を
サポートしていないノードのIPv4アドレスをIPv6アドレスとして塀するために使用される。これにより、IPv4しかサ
ポートしないホストとIPv6ホストが通信ができる。
AF_INET6ケットは、IPv6通信とIPv4通信の両方に使用できる。IPv4通信の場合は、AF_INET6ケットを作成し、
IPv4射影IPv6アドレスが含まれるsockaddr_in6構造体にソケットを渡す。したがって、AF_INET6でソケットをオ
ープンしているにも、IPv4でも通信できる。

*課題3*:サンプルプログラム(2)のクライアント(client4.c)とサーバ(server4.c)をアドレスファミリ独立となるように書き換えよ。
a-1.プログラム(client0.c)

#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <errno.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <arpa/inet.h> int main __P((int, char **)); int main(argc, argv) int argc; char **argv; { struct addrinfo hints, *hp; struct servent *sp; unsigned long lport; u_int16_t port; char *ep; int dstlen; size_t l; int s; char buf[1024]; char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; if (argc != 3) { fprintf(stderr, "usage: test host port\n"); exit(1); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; getaddrinfo(argv[1], argv[2], &hints, &hp); if (!hp) { fprintf(stderr, "%s: %s\n", argv[1], hstrerror(h_errno)); exit(1); } sp = getservbyname(argv[2], "TCP"); if (sp) { port = sp->s_port & 0xffff; } else { ep = NULL; errno = 0; lport = strtoul(argv[2], &ep, 10); if (!*argv[2] || errno || !ep || *ep) { fprintf(stderr, "%s: no such service\n", argv[2]); exit(1); } if (lport & ~0xffff) { fprintf(stderr, "%s: out of range\n", argv[2]); exit(1); } port = htons(lport & 0xffff); } endservent(); s = socket(hp->ai_family, hp->ai_socktype, hp->ai_protocol); if (s < 0) { perror("socket"); exit(1); } getnameinfo(hp->ai_addr, hp->ai_addrlen, hbuf, sizeof(hbuf), sbuf, sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV); fprintf(stderr, "trying %s port %u\n", hbuf, ntohs(port)); if (connect(s, hp->ai_addr, hp->ai_addrlen) < 0) { perror("connect"); exit(1); } while ((l = read(s, buf, sizeof(buf))) > 0) write(STDOUT_FILENO, buf, l); close(s); exit(0); }

a-2.プログラム(server0.c)

#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <errno.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <arpa/inet.h> int main __P((int, char **)); int main(argc, argv) int argc; char **argv; { struct servent *sp; unsigned long lport; u_int16_t port; char *ep; struct sockaddr_in6 serv; int servlen; struct sockaddr_in6 from; socklen_t fromlen; int s; int ls; char hbuf[INET6_ADDRSTRLEN]; if (argc != 2) { fprintf(stderr, "usage: test port\n"); exit(1); } sp = getservbyname(argv[1], "tcp"); if (sp) port = sp->s_port & 0xffff; else { ep =NULL; errno = 0; lport =strtoul(argv[1], &ep, 10); if (!*argv[1] || errno || !ep || *ep) { fprintf(stderr, "%s: no such service\n", argv[1]); exit(1); } if (lport & ~0xffff) { fprintf(stderr, "%s: out of range\n", argv[1]); exit(1); } port = htons(lport & 0xffff); } endservent(); memset(&serv, 0, sizeof(serv)); serv.sin6_family = AF_INET6; serv.sin6_len = sizeof(struct sockaddr_in6); serv.sin6_port = port; servlen = sizeof(struct sockaddr_in6); s = socket(AF_INET6, SOCK_STREAM, 0); if (s < 0) { perror("socket"); exit(1); } if (bind(s, (struct sockaddr *)&serv, servlen) < 0) { perror("bind"); exit(1); } if (listen(s, 5) < 0) { perror("listen"); exit(1); } while (1) { fromlen = sizeof(from); ls = accept(s, (struct sockaddr *)&from, &fromlen); if (ls < 0) continue; if (from.sin6_family != AF_INET6 || fromlen != sizeof(struct sockaddr_in6)) { exit(1); } if (inet_ntop(AF_INET6, &from.sin6_addr, hbuf, sizeof(hbuf)) == NULL) { exit(1); } write(ls, "Hello ",6); write(ls, hbuf, strlen(hbuf)); write(ls, "\n", 1); close(ls); } }

b-1.実行結果(サンプルプログラム)

*[nw0538:~]*(^_^)v j05038% cc -o server4 server4.c *[nw0538:~]*(^_^)v j05038% ./server4 usage: test port *[nw0538:~]*(^_^)v j05038% ./server4 5555 ---------------------------------------------------------------------- *[nw0538:~]*(^_^)v j05038% ./client4 133.13.59.38 5555 trying 133.13.59.38 port 5555 Hello 133.13.59.38 *[nw0538:~]*(^_^)v j05038%

b-2.実行結果(アドレスファミリ独立のプログラム)

*[nw0538:~]*(^_^)v j05038% cc -o server0 server0.c *[nw0538:~]*(^_^)v j05038% ./server0 5555 -------------------------------------------------------------------- *[nw0538:~]*(^_^)v j05038% cc -o client0 client0.c *[nw0538:~]*(^_^)v j05038% ./client0 133.13.59.38 5555 trying 133.13.59.38 port 5555 Hello ::ffff:133.13.59.38 *[nw0538:~]*(^_^)v j05038%

考察
◎変更のところについて

・struct sockaddr_in --> struct sockaddr_in6
・hbuf[INET_ADDRSTRLEN]; --> hbuf[INET6_ADDRSTRLEN];
・AF_INET --> AF_INET6
・struct hostentとgethostbyname()をかわりにgetaddrinfo()を使ってリモートホストの情報を取得する。
・inet_ntop()についても変更した。

*感想



今度の課題の考察については難しいと思います。今度のレポートの完成が難しいです。やっはり、
もっと頑張りしなければなりません。