プロセス間通信、UDP/IP

システム・プログラムI

                                       電子・情報工学系
                                       新城 靖
                                       <yas@is.tsukuba.ac.jp>

このページは、次の URL にあります。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/syspro1-1997/1997-06-17
あるいは、次のページから手繰っていくこともできます。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/
http://www.hlla.is.tsukuba.ac.jp/~yas/index-j.html

■復習

■ゾンビ・プロセス

exit(2) システム・コールで終了したり、ソフトウェア割り込み(kill(2))で 強制終了させれたプロセスは、親プロセスが wait() するまで、形だけのこっ ている。このようなプロセスは、ゾンビ(Zombie)と呼ばれる。

★練習問題(41) ゾンビの消去

echo-server-fork.c では、ゾンビ・プロセスがどんどん残ってしまう。これ を残らないようにしなさい。

ヒント:accept() で止まる前に、wait() する方法がある。ただし、単純に wait() すると、fork() の効果がまったくなくなる。子プロセスが終了したと きだけ、wait() したい。それには、waitpid() や wait3(), wait4() で、あ るオプションを使うとよい。

ヒント:子プロセスの終了を、ソフトウェア割り込み(SIGCLD)で知る方法もあ る。複数の子プロセスが終了しても、割り込みは1回しか起こらないことがあ ることに注意しなさい。

■HTTP Proxy

HTTP のレベルで、クライアントとサーバの間を中継するプログラムを、HTTP Proxy と呼ぶ。HTTP Proxy は、クライアントから見ると、サーバに見え、サー バから見ると、クライアントに見える。

HTTP Proxy は、次のような目的に使われる。

★練習問題(42) HTTP Proxy

HTTP proxy 作りなさい。キャッシングが、防火壁越えか、フィルタリングの 機能を付けなさい。

■echo-server-select

■echo-client-udp

UDP/IP のポート番号 7 (echo) では、受け取ったデータをそのまま返すサー ビスを提供している。以下は、このサービスを利用するクライアントである。

----------------------------------------------------------------------
   1:	
   2:	/*
   3:	        echo-client-udp.c -- 文字列を送受信するクライアント(UDP/IP版)
   4:	        /usr/local/LECTURES/syspro-1997-shinjo/ipc/echo-client-udp.c
   5:	        $Header: echo-client-udp.c,v 1.2 97/06/16 22:11:03 yas Exp $
   6:	        Start: 1997/06/16 21:22:26
   7:	*/
   8:	#include <stdio.h>
   9:	#include <sys/socket.h> /* socket() */
  10:	#include <netinet/in.h> /* struct sockaddr_in */
  11:	#include <netdb.h>      /* gethostbyname() */
  12:	
  13:	main( argc,argv )
  14:	    int argc ;
  15:	    char *argv[] ;
  16:	{
  17:	        if( argc != 3 )
  18:	        {
  19:	            fprintf( stdout,"Usage: %s host port\n",argv[0] );
  20:	            exit( -1 );
  21:	        }
  22:	        recho( argv[1],atoi(argv[2]) );
  23:	}
  24:	
  25:	#define BUFFSIZE        1024
  26:	
  27:	recho( hostname,portno )
  28:	    char *hostname ;
  29:	    int portno ;
  30:	{
  31:	    int s, rcount, scount, len, fromlen ;
  32:	    struct sockaddr_in to, from ;
  33:	    char buff[BUFFSIZE];
  34:	
  35:	        s = udp_port( 0 );
  36:	        if( s<0 )
  37:	            exit( -1 );
  38:	        printf("my port is ");  sockname_print( s );
  39:	
  40:	        sprintf( buff,"hello" );
  41:	        len = strlen( buff ) + 1 ;
  42:	        sockaddr_in_init( &to, hostname, portno );
  43:	        if( scount = sendto( s, buff, len, 0, &to, sizeof(to) )!= len )
  44:	        {
  45:	            perror("sendto()");
  46:	            exit( 1 );
  47:	        }
  48:	
  49:	        fromlen = sizeof( from );
  50:	        if( (rcount = recvfrom( s, buff, BUFFSIZE, 0, &from, &fromlen )) < 0 )
  51:	        {
  52:	            perror("recvfrom()");
  53:	            exit( 1 );
  54:	        }
  55:	        printf("received from "); sockaddr_in_print( &from );
  56:	        buff[rcount] = 0 ;
  57:	        printf("%d bytes received. [%s] \n", rcount, buff );
  58:	
  59:	        close( s );
  60:	}
  61:	
  62:	int udp_port( portno )
  63:	    int portno ;
  64:	{
  65:	    struct hostent *hostent ;
  66:	    struct sockaddr_in addr ;
  67:	    int addr_len ;
  68:	    int s ;
  69:	
  70:	        if( (s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )
  71:	        {
  72:	            perror("socket");
  73:	            return( -1 );
  74:	        }
  75:	
  76:	        addr.sin_family = AF_INET ;
  77:	        addr.sin_addr.s_addr = INADDR_ANY ;
  78:	        addr.sin_port = htons( portno );
  79:	
  80:	        if( bind(s,&addr,sizeof(addr)) < 0 )
  81:	        {
  82:	            perror( "bind: " );
  83:	            fprintf(stderr,"port number %d is already used. kill another program.", portno );
  84:	            return( -1 );
  85:	        }
  86:	        return( s );
  87:	}
  88:	
  89:	sockaddr_in_init( addr, hostname, portno )
  90:	    struct sockaddr_in *addr ;
  91:	{
  92:	    struct hostent *hostent ;
  93:	        addr->sin_family = AF_INET ;
  94:	        if( (hostent = gethostbyname( hostname )) == NULL )
  95:	        {
  96:	            fprintf(stderr,"unknown host %s\n",hostname );
  97:	            return( -1 );
  98:	        }
  99:	        bcopy( hostent->h_addr, &addr->sin_addr, hostent->h_length );
 100:	        addr->sin_port = htons( portno );
 101:	        return( 0 );
 102:	}
 103:	
 104:	sockaddr_in_print( addr )
 105:	    struct sockaddr_in *addr ;
 106:	{
 107:	    union {
 108:	        int i ;
 109:	        unsigned char byte[4] ;
 110:	    } x ;
 111:	        x.i = addr->sin_addr.s_addr ;
 112:	        printf("sockaddr_in: %d.%d.%d.%d:%d\n",
 113:	               x.byte[0],x.byte[1],x.byte[2],x.byte[3],
 114:	               ntohs( addr->sin_port ));
 115:	}
 116:	
 117:	sockname_print( s )
 118:	{
 119:	    struct sockaddr_in addr ;
 120:	    int len ;
 121:	        len = sizeof( addr );
 122:	        if( getsockname( s, &addr, &len )< 0 )
 123:	        {
 124:	            perror("getsockname");
 125:	            exit( -1 );
 126:	        }
 127:	        sockaddr_in_print( &addr );
 128:	}
----------------------------------------------------------------------

bind() では、INADDR_ANY, porno=0 で名前を付けている。これにより、オペ レーティング・システムが、空いているポートを割り当てる。こうして割り当 てられた番号は、後で getsockname() で調べることができる。

実行例。


----------------------------------------------------------------------
% ./echo-client-udp localhost 7 [←]
my port is sockaddr_in: 0.0.0.0:2751
received from sockaddr_in: 127.0.0.1:7
6 bytes received. [hello] 
% ./echo-client-udp adonis5 7 [←]
my port is sockaddr_in: 0.0.0.0:2786
received from sockaddr_in: 130.158.87.5:7
6 bytes received. [hello] 
% []
----------------------------------------------------------------------

■echo-server-udp

UDP/IP のポート番号 7 (echo) では、受け取ったデータをそのまま返すサー ビスを提供している。以下は、これと同じような機能を提供するサーバである。

----------------------------------------------------------------------
   1:	
   2:	/*
   3:	        echo-server-udp.c -- 文字列を送受信するサーバ(UDP/IP版)
   4:	        /usr/local/LECTURES/syspro-1997-shinjo/ipc/echo-server-udp.c
   5:	        $Header: echo-server-udp.c,v 1.2 97/06/16 22:10:53 yas Exp $
   6:	        Start: 1997/06/16 21:22:26
   7:	*/
   8:	#include <stdio.h>
   9:	#include <sys/socket.h> /* socket() */
  10:	#include <netinet/in.h> /* struct sockaddr_in */
  11:	#include <netdb.h>      /* gethostbyname() */
  12:	
  13:	main( argc,argv )
  14:	    int argc ;
  15:	    char *argv[] ;
  16:	{
  17:	    int portno ;
  18:	        if( argc >= 3 )
  19:	        {
  20:	            fprintf( stdout,"Usage: %s host port\n",argv[0] );
  21:	            exit( -1 );
  22:	        }
  23:	        if( argc == 2 )
  24:	            portno = atoi( argv[1] );
  25:	        else
  26:	            portno = getuid();
  27:	        echo_server_udp( portno );
  28:	}
  29:	
  30:	#define BUFFSIZE        1024
  31:	
  32:	echo_server_udp( portno )
  33:	    int portno ;
  34:	{
  35:	    int s, rcount, scount, addrlen ;
  36:	    struct sockaddr_in addr ;
  37:	    char buff[BUFFSIZE];
  38:	
  39:	        s = udp_port( portno );
  40:	        if( s<0 )
  41:	            exit( -1 );
  42:	        printf("my port is ");  sockname_print( s );
  43:	
  44:	        while( 1 )
  45:	        {
  46:	            addrlen = sizeof( addr );
  47:	            if( (rcount = recvfrom( s, buff, BUFFSIZE, 0, &addr, &addrlen )) < 0 )
  48:	            {
  49:	                perror("recvfrom()");
  50:	                exit( 1 );
  51:	            }
  52:	            printf("received from "); sockaddr_in_print( &addr );
  53:	            buff[rcount] = 0 ;
  54:	            printf("%d bytes received. [%s] \n", rcount, buff );
  55:	
  56:	            if( scount = sendto( s, buff, rcount, 0, &addr, addrlen )!= rcount )
  57:	            {
  58:	                perror("sendto()");
  59:	                exit( 1 );
  60:	            }
  61:	        }
  62:	}
<以下省略>
----------------------------------------------------------------------

実行例。

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


----------------------------------------------------------------------
% ./echo-server-udp [←]
my port is sockaddr_in: 0.0.0.0:1231
received from sockaddr_in: 127.0.0.1:1453
6 bytes received. [hello] 
received from sockaddr_in: 130.158.86.225:1466
6 bytes received. [hello] 
received from sockaddr_in: 130.158.87.5:1714
6 bytes received. [hello] 
^C
% []
----------------------------------------------------------------------
クライアント側(その1)。
----------------------------------------------------------------------
% ./echo-client-udp localhost 1231 [←]
my port is sockaddr_in: 0.0.0.0:1453
received from sockaddr_in: 127.0.0.1:1231
6 bytes received. [hello] 
% ./echo-client-udp orchid 1231 [←]
my port is sockaddr_in: 0.0.0.0:1466
received from sockaddr_in: 130.158.86.225:1231
6 bytes received. [hello] 
% []
----------------------------------------------------------------------
クライアント側(その2)。
----------------------------------------------------------------------
% ./echo-client-udp orchid 1231 [←]
my port is sockaddr_in: 0.0.0.0:1714
received from sockaddr_in: 130.158.86.225:1231
6 bytes received. [hello] 
% []
----------------------------------------------------------------------

★[report] report-9,TCP/IPのサーバ(追加・修正)

練習問題(36),(39),(40),(42) の中から1つ以上選んでやりなさい。問題を難 しい方に変更してもよい。 (注意:6月10の印刷資料には、(36) ではなくて、(37)になっていました。 )
↑[もどる] ←[6月10日] ・[6月17日] →[6月24日]
Last updated: 1997/06/23 21:14:38
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>