システムプログラム(第8週): ネットワーク・プログラミング/UDP

                                       筑波大学 システム情報工学研究科 
                                       コンピュータサイエンス専攻, 電子・情報工学系
                                       新城 靖
                                       <yas@is.tsukuba.ac.jp>

このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~syspro/2007/No8.html
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~syspro/2007/
http://www.coins.tsukuba.ac.jp/~yas/

捕捉

HTTP のエラーは、次のようになる。
% telnet www 80 [←]
Trying 130.158.86.207...
Connected to orchid-nwd.coins.tsukuba.ac.jp.
Escape character is '^]'.
GET /.. HTTP/1.0[←]
[←]
HTTP/1.1 400 Bad Request
Date: Tue, 05 Jun 2007 09:52:56 GMT
Server: Apache/2.0.55 (Unix) PHP/4.4.2
Content-Length: 324
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
<hr>
<address>Apache/2.0.55 (Unix) PHP/4.4.2 Server at www2.coins.tsukuba.ac.jp Port 80</address>
</body></html>
Connection closed by foreign host.
% []
このうち、1行目、Content-Type:、空行、本文はしっかり返したい。

次の場所に、作りかけの HTTP サーバがある。

~yas/syspro/ipc/http-server.c
常に hello. と返すサーバ。
~yas/syspro/ipc/http-server-error.c
常に 400 Bad Request を返すサーバ。
この中にある 400 Bad Request を返す関数を利用してもよい。
int
http_send_reply_bad_request( FILE *out )
{
	fprintf(out,"HTTP/1.0 400 Bad Request\r\nContent-Type: text/html\r\n\r\n");
    	fprintf(out,"<html><head></head><body>400 Bad Request</body></html>\n");
}
実際の Web サーバでは、exit() することは許されない。攻撃が成功したとも 言える。

今日の重要な話

UDP/IP によるネットワーク・プログラミング

復習

UDP/IPの考え方

UDP/IP は、IP と同じく、 データグラム転送サービス を提供する。データグラムでは、ストリーム(TCP/IP)とは異なり、通信路を 開設することなく、アドレスを指定してデータを送る。UDP/IP では、アドレ スとしては、次の2つを使う。
  1. IP アドレス(IPv4 で 32 ビット、IPv6 で 128 ビット)
  2. ポート番号(16ビット)

IP 層では、アドレスとしては、IP アドレスだけを使う。UDP/IP は、IP 層の 機能をほとんどそのままの形で利用可能にしたものである。違いは、ポート番 号を指定できることと、チェックサムでデータの内容を検査できることなどで ある。

UDP/IP でも、クライアント側のアドレスは、OSに任せ、自らは指 定しないことが多い(指定することもできる)。

UDP/IP でも、通信パタンによる クライアント・サーバ・モデル に基づくことが多い。

図? UDP/IPによるクライアント・サーバ型の通信

図? UDP/IPによるクライアント・サーバ型の通信

UDPの特徴

TCP/IP で提供されているストリームと比較して、UDP/IP で提供されているデー タグラムには次のような特徴がある。 UDP/IP では、connect() しなければ、1つのソケットで、複数の通信相手と データを送受信することができる。通信相手は、sendto() で指定し、 recvfrom() で任意の場所から受信することが普通である。connect() システ ムコールを使うと、特定の相手としか通信できなくなるが、connect() を使う 方法は、UDP/IP のプログラムの書き方としては一般的ではない。

telnet

telnet は、TCP/IP の汎用のクライアント(文字列の送受信用)として使える。 しかし、UDP/IP 用のクライアントとしては使えない。

echo-client-udp

UDP/IP のポート番号 7 (echo) では、受け取ったデータをそのまま返すサー ビスを提供している。ただし、セキュリティ上の理由から、echo サービスを 停止することが、一般的である。以下は、このサービスを利用するクライアン トである。
   1:	
   2:	/*
   3:	        echo-client-udp.c -- 文字列を送受信するクライアント(UDP/IP版)
   4:	        ~yas/syspro/ipc/echo-client-udp.c
   5:	        Created on: 1997/06/16 21:22:26
   6:	*/
   7:	#include <stdio.h>
   8:	#include <stdlib.h>     /* exit() */
   9:	#include <sys/types.h>  /* socket() */
  10:	#include <sys/socket.h> /* socket() */
  11:	#include <netinet/in.h> /* struct sockaddr_in */
  12:	#include <netdb.h>      /* getaddrinfo() */
  13:	#include <string.h>     /* strlen() */
  14:	
  15:	extern void echo_client_udp( char *server, int portno );
  16:	extern int udp_port_nobind();
  17:	extern  int sockaddr_in_init( struct sockaddr_in *addr, int addrlen,
  18:	                              char *hostname, int portno );
  19:	extern void sockaddr_print( struct sockaddr *addrp, socklen_t addr_len );
  20:	extern void sockname_print( int s );
  21:	
  22:	main( int argc, char *argv[] )
  23:	{
  24:	     char *server ;
  25:	     int portno ;
  26:	        if( argc != 3 )
  27:	        {
  28:	            fprintf( stdout,"Usage: %% %s host port\n",argv[0] );
  29:	            exit( -1 );
  30:	        }
  31:	        server = argv[1] ;
  32:	        portno = strtol( argv[2],0,10 );
  33:	        echo_client_udp( server, portno );
  34:	}
  35:	

main の部分は、TCP/IP 版の echo サービスのクライアント とほとんど同じである。

main() 関数は、コマンドラインの引数を調べて、echo_client() を読んでい る。strtol() で、文字列で与えられたポート番号を、int に変換している。

  36:	#define BUFFERSIZE      1024
  37:	
  38:	void
  39:	echo_client_udp( char *server, int portno )
  40:	{
  41:	    int          sock ;
  42:	    int          slen,scount,rcount ;
  43:	    char         sbuf[BUFFERSIZE];
  44:	    char         rbuf[BUFFERSIZE];
  45:	    int          i ;
  46:	    socklen_t    fromlen ;
  47:	    struct sockaddr_in to; struct sockaddr_storage from ;
  48:	
  49:	        sock = udp_port_nobind();
  50:	        if( sock<0 )
  51:	            exit( -1 );
  52:	        printf("my port is "); sockname_print( sock ); printf("\n");
  53:	
  54:	        if( sockaddr_in_init( &to, sizeof(to), server, portno )<0 )
  55:	        {
  56:	            perror("sockaddr_in_init");
  57:	            exit( -1 );
  58:	        }
  59:	        printf("server is ");
  60:	        sockaddr_print( (struct sockaddr *)&to, sizeof(to) ); printf("\n");
  61:	
  62:	        printf("==> "); fflush(stdout);
  63:	        while( fgets(sbuf,BUFFERSIZE,stdin) )
  64:	        {
  65:	            slen = strlen( sbuf );
  66:	            printf("sending [%s] (%d bytes) to ", sbuf, slen );
  67:	            sockaddr_print( (struct sockaddr *)&to, sizeof(to) ); printf("\n");
  68:	
  69:	            scount = sendto( sock, sbuf, slen, 0,
  70:	                             (struct sockaddr *)&to, sizeof(to) );
  71:	            if( scount != slen )
  72:	            {
  73:	                perror("sendto()");
  74:	                exit( 1 );
  75:	            }
  76:	            printf("after sendo(), my port is "); sockname_print( sock ); printf("\n");
  77:	
  78:	            fromlen = sizeof( from );
  79:	            rcount = recvfrom( sock, rbuf, BUFFERSIZE, 0,
  80:	                               (struct sockaddr *)&from, &fromlen);
  81:	            if( rcount < 0 )
  82:	            {
  83:	                perror("recvfrom()");
  84:	                exit( 1 );
  85:	            }
  86:	            rbuf[rcount] = 0 ;
  87:	            printf("received %d bytes [%s] from ",rcount, rbuf );
  88:	            sockaddr_print( (struct sockaddr *)&from, fromlen ); printf("\n");
  89:	
  90:	            printf("==> "); fflush(stdout);
  91:	        }
  92:	        printf("\n");
  93:	
  94:	        close( sock );
  95:	}
  96:	

echo_client_udp() では、udp_port_nobind() という関数を呼び出している。 この結果、UDP/IP の通信用ポートが作られ、通信可能なファイル記述子が返される。 ただし、サーバとの間には、通信路は確保されない。このファイル記述子は、 標準入出力(0,1,2)や open() システム・コールの結果と同じもので、不要に なったら close() で解放する。しかし、この状態では、write() や read() システムコールは使えない。その代りに、sendto() や recvfrom() システム コールを使う。

クライアント側では、bind() でアドレス(IPアドレスとポート番号)を設定し ないことが多い。通信に使う前には、アドレスは固定されていない。通信に使 うと、その瞬間に固定され、close() するまで有効である。(クライアント側 でも、bind() でアドレスを固定することもできるが、一般的ではない。)

sockaddr_in_init() は、構造体 to に送り先のアドレス(IPアドレスとポート 番号)をセットしている。

送るデータは、TCP/IP版の同じく文字列である。UDP/IP の通信では、データ の区切りは保存されるので、行末の区切りをつけずに構造体をそのまま送るも のも多い。

sendto() システムコールで、データを送信している。送り先は、第5引数に指 定されている。TCP/IP とは異なり、データの区切りは保存される。また、一 度に全データが送られるので、TCP/IP とは異なり、全デー タを送り出すためのループは不要である。ただし、一度に送ることができるデー タの大きさには上限がある。

途中、階層の通信媒体の上限を越えた場合、「フラグメント化」が行われ、実 際のデータとしては分割されることがある。たとえば、イーサネットでは、 1500バイトを越えた場合、フラグメント化される。フラグメント化されたデー タは、受信側のプロセスに送られる前に組み立てられる。

データを受け取るには、recvfrom() システムコールを使っている。この時、 データの送り手のアドレス(IPアドレスとポート番号)が&from番 地に保存される。普通は、sendto() と同じアドレスから返ってくるが、 違うアドレスから返ってくることもある。

recvfrom() では、最後に終端の 0 を付けてくれないので、自分で 0 を付け ている。

  97:	int
  98:	udp_port_nobind()
  99:	{
 100:	    int s ;
 101:	        if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0 )
 102:	        {
 103:	            perror("socket");
 104:	            return( -1 );
 105:	        }
 106:	        return( s );
 107:	}
 108:	

udp_port_nobind() は、クライアント側の UDP/IP のポートを作る関数である。 内部では、ソケットを socket() システムコールで作成しているだけである。 PF_INET と SOCK_DGRAMの組み合わせなので、 UDP を使うことを意味する。 socket() の引数で、PF_INET の変りに、AF_INET と書いてもよい。ここでは、 Protocol を選んでいるので、PF_ が正しいが、実際には、PF_INET と AF_INET は同じであり、また、多くのテキストで混在されて使われいる。

UDP/IP でも、connect() システムコールで接続先を固定する方法もあるが、 一般的ではない。接続先を固定した場合は、sendto() や recvfrom() ではな く、write() やread() を使って通信することもできる。その場合も、UDP の 性質は保たれるので、write() したデータのパケットが失われた時には、再転 送は行われない。

 109:	int
 110:	sockaddr_in_init( struct sockaddr_in *addr, int addrlen,
 111:	                  char *hostname, int portno )
 112:	{
 113:	    struct addrinfo hints, *ai;
 114:	    int err ;
 115:	
 116:	        if( addrlen < sizeof(struct sockaddr_in) )
 117:	        {
 118:	            fprintf(stderr,"sockaddr_in, not enough space (%d) > (%d)\n",
 119:	                     addrlen, sizeof(struct sockaddr_in) );
 120:	            return( -1 );
 121:	        }
 122:	        memset( &hints, 0, sizeof(hints) );
 123:	        hints.ai_family   = AF_INET ; /* IPv4 */
 124:	        if( (err = getaddrinfo( hostname, NULL, &hints, &ai )) )
 125:	        {
 126:	            fprintf(stderr,"unknown host %s (%s)\n",hostname,
 127:	                    gai_strerror(err) );
 128:	            return( -1 );
 129:	        }
 130:	        if( ai->ai_addrlen > addrlen )
 131:	        {
 132:	            fprintf(stderr,"sockaddr too large (%d) > (%d)\n",
 133:	                    ai->ai_addrlen,sizeof(addr) );
 134:	            freeaddrinfo( ai );
 135:	            return( -1 );
 136:	        }
 137:	        memcpy( addr, ai->ai_addr, ai->ai_addrlen );
 138:	        addr->sin_port = htons( portno );
 139:	        freeaddrinfo( ai );
 140:	
 141:	        return( 0 );
 142:	}

sockaddr_in_init() は、 TCP/IPのechoクライアントで用いたものと同じものである。

UDP/IP の場合も、TCP/IP と同様に、アドレスの指定には、sockaddr_in 構造 体を使う。sendto() システムコールのマニュアルには、sockaddr 構造体を使 うようにと書かれているが、UDP/IP (IPv4) では、そのサブクラス(オブジェ クト指向用語)であるsockaddr_in を使う。この場合、IP アドレスとポート番 号が埋められている必要がある。その他に先頭に、sockaddr_in であることを 示す定数 AF_INET を置く。 getaddrinfo() は、ホスト名を IP アドレスし、さらに、先頭に定数 AF_INET を設定している。ポート番号は、第2引数が NULL なので、0 を指定している。 この例では、引数で与えられたポート番号を htons() を介してバイトオーダ を調整してから設定している。

 143:	
 144:	void
 145:	sockaddr_print( struct sockaddr *addrp, socklen_t addr_len )
 146:	{
 147:	    char host[BUFFERSIZE] ;
 148:	    char port[BUFFERSIZE] ;
 149:	        if( getnameinfo(addrp, addr_len, host, sizeof(host),
 150:	                        port, sizeof(port), NI_NUMERICHOST|NI_NUMERICSERV)<0 )
 151:	            return;
 152:	        printf("%s:%s", host, port );
 153:	}
 154:	
 155:	void
 156:	sockname_print( int s )
 157:	{
 158:	    struct sockaddr_storage addr ;
 159:	    socklen_t len ;
 160:	        len = sizeof( addr );
 161:	        if( getsockname( s, (struct sockaddr *)&addr, &len )< 0 )
 162:	        {
 163:	            perror("getsockname");
 164:	            exit( -1 );
 165:	        }
 166:	        sockaddr_print( (struct sockaddr *)&addr,len );
 167:	}

sockaddr_print() は、 echo-server-nofork-fdopen.c のものと同じである。 getaddrinfo() ライブラリ関数により、ホスト名とポート番号の文字列表現を 得ている。文字列といっても、NI_NUMERICHOST|NI_NUMERICSERV というフラグ を指定しているので、結果は "123.4.5.6" や "80" のような数字の並びによ る表記になる。

sockname_print() は、自分自身のポートのアドレスを表示する関数である。 アドレスは、getsockname() で得られる。なお、UDP/IP では、TCP/IP とは異 なり、getpeername() で通信相手を調べることは、この場合できない。UDP/IP では、通信相手は、recvfrom() の引数で知ることができる。 sockname_print() は、 echo-server-nofork-fdopen.c の tcp_peeraddr_print() の getpeername() を、getsockname() に変えたものである。getsockname() は、自分自身の名前(TCP/IP では、IP アドレスとポート番号)を得るためのシステムコールである。

注意:メッセージの送り先としては、 echo-server-udp.c を用いている。 標準の 7 番ポートで動作しているものは、うまく動作しない。

実行例:

% cp ~yas/syspro/ipc/echo-client-udp.c .  [←]
% make echo-client-udp [←]
cc     echo-client-udp.c   -o echo-client-udp
% ./echo-client-udp azalea20.coins.tsukuba.ac.jp 1231 [←]
my port is 0.0.0.0:0
server is 130.158.86.40:1231
==> hello[←]
sending [hello
] (6 bytes) to 130.158.86.40:1231
after sendo(), my port is 0.0.0.0:53397
received 6 bytes [hello
] from 130.158.86.40:1231
==> world![←]
sending [world!
] (7 bytes) to 130.158.86.40:1231
after sendo(), my port is 0.0.0.0:53397
received 7 bytes [world!
] from 130.158.86.40:1231
==> ^D
% ./echo-client-udp azalea20.coins.tsukuba.ac.jp 1231 [←]
my port is 0.0.0.0:0
server is 130.158.86.40:1231
==> aaa[←]
sending [aaa
] (4 bytes) to 130.158.86.40:1231
after sendo(), my port is 0.0.0.0:53398
received 4 bytes [aaa
] from 130.158.86.40:1231
==> bbb[←]
sending [bbb
] (4 bytes) to 130.158.86.40:1231
after sendo(), my port is 0.0.0.0:53398
received 4 bytes [bbb
] from 130.158.86.40:1231
==> ^D
% []
このプログラムは、コマンドラインから2の引数をとる。第1引数は、ホスト 名、第2引数は、ポート番号である。このプログラムは、標準入力から得られ た行を、その指定されたホスト上のポート番号で動作しているサーバに対して 送る。サーバは、 同じものを送り返してくるので、それを受け取る。

echo-server-udp.c

UDP/IP のポート番号 7 (echo) では、受け取ったデータをそのまま返すサー ビスを提供している。以下は、これと同じような機能を提供するサーバである。
   1:	
   2:	/*
   3:	        echo-server-udp.c -- 文字列を送受信するサーバ(UDP/IP版)   
   4:	        ~yas/syspro/ipc/echo-server-udp.c
   5:	        Created on: 1997/06/16 21:22:26
   6:	*/
   7:	
   8:	#include <stdio.h>
   9:	#include <stdlib.h>     /* exit() */
  10:	#include <sys/types.h>  /* socket() */
  11:	#include <sys/socket.h> /* socket() */
  12:	#include <netinet/in.h> /* struct sockaddr_in */
  13:	#include <netdb.h>      /* getaddrinfo() */
  14:	#include <string.h>     /* memset() */
  15:	
  16:	extern void echo_server_udp( int portno );
  17:	extern int udp_port_bind( int portno );
  18:	extern void sockaddr_print( struct sockaddr *addrp, socklen_t addr_len );
  19:	extern void sockname_print( int s );
  20:	
  21:	main( int argc, char *argv[] )
  22:	{
  23:	    int portno ;
  24:	        if( argc >= 3 )
  25:	        {
  26:	            fprintf( stdout,"Usage: %s [portno]\n",argv[0] );
  27:	            exit( -1 );
  28:	        }
  29:	        if( argc == 2 )
  30:	            portno = strtol( argv[1],0,10 );
  31:	        else
  32:	            portno = getuid();
  33:	        echo_server_udp( portno );
  34:	}
  35:	

TCP版のecho サービスのサーバ と同様に、 引数として、ポート番号を取る。ポート番号が与えられなければ、そのプロセ スの UID (User ID) から生成する。UID は、個人個人を識別するための番号 (16ビット程度、システムによっては 32 ビット)である。この課題では、(1台 のコンピュータでは)個人ごとに別々の UID を使う必要がある。上のように UID から生成する方法は、一般的ではない。(筑波大学情報学類のシステムで はうまく働く。)

  36:	#define BUFFERSIZE      1024
  37:	
  38:	void
  39:	echo_server_udp( int portno )
  40:	{
  41:	    int s, rcount, scount;
  42:	    struct sockaddr_storage addr ;
  43:	    socklen_t addrlen ;
  44:	    char buffer[BUFFERSIZE];
  45:	
  46:	        s = udp_port_bind( portno );
  47:	        if( s<0 )
  48:	            exit( -1 );
  49:	        printf("my port is "); sockname_print( s ); printf("\n");
  50:	
  51:	        while( 1 )
  52:	        {
  53:	            addrlen = sizeof( addr );
  54:	            rcount = recvfrom( s, buffer, BUFFERSIZE, 0,
  55:	                               (struct sockaddr *)&addr, &addrlen );
  56:	            if( rcount < 0 )
  57:	            {
  58:	                perror("recvfrom()");
  59:	                exit( 1 );
  60:	            }
  61:	            buffer[rcount] = 0 ;
  62:	            printf("received %d bytes [%s] from ",rcount, buffer );
  63:	            sockaddr_print( (struct sockaddr *)&addr,addrlen ); printf("\n");
  64:	
  65:	            printf("sending back [%s] (%d bytes) to ", buffer, rcount );
  66:	            sockaddr_print( (struct sockaddr *)&addr,addrlen ); printf("\n");
  67:	            scount=sendto( s, buffer, rcount, 0, (struct sockaddr *)&addr, addrlen );
  68:	            if( scount!= rcount )
  69:	            {
  70:	                perror("sendto()");
  71:	                exit( 1 );
  72:	            }
  73:	        }
  74:	}
  75:	

udp_port_bind() は、引数で与えられたポート番号を使ってUDP/IP のポート を作成し、そのファイル記述子(ソケット)を返す。sockname_print() は、そ のアドレス(IPアドレスとポート番号)を表示する。 TCP/IP とは異なり、このポートは、そのまま通信に使うことができる。 逆に、accept() は使うことはできない。

サーバのプログラムの特徴は、内部に無限ループを持っていることである。 サーバは、普通の状態では、終了しない。

このサーバは、fork() しない。サービスの内容が簡単であり、sendto() シス テムコールでブロックすることもないからである。サービスが重たい時には、 他のクライアントからの処理を並列に進めるために、子プロセスを作ること可 能である。

  76:	int
  77:	udp_port_bind( int portno )
  78:	{
  79:	    struct sockaddr_in addr ;
  80:	    int addr_len ;
  81:	    int s ;
  82:	
  83:	        if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0 )
  84:	        {
  85:	            perror("socket");
  86:	            return( -1 );
  87:	        }
  88:	
  89:	        memset( &addr, 0, sizeof(addr) );
  90:	        addr.sin_family = AF_INET ;
  91:	        addr.sin_addr.s_addr = INADDR_ANY ;
  92:	        addr.sin_port = htons( portno );
  93:	
  94:	        if( bind(s,(struct sockaddr *)&addr,sizeof(addr)) < 0 )
  95:	        {
  96:	            perror("bind");
  97:	            fprintf(stderr,"port number %d is already used. wait a moment or kill another program.\n", portno );
  98:	            return( -1 );
  99:	        }
 100:	        return( s );
 101:	}
...
 104:	sockaddr_print( struct sockaddr *addrp, socklen_t addr_len )
...
 115:	sockname_print( int s )

udp_port_bind() は、サーバ用に、ポート番号を固定した UDP/IP のポートを作成する。 クライアント側との違いは、 bind() システムコールを使っている点にある。

bind() システムコールの引数は、 TCP版のecho サービスのサーバ と同じである。 ソケットが作成できたら、bind() システムコールで、サーバ側で利用するア ドレス(IPアドレスとポート番号)を設定する。IP アドレスは、普通は、 INADDR_ANY を指定する。複数の IP アドレスがある時には、どれに要求が来 ても受け付ける。特定の IP アドレスを指定すると、そのアドレスに来た要求 だけを受け付けるようになる。

ポート番号は、引数で与えられたものを、htons() でネットワーク・バイトオー ダに変換して与える。

listen() システムコールは、UDP/IP では使われない。 要求、すなわち、データが大量に送られ、サーバが処理できない時には、(普 通は古いものから順に)捨てられる。

実行例。

サーバは、終了しないので、最後に、^C を押して、割り込みを掛け て終了させる。

注意:全員が同じコンピュータでポート番号 1231 を使うとプログラムが動かないことがある。

% cp ~yas/syspro/ipc/echo-server-udp.c . [←]
% make echo-server-udp [←]
cc     echo-server-udp.c   -o echo-server-udp
% ./echo-server-udp 1231 [←]
my port is 0.0.0.0:1231
received 6 bytes [hello
] from 130.158.86.50:53397
sending back [hello
] (6 bytes) to 130.158.86.50:53397
received 7 bytes [world!
] from 130.158.86.50:53397
sending back [world!
] (7 bytes) to 130.158.86.50:53397
received 4 bytes [aaa
] from 130.158.86.50:53398
sending back [aaa
] (4 bytes) to 130.158.86.50:53398
received 4 bytes [bbb
] from 130.158.86.50:53398
sending back [bbb
] (4 bytes) to 130.158.86.50:53398
^C
% []
サーバ側では、bind() をつかっているので、最初からポート番号が固定され ていることがわかる。

練習問題

練習問題(801) Javaによるecho-client-udpの実現

echo-client-udp.c を Java で書き直しなさい。

ヒント:DatagramSocket() を使う。

練習問題(802) Javaによるecho-server-udpの実現

echo-server-udp.c を Java で書き直しなさい。

練習問題(803) UDP/IPで送れるデータの大きさの上限

UDP/IP では、一度に送ることができるデータの大きさにには、実装上の制限 が付いている。これがいくつかを調べるプログラムを作りなさい。

練習問題(804) udprelay

UDP/IP のデータを中継するようなプログラムを作りなさい。 単方向だけでなく、双方向で中継するようにしなさい。

このようなプログラムの例として、udprelay と呼ばれるプログラムがある。

練習問題(805) UDP/IPでのアクセス制御

UDP/IP のサーバ、または、中継プログラムで、クライアントの IP アドレス によってアクセスを許したりエラーを発生させたりしなさい。

練習問題(806) UDP/IPによるサービスの利用

次の UDP/IP で提供されているサービスを利用するクライアントを作成しなさい。
daytime (13, Daytime Protocol)
rfc867.txt
time (37, Time Protocol)
rfc868.txt
NTP (123, Network Time Protocol)
rfc1305.tx
DNS (53, Domain Name System)
rfc1034.txt, rfc1035.txt
それぞれのプロトコルでは、次のホストで動いているサーバを使いなさい。
daytime, time
azalea1-azalea45, balsam1-balsam60, canna1-canna50, localhost
NTP
orchid-nwa
DNS
orchid-nwa, orchid-nwb

Last updated: 2007/06/05 19:04:29
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>