システム・プログラム
電子・情報工学系
新城 靖
<yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/syspro-2004/2004-05-10
/echo-server-fork.html
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.is.tsukuba.ac.jp/~yas/index-j.html
1: /*
2: echo-server-fork-fdopen.c -- 受け取った文字列をそのまま返すサーバ(fork版)
3: ~yas/syspro/ipc/echo-server-fork-fdopen.c
4: Created on 2004/05/09 19:57:07
5: */
6: #define _USE_BSD /* wait4() */
7: #include <stdio.h>
8: #include <sys/types.h> /* socket(), wait4() */
9: #include <sys/socket.h> /* socket() */
10: #include <netinet/in.h> /* struct sockaddr_in */
11: #include <sys/resource.h> /* wait4() */
12: #include <sys/wait.h> /* wait4() */
13: #include <netdb.h> /* getnameinfo() */
14:
15: extern void echo_server( int portno );
16: extern void echo_reply( int com );
17: extern void print_my_host_port( int portno );
18: extern void tcp_peeraddr_print( int com );
19: extern void sockaddr_print( struct sockaddr *addrp, int addr_len );
20: extern tcp_acc_port( int portno );
21: extern void delete_zombie(void);
22: extern int fdopen_sock( int sock, FILE **inp, FILE **outp );
23:
24: main( int argc, char *argv[] )
25: {
26: int portno ;
27: if( argc >= 3 )
28: {
29: fprintf( stdout,"Usage: %s [portno] \n",argv[0] );
30: exit( -1 );
31: }
32: if( argc == 2 )
33: portno = strtol( argv[1],0,10 );
34: else
35: portno = getuid();
36: echo_server( portno );
37: }
38:
main() は、
echo-server-nofork-fdopen.c
と同じである。
39: void
40: echo_server( int portno )
41: {
42: int acc,com ;
43: pid_t child_pid ;
44: acc = tcp_acc_port( portno );
45: if( acc<0 )
46: exit( -1 );
47: print_my_host_port( portno );
48: while( 1 )
49: {
50: delete_zombie();
51: if( (com = accept( acc,0,0 )) < 0 )
52: {
53: perror("accept");
54: exit( -1 );
55: }
56: tcp_peeraddr_print( com );
57: if( (child_pid=fork()) > 0 ) /* parent */
58: {
59: close( com );
60: }
61: else if( child_pid == 0 ) /* child */
62: {
63: close( acc );
64: echo_reply( com );
65: exit( 0 );
66: }
67: else
68: {
69: perror("fork");
70: exit( -1 );
71: }
72: }
73: }
delete_zombie() は、ゾンビ・プロセス(後述)を消去するものである。 (改善の余地がある。) echo サービスとしての処理は、fork() システムコールで分身を作り、子プロ セス側で行う。親プロセスは、すぐにaccept() に戻る。
getpid() は、自分自身の PID (Process ID (identifier)) を返すシステムコー ルである。PID (pid_t) は、16 ビット(システムによっては32ビット)の整数 である。実行結果で printf() の表示に、PID が表示されているが、同じではないことに 注意しなさい。
167: void
168: delete_zombie()
169: {
170: pid_t pid ;
171: while( (pid=wait4(-1,0,WNOHANG,0)) >0 )
172: {
173: printf("[%d] zombi %d deleted.\n",getpid(),pid );
174: continue;
175: }
176: }
wait4() システムコールを使って、終了した子プロセスをwait してあげてい
る。ただし、WNOHANG オプションを付けてあるので、終了した子プロセスがい
なければ、待たずに返ってくる。
他の関数は、 echo-server-nofork-fdopen.c と同じである。
% diff -c echo-server-nofork-fdopen.c echo-server-fork-fdopen.c
echo-server-nofork-fdopen.c Sun May 9 23:19:57 2004
--- echo-server-fork-fdopen.c Mon May 10 11:44:38 2004
1,8 ****
-
/*
! echo-server-nofork-fdopen.c -- 受け取った文字列をそのまま返すサーバ(fork無し版)
! ~yas/syspro/ipc/echo-server-nofork-fdopen.c
! Created on 2004/05/09 19:08:47
*/
#define _USE_BSD /* wait4() */
#include <stdio.h>
--- 1,7 ----
/*
! echo-server-fork-fdopen.c -- 受け取った文字列をそのまま返すサーバ(fork版)
! ~yas/syspro/ipc/echo-server-fork-fdopen.c
! Created on 2004/05/09 19:57:07
*/
#define _USE_BSD /* wait4() */
#include <stdio.h>
19,24 ****
--- 18,24 ----
extern void tcp_peeraddr_print( int com );
extern void sockaddr_print( struct sockaddr *addrp, int addr_len );
extern tcp_acc_port( int portno );
+ extern void delete_zombie(void);
extern int fdopen_sock( int sock, FILE **inp, FILE **outp );
main( int argc, char *argv[] )
40,58 ****
echo_server( int portno )
{
int acc,com ;
acc = tcp_acc_port( portno );
if( acc<0 )
exit( -1 );
print_my_host_port( portno );
while( 1 )
{
if( (com = accept( acc,0,0 )) < 0 )
{
perror("accept");
exit( -1 );
}
tcp_peeraddr_print( com );
! echo_reply( com );
}
}
--- 40,74 ----
echo_server( int portno )
{
int acc,com ;
+ pid_t child_pid ;
acc = tcp_acc_port( portno );
if( acc<0 )
exit( -1 );
print_my_host_port( portno );
while( 1 )
{
+ delete_zombie();
if( (com = accept( acc,0,0 )) < 0 )
{
perror("accept");
exit( -1 );
}
tcp_peeraddr_print( com );
! if( (child_pid=fork()) > 0 ) /* parent */
! {
! close( com );
! }
! else if( child_pid == 0 ) /* child */
! {
! close( acc );
! echo_reply( com );
! exit( 0 );
! }
! else
! {
! perror("fork");
! exit( -1 );
! }
}
}
149,154 ****
--- 165,181 ----
return( -1 );
}
return( s );
+ }
+
+ void
+ delete_zombie()
+ {
+ pid_t pid ;
+ while( (pid=wait4(-1,0,WNOHANG,0)) >0 )
+ {
+ printf("[%d] zombi %d deleted.\n",getpid(),pid );
+ continue;
+ }
}
int
%
実行例。
サーバ側。 サーバは、終了しないので、最後に、^C を押して、割り込みを掛け て終了させる。
注意:全員がポート番号 1231 を使うとプログラムが動かないことがある。
% ./echo-server-fork-fdopen 1231クライアント側(その1)。run telnet adonis9.coins.tsukuba.ac.jp 1231 [6907] connection (fd==4) from 130.158.86.28:47332 [6908] read(4,,) 5 bytes, [012 ] [6907] connection (fd==4) from 130.158.86.29:42126 [6910] read(4,,) 5 bytes, [abc ] [6910] read(4,,) 5 bytes, [def ] [6910] connection (fd==4) closed. [6908] read(4,,) 5 bytes, [345 ] [6908] connection (fd==4) closed.
% telnet adonis9.coins.tsukuba.ac.jp 1231クライアント側(その2)。Trying 130.158.86.29... Connected to adonis9.coins.tsukuba.ac.jp. Escape character is '^]'. 012
012 345
345 ^] telnet> quit
Connection closed. %
![]()
% telnet adonis9.coins.tsukuba.ac.jp 1231Trying 130.158.86.29... Connected to adonis9.coins.tsukuba.ac.jp. Escape character is '^]'. abc
abc def
def ^] telnet> quit
Connection closed. %
![]()
図1サーバが accept()している時にクライアントが connect()した所
図2 サーバで accept()からreturnした所。fork() する直前。
図3サーバで親がcomをclose()、子が acc を close() した所。
図4 複数のクライアントが接続した時
ps -l コマンドで見ると、ゾンビの状態(S) は、Z と表示される。
% ps aux | egrep echoecho-server-fork.c では、 delete_zombie() でゾンビを消そうとはしている。しかし、accept() で止まっ ている状態なので、どこかのクライアントから接続要求が来ない限りは、 delete_zombie() が呼ばれないので、ゾンビとして残っている。yas 6765 0.0 0.2 1752 684 pts/5 S 22:09 0:00 less echo-server- yas 6907 0.0 0.1 1364 396 pts/1 S 22:51 0:00 ./echo-server-for yas 6908 0.0 0.0 0 0 pts/1 Z 22:51 0:00 [echo-server-for yas 6910 0.0 0.0 0 0 pts/1 Z 22:51 0:00 [echo-server-for yas 6913 0.0 0.1 1448 444 pts/4 R 22:53 0:00 egrep echo %
![]()
この状態で接続要求が来ると、ゾンビが回収される。
% ./echo-server-fork-fdopen 1231run telnet adonis9.coins.tsukuba.ac.jp 1231 [6907] connection (fd==4) from 130.158.86.28:47332 [6908] read(4,,) 5 bytes, [012 ] [6907] connection (fd==4) from 130.158.86.29:42126 [6910] read(4,,) 5 bytes, [abc ] [6910] read(4,,) 5 bytes, [def ] [6910] connection (fd==4) closed. [6908] read(4,,) 5 bytes, [345 ] [6908] connection (fd==4) closed. [6907] connection (fd==4) from 127.0.0.1:42127 [6907] zombi 6910 deleted. [6907] zombi 6908 deleted.