筑波大学 システム情報工学研究科
コンピュータサイエンス専攻, 電子・情報工学系
新城 靖
<yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~syspro/2011/2011-06-15/echo-server-pthread.html
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~syspro/2011/
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.
$