筑波大学 システム情報工学研究科 コンピュータサイエンス専攻, 電子・情報工学系 新城 靖 <yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~syspro/2010/No8_files/echo-server-pthread.html
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~syspro/2010/
http://www.coins.tsukuba.ac.jp/~yas/
echo-server-pthread.c
では、プロセスではなく
スレッドを作っている。
1: 2: /* 3: echo-server-pthread.c -- 受け取った文字列をそのまま返すサーバ(pthread版) 4: ~yas/syspro/ipc/echo-server-pthread.c 5: Created on 2002/02/04 21:17:04 6: */ 7: #include <stdio.h> 8: #include <stdlib.h> /* exit() */ 9: #include <sys/types.h> /* socket(), time() */ 10: #include <sys/socket.h> /* socket() */ 11: #include <netinet/in.h> /* struct sockaddr_in */ 12: #include <pthread.h> /* pthread_create */ 13: #include <netdb.h> /* getnameinfo() */ 14: #include <string.h> /* strlen() */ 15: 16: struct echo_server_thread_arg; 17: extern void echo_server( int portno, int ip_version ); 18: extern void echo_receive_request_and_send_reply( int com ); 19: extern void *echo_server_thread( struct echo_server_thread_arg *arg ); 20: extern void print_my_host_port( int portno ); 21: extern void tcp_peeraddr_print( int com ); 22: extern void sockaddr_print( struct sockaddr *addrp, socklen_t addr_len ); 23: extern int tcp_acc_port( int portno, int pf ); 24: extern int fdopen_sock( int sock, FILE **inp, FILE **outp ); 25: 26: main( int argc, char *argv[] ) 27: { 28: int portno, ip_version; 29: if( !(argc == 2 || argc==3) ) { 30: fprintf(stderr,"Usage: %s portno {ipversion}\n",argv[0] ); 31: exit( 1 ); 32: } 33: portno = strtol( argv[1],0,10 ); 34: if( argc == 3 ) 35: ip_version = strtol( argv[2],0,10 ); 36: else 37: ip_version = 4; /* IPv4 by default */ 38: echo_server( portno, ip_version ); 39: } 40:main() は、 forkなし版 や fork版 とほとんど同じである。
41: struct echo_server_thread_arg { 42: int com; 43: }; 44: 45: void 46: echo_server( int portno, int ip_version ) 47: { 48: int acc,com ; 49: pthread_t worker ; 50: struct echo_server_thread_arg *arg; 51: acc = tcp_acc_port( portno, ip_version ); 52: if( acc<0 ) 53: exit( -1 ); 54: print_my_host_port( portno ); 55: while( 1 ) 56: { 57: if( (com = accept( acc,0,0 )) < 0 ) 58: { 59: perror("accept"); 60: exit( -1 ); 61: } 62: tcp_peeraddr_print( com ); 63: arg = malloc( sizeof(struct echo_server_thread_arg) ); 64: if( arg == NULL ) 65: { 66: perror("malloc()"); 67: exit( -1 ); 68: } 69: arg->com = com; 70: if( pthread_create( &worker, NULL, (void *)echo_server_thread, (void *)arg) 71: != 0 ) 72: { 73: perror("pthread_create()"); 74: exit( 1 ); 75: } 76: pthread_detach( worker ); 77: } 78: } 79:
このプログラムの特徴を以下にまとめる。
80: void * 81: echo_server_thread( struct echo_server_thread_arg *arg ) 82: { 83: echo_receive_request_and_send_reply( arg->com ); 84: free( arg ); 85: return( NULL ); 86: }echo_server_thread() は、スレッドが生成された時に最初に呼ばれる関数であ る。引数の構造体から com を取り出し、 echo_receive_request_and_send_reply() を呼んでいる。それからリターンし た後には、引数の構造体を free している。
他の関数は、fork版、forkなし版とと同じである。
$ diff -c echo-server-fork-fdopen.c echo-server-pthread.c *** echo-server-fork-fdopen.c 2010-06-07 21:03:44.000000000 +0900 --- echo-server-pthread.c 2010-06-07 22:14:39.000000000 +0900 *************** *** 1,22 **** /* ! echo-server-fork-fdopen.c -- 受け取った文字列をそのまま返すサーバ(fork版) ! ~yas/syspro/ipc/echo-server-fork-fdopen.c ! Created on 2004/05/09 19:57:07 */ #include <stdio.h> #include <stdlib.h> /* exit() */ ! #include <sys/types.h> /* socket(), wait4() */ #include <sys/socket.h> /* socket() */ #include <netinet/in.h> /* struct sockaddr_in */ ! #include <sys/resource.h> /* wait4() */ ! #include <sys/wait.h> /* wait4() */ #include <netdb.h> /* getnameinfo() */ #include <string.h> /* strlen() */ extern void echo_server( int portno, int ip_version ); - extern void delete_zombie(); extern void echo_receive_request_and_send_reply( int com ); extern void print_my_host_port( int portno ); extern void tcp_peeraddr_print( int com ); extern void sockaddr_print( struct sockaddr *addrp, socklen_t addr_len ); --- 1,22 ---- /* ! echo-server-pthread.c -- 受け取った文字列をそのまま返すサーバ(pthread版) ! ~yas/syspro/ipc/echo-server-pthread.c ! Created on 2002/02/04 21:17:04 */ #include <stdio.h> #include <stdlib.h> /* exit() */ ! #include <sys/types.h> /* socket(), time() */ #include <sys/socket.h> /* socket() */ #include <netinet/in.h> /* struct sockaddr_in */ ! #include <pthread.h> /* pthread_create */ #include <netdb.h> /* getnameinfo() */ #include <string.h> /* strlen() */ + struct echo_server_thread_arg; extern void echo_server( int portno, int ip_version ); extern void echo_receive_request_and_send_reply( int com ); + extern void *echo_server_thread( struct echo_server_thread_arg *arg ); extern void print_my_host_port( int portno ); extern void tcp_peeraddr_print( int com ); extern void sockaddr_print( struct sockaddr *addrp, socklen_t addr_len ); *************** *** 38,88 **** echo_server( portno, ip_version ); } void echo_server( int portno, int ip_version ) { int acc,com ; ! pid_t child_pid ; acc = tcp_acc_port( portno, ip_version ); 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_receive_request_and_send_reply( com ); ! exit( 0 ); } ! else ! { ! perror("fork"); ! exit( -1 ); ! } } } ! void ! delete_zombie() { ! pid_t pid ; ! while( (pid=wait4(-1,0,WNOHANG,0)) >0 ) ! { ! printf("[%d] zombi %d deleted.\n",getpid(),pid ); ! continue; ! } } #define BUFFERSIZE 1024 --- 38,88 ---- echo_server( portno, ip_version ); } + struct echo_server_thread_arg { + int com; + }; + void echo_server( int portno, int ip_version ) { int acc,com ; ! pthread_t worker ; ! struct echo_server_thread_arg *arg; acc = tcp_acc_port( portno, ip_version ); 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 ); ! arg = malloc( sizeof(struct echo_server_thread_arg) ); ! if( arg == NULL ) { ! perror("malloc()"); ! exit( -1 ); } ! arg->com = com; ! if( pthread_create( &worker, NULL, (void *)echo_server_thread, (void *)arg) ! != 0 ) { ! perror("pthread_create()"); ! exit( 1 ); } ! pthread_detach( worker ); } } ! void * ! echo_server_thread( struct echo_server_thread_arg *arg ) { ! echo_receive_request_and_send_reply( arg->com ); ! free( arg ); ! return( NULL ); } #define BUFFERSIZE 1024 $実行例。
サーバ側。サーバは、終了しないので、最後に、^C を押して、割り 込みを掛けて終了させる。
注意:全員がポート番号 1231 を使うとプログラムが動かないことがある。
$ ./echo-server-pthread 1231
run telnet cosmos10(v6) 1231
[15826] connection (fd==4) from 130.158.86.151:62141
[15826] received (fd==4) 5 bytes, [012
]
[15826] connection (fd==6) from 130.158.86.151:62142
[15826] received (fd==6) 5 bytes, [abc
]
[15826] received (fd==6) 5 bytes, [def
]
[15826] connection (fd==6) closed.
[15826] received (fd==4) 5 bytes, [345
]
[15826] connection (fd==4) closed.
^C
$
クライアント側(その1)。
$ telnet cosmos10 1231
Trying 130.158.86.150...
Connected to cosmos10.coins.tsukuba.ac.jp.
Escape character is '^]'.
012
012
345
345
^]
telnet> ^D
Connection closed.
$
クライアント側(その2)。
$ telnet cosmos10 1231
Trying 130.158.86.150...
Connected to cosmos10.coins.tsukuba.ac.jp.
Escape character is '^]'.
abc
abc
def
def
^]
telnet> ^D
Connection closed.
$