筑波大学 システム情報系 情報工学域
新城 靖
<yas@cs.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~syspro/2013/2013-06-05
/echo-server-pthread.html
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~syspro/2013/
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: printf("[%d] accepting incoming connections (fd==%d) ...\n",getpid(),acc );
58: if( (com = accept( acc,0,0 )) < 0 )
59: {
60: perror("accept");
61: exit( -1 );
62: }
63: tcp_peeraddr_print( com );
64: arg = malloc( sizeof(struct echo_server_thread_arg) );
65: if( arg == NULL )
66: {
67: perror("malloc()");
68: exit( -1 );
69: }
70: arg->com = com;
71: if( pthread_create( &worker, NULL, (void *)echo_server_thread, (void *)arg)
72: != 0 )
73: {
74: perror("pthread_create()");
75: exit( 1 );
76: }
77: pthread_detach( worker );
78: }
79: }
80:
このプログラムの特徴を以下にまとめる。
81: void *
82: echo_server_thread( struct echo_server_thread_arg *arg )
83: {
84: echo_receive_request_and_send_reply( arg->com );
85: free( arg );
86: return( NULL );
87: }
88:
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 2012-06-04 15:05:44.000000000 +0900
--- echo-server-pthread.c 2012-06-04 15:07:08.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,55 ****
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();
printf("[%d] accepting incoming connections (fd==%d) ...\n",getpid(),acc );
if( (com = accept( acc,0,0 )) < 0 )
{
--- 38,59 ----
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 )
{
printf("[%d] accepting incoming connections (fd==%d) ...\n",getpid(),acc );
if( (com = accept( acc,0,0 )) < 0 )
{
***************
*** 57,89 ****
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
--- 61,89 ----
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 を使うとプログラムが動かないことがある。
$ cp ~yas/syspro/ipc/echo-server-pthread.c .
$ make echo-server-pthread
cc echo-server-pthread.c -o echo-server-pthread
$ ./echo-server-pthread
Usage: ./echo-server-pthread portno {ipversion}
$ ./echo-server-pthread 1231
run telnet cosmos10(v6) 1231
[17385] accepting incoming connections (fd==3) ...
[17385] connection (fd==4) from 130.158.86.150:57810
[17385] accepting incoming connections (fd==3) ...
[17385] received (fd==4) 5 bytes, [012
]
[17385] connection (fd==6) from 130.158.86.1:54729
[17385] accepting incoming connections (fd==3) ...
[17385] received (fd==6) 5 bytes, [abc
]
[17385] received (fd==6) 5 bytes, [def
]
[17385] received (fd==4) 5 bytes, [345
]
[17385] connection (fd==4) closed.
[17385] connection (fd==6) 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> quit
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> quit
Connection closed.
$