システム・プログラムI
電子・情報工学系
新城 靖
<yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/syspro1-1998/1998-06-23
あるいは、次のページから手繰っていくこともできます。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/
http://www.hlla.is.tsukuba.ac.jp/~yas/index-j.html
----------------------------------------------------------------------
1: /*
2: vaddr-print.c -- 変数の番地をしらべるプログラム
3: ~yas/syspro1/cc/vaddr-print.c
4: $Header: vaddr-print.c,v 1.1 97/05/19 23:19:10 yas Exp $
5: Start: 1997/05/19 22:58:49
6: */
7: #include <stdlib.h>
8:
9: int x1=1 ;
10: int x2 ;
11:
12: extern int etext, edata, end ;
13:
14: main( argc,argv,envp )
15: int argc ;
16: char *argv[] ;
17: char *envp[] ;
18: {
19: int x3 ;
20: char *x4p ;
21:
22: printf("&main == 0x%x \n",&main );
23: printf("&etext == 0x%x \n",&etext );
24: printf("&edata == 0x%x \n",&edata );
25: printf("&end == 0x%x \n",&end );
26:
27: printf("&x1 == 0x%x (data)\n",&x1 );
28: printf("&x2 == 0x%x (bss)\n",&x2 );
29: printf("&x3 == 0x%x (auto)\n",&x3 );
30: x4p = malloc( 10 );
31: printf("x4p == 0x%x (heap)\n",x4p );
32: x4p = malloc( 10 );
33: printf("x4p == 0x%x (heap)\n",x4p );
34: recursive( 3 );
35: }
36:
37: recursive( n )
38: int n ;
39: {
40: int x5 ;
41: printf("&x5 == 0x%x (auto,%d)\n",&x5,n );
42: if( n<=0 )
43: return;
44: recursive( n-1 );
45: }
----------------------------------------------------------------------
実行例。
---------------------------------------------------------------------- % cp ~yas/syspro1/cc/vaddr-print.c .% make vaddr-print
cc vaddr-print.c -o vaddr-print % ./vaddr-print
&main == 0x400ad0 &etext == 0x400cb0 &edata == 0x10002000 &end == 0x10002000 &x1 == 0x100010d0 (data) &x2 == 0x10001130 (bss) &x3 == 0x7fff2f1c (auto) x4p == 0x10002010 (heap) x4p == 0x10002028 (heap) &x5 == 0x7fff2ef4 (auto,3) &x5 == 0x7fff2ecc (auto,2) &x5 == 0x7fff2ea4 (auto,1) &x5 == 0x7fff2e7c (auto,0) % size vaddr-print
text data bss dec hex filename 2933 304 28 3265 cc1 vaddr-print %
----------------------------------------------------------------------
----------------------------------------------------------------------
1:
2: /*
3: echo-client-udp.c -- 文字列を送受信するクライアント(UDP/IP版)
4: ~yas/syspro1/ipc/echo-client-udp.c
5: $Header: /home/lab2/OS/yas/syspro1/ipc/RCS/echo-client-udp.c,v 1.4 1998/06/22 14:23:48 yas Exp $
6: Start: 1997/06/16 21:22:26
7: */
8: #include <stdio.h>
9: #include <sys/types.h> /* socket() */
10: #include <sys/socket.h> /* socket() */
11: #include <netinet/in.h> /* struct sockaddr_in */
12: #include <netdb.h> /* gethostbyname() */
13:
14: extern void echo_client_udp( char *hostname, int portno );
15: extern int udp_port_not_bound();
16: extern int sockaddr_in_init( struct sockaddr_in *addr, char *hostname, int portno );
17: extern void sockaddr_in_print( struct sockaddr_in *addr );
18: extern void sockname_print( int s );
19:
20: main( int argc, char *argv[] )
21: {
22: if( argc != 3 )
23: {
24: fprintf( stdout,"Usage: %s host port\n",argv[0] );
25: exit( -1 );
26: }
27: echo_client_udp( argv[1],atoi(argv[2]) );
28: }
29:
30: void echo_client_udp( char *hostname, int portno )
31: {
32: int s, rcount, scount, len, fromlen ;
33: struct sockaddr_in to, from ;
34: char buf[BUFSIZ];
35:
36: s = udp_port_not_bound();
37: if( s<0 )
38: exit( -1 );
39: printf("my port is "); sockname_print( s );
40:
41: strncpy( buf,"hello",sizeof(buf) );
42: len = strlen( buf ) + 1 ;
43: sockaddr_in_init( &to, hostname, portno );
44: printf("sending [%s] (%d bytes) to ", buf,len );
45: sockaddr_in_print( &to );
46: if( scount = sendto( s, buf, len, 0, &to, sizeof(to) )!= len )
47: {
48: perror("sendto()");
49: exit( 1 );
50: }
51: printf("after sendto(), my port is "); sockname_print( s );
52:
53: fromlen = sizeof( from );
54: if( (rcount = recvfrom( s, buf, BUFSIZ, 0, &from, &fromlen )) < 0 )
55: {
56: perror("recvfrom()");
57: exit( 1 );
58: }
59: printf("received from "); sockaddr_in_print( &from );
60: buf[rcount] = 0 ;
61: printf("%d bytes received. [%s] \n", rcount, buf );
62:
63: close( s );
64: }
65:
66: int udp_port_not_bound()
67: {
68: int s ;
69: if( (s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )
70: {
71: perror("socket");
72: return( -1 );
73: }
74: return( s );
75: }
76:
77: int sockaddr_in_init( struct sockaddr_in *addr, char *hostname, int portno )
78: {
79: struct hostent *hostent ;
80: addr->sin_family = AF_INET ;
81: if( (hostent = gethostbyname( hostname )) == NULL )
82: {
83: fprintf(stderr,"unknown host %s\n",hostname );
84: return( -1 );
85: }
86: bcopy( hostent->h_addr, &addr->sin_addr, hostent->h_length );
87: addr->sin_port = htons( portno );
88: return( 0 );
89: }
90:
91: void sockaddr_in_print( struct sockaddr_in *addr )
92: {
93: union {
94: int i ;
95: unsigned char byte[4] ;
96: } x ;
97: x.i = addr->sin_addr.s_addr ;
98: printf("sockaddr_in: %d.%d.%d.%d:%d\n",
99: x.byte[0],x.byte[1],x.byte[2],x.byte[3],
100: ntohs( addr->sin_port ));
101: }
102:
103: void sockname_print( int s )
104: {
105: struct sockaddr_in addr ;
106: int len ;
107: len = sizeof( addr );
108: if( getsockname( s, &addr, &len )< 0 )
109: {
110: perror("getsockname");
111: exit( -1 );
112: }
113: sockaddr_in_print( &addr );
114: }
----------------------------------------------------------------------
クライアント側では、bind() で名前を付けていない。sendto() の時に、自動 的にオペレーティング・システムにより、名前が付けられる。同じことは、 porno=0 で bind() しても可能である。オペレーティング・システムによって 付けられた名前は、後で getsockname() で調べることができる。
明示的に bind() する方法もある。
実行例。
---------------------------------------------------------------------- % ./echo-client-udp adonis1 7my port is sockaddr_in: 0.0.0.0:0 sending [hello] (6 bytes) to sockaddr_in: 130.158.86.1:7 after sendto(), my port is sockaddr_in: 0.0.0.0:8013 received from sockaddr_in: 130.158.86.1:7 6 bytes received. [hello] % ./echo-client-udp adonis11 7
my port is sockaddr_in: 0.0.0.0:0 sending [hello] (6 bytes) to sockaddr_in: 130.158.86.11:7 after sendto(), my port is sockaddr_in: 0.0.0.0:8014 received from sockaddr_in: 130.158.86.11:7 6 bytes received. [hello] % ./echo-client-udp localhost 7
my port is sockaddr_in: 0.0.0.0:0 sending [hello] (6 bytes) to sockaddr_in: 127.0.0.1:7 after sendto(), my port is sockaddr_in: 0.0.0.0:8015 received from sockaddr_in: 127.0.0.1:7 6 bytes received. [hello] %
----------------------------------------------------------------------
----------------------------------------------------------------------
1:
2: /*
3: echo-server-udp.c -- 文字列を送受信するサーバ(UDP/IP版)
4: ~yas/syspro1/ipc/echo-server-udp.c
5: $Header: /home/lab2/OS/yas/syspro1/ipc/RCS/echo-server-udp.c,v 1.3 1998/06/22 14:24:17 yas Exp $
6: Start: 1997/06/16 21:22:26
7: */
8: #include <stdio.h>
9: #include <sys/types.h> /* socket() */
10: #include <sys/socket.h> /* socket() */
11: #include <netinet/in.h> /* struct sockaddr_in */
12: #include <netdb.h> /* gethostbyname() */
13:
14: extern void echo_server_udp( int portno );
15: extern int udp_port_bind( int portno );
16: extern int sockaddr_in_init( struct sockaddr_in *addr, char *hostname, int portno );
17: extern void sockaddr_in_print( struct sockaddr_in *addr );
18: extern void sockname_print( int s );
19:
20: main( int argc, char *argv[] )
21: {
22: int portno ;
23: if( argc >= 3 )
24: {
25: fprintf( stdout,"Usage: %s host port\n",argv[0] );
26: exit( -1 );
27: }
28: if( argc == 2 )
29: portno = atoi( argv[1] );
30: else
31: portno = getuid();
32: echo_server_udp( portno );
33: }
34:
35: void echo_server_udp( int portno )
36: {
37: int s, rcount, scount, addrlen ;
38: struct sockaddr_in addr ;
39: char buf[BUFSIZ];
40:
41: s = udp_port_bind( portno );
42: if( s<0 )
43: exit( -1 );
44: printf("my port is "); sockname_print( s );
45:
46: while( 1 )
47: {
48: addrlen = sizeof( addr );
49: if( (rcount = recvfrom( s, buf, BUFSIZ, 0, &addr, &addrlen )) < 0 )
50: {
51: perror("recvfrom()");
52: exit( 1 );
53: }
54: buf[rcount] = 0 ;
55: printf("received %d bytes [%s] from ",rcount, buf );
56: sockaddr_in_print( &addr );
57: printf("sending back [%s] (%d bytes) to ", buf, rcount );
58: sockaddr_in_print( &addr );
59: if( scount = sendto( s, buf, rcount, 0, &addr, addrlen )!= rcount )
60: {
61: perror("sendto()");
62: exit( 1 );
63: }
64: }
65: }
66:
67: int udp_port_bind( int portno )
68: {
69: struct hostent *hostent ;
70: struct sockaddr_in addr ;
71: int addr_len ;
72: int s ;
73:
74: if( (s = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )
75: {
76: perror("socket");
77: return( -1 );
78: }
79:
80: addr.sin_family = AF_INET ;
81: addr.sin_addr.s_addr = INADDR_ANY ;
82: addr.sin_port = htons( portno );
83:
84: if( bind(s,&addr,sizeof(addr)) < 0 )
85: {
86: perror( "bind: " );
87: fprintf(stderr,"port number %d is already used. kill another program.", portno );
88: return( -1 );
89: }
90: return( s );
91: }
<以下省略>
----------------------------------------------------------------------
実行例。
サーバ側。サーバは、終了しないので、最後に、^C か Del を押して、割り込みを掛けて終了させる。
クライアント側(その1)。---------------------------------------------------------------------- % ./echo-server-udpmy port is sockaddr_in: 0.0.0.0:1231 received 6 bytes [hello] from sockaddr_in: 130.158.86.11:5890 sending back [hello] (6 bytes) to sockaddr_in: 130.158.86.11:5890 received 6 bytes [hello] from sockaddr_in: 130.158.86.1:8023 sending back [hello] (6 bytes) to sockaddr_in: 130.158.86.1:8023 received 6 bytes [hello] from sockaddr_in: 127.0.0.1:8024 sending back [hello] (6 bytes) to sockaddr_in: 127.0.0.1:8024 ^C %
----------------------------------------------------------------------
クライアント側(その2)。---------------------------------------------------------------------- % ./echo-client-udp adonis1 1231my port is sockaddr_in: 0.0.0.0:0 sending [hello] (6 bytes) to sockaddr_in: 130.158.86.1:1231 after sendto(), my port is sockaddr_in: 0.0.0.0:5890 received from sockaddr_in: 130.158.86.1:1231 6 bytes received. [hello] %
----------------------------------------------------------------------
クライアント側(その3)。---------------------------------------------------------------------- % ./echo-client-udp adonis1 1231my port is sockaddr_in: 0.0.0.0:0 sending [hello] (6 bytes) to sockaddr_in: 130.158.86.1:1231 after sendto(), my port is sockaddr_in: 0.0.0.0:8023 received from sockaddr_in: 130.158.86.1:1231 6 bytes received. [hello] % ----------------------------------------------------------------------
---------------------------------------------------------------------- % ./echo-client-udp localhost 1231my port is sockaddr_in: 0.0.0.0:0 sending [hello] (6 bytes) to sockaddr_in: 127.0.0.1:1231 after sendto(), my port is sockaddr_in: 0.0.0.0:8024 received from sockaddr_in: 127.0.0.1:1231 6 bytes received. [hello] %
----------------------------------------------------------------------
malloc() は、brk() システム・コール、または、sbrk システム・コールでオ ペレーティング・システムからメモリの割り当てを受けている。brk(), sbrk() は、プロセスのデータ・セグメントの終わりを変化させるシステム・ コールである。
main(int argc, argv[]) の引数である argv
をコピーするプログラムを作りなさい。コピーの方法としては、次の2種類が
考えられる。
ヒント:malloc() でメモリを割り当てて、内容をコピーする。コピーの方法 では、浅いコピーでは、文字列(文字の配列の先頭番地)をコピーする。深い コピーでは、strlen() +1 バイト malloc() して、番地を保存して strncpy() する。配列の終わりの 0 を忘れないように。
strdup() というライブラリ関数を使うと便利。
UDP/IP では、一度に送ることができるデータの大きさにには、実装上の制限 が付いている。これがいくつかを調べるプログラムを作りなさい。
UDP/IP のデータを中継するようなプログラムを作りなさい。 単方向だけでなく、双方向で中継するようにしなさい。
このようなプログラムの例として、udprelay と呼ばれるプログラムがある。
UDP/IP のサーバ、または、中継プログラムで、クライアントの IP アドレス によってアクセスを許したりエラーを発生させたりしなさい。