システムプログラム(第7週): Pthreadによる複数のクライアントに対するサービスの同時提供


電子・情報工学系/システム情報工学研究科CS専攻
新城 靖
<yas@is.tsukuba.ac.jp>

このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~syspro/2005/No7_files/echo-server-pthread.html
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~syspro/2005/
http://www.coins.tsukuba.ac.jp/~yas/

Ptheadとは

Pthread とは、C言語から使えるスレッド・ライブラリである。 オペレーティングシステムIIの資料 に簡単な説明がある。

echo-server-pthread.c

fork版 では、クライアントから接続要 求を受け付けるたびに、新しいプロセスを作っていた。以下の 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 <sys/types.h>  /* socket(), time() */
   9:	#include <sys/socket.h> /* socket() */
  10:	#include <netinet/in.h> /* struct sockaddr_in */
  11:	#include <pthread.h>    /* pthread_create */
  12:	#include <netdb.h>      /* getnameinfo() */
  13:	
  14:	extern  void echo_server( int portno );
  15:	extern  void echo_reply( int com );
  16:	extern  void print_my_host_port( int portno );
  17:	extern  void tcp_peeraddr_print( int com );
  18:	extern  void sockaddr_print( struct sockaddr *addrp, int addr_len );
  19:	extern  tcp_acc_port( int portno );
  20:	extern  int fdopen_sock( int sock, FILE **inp, FILE **outp );
  21:	
  22:	main( int argc, char *argv[] )
  23:	{
  24:	    int portno ;
  25:	        if( argc >= 3 )
  26:	        {
  27:	            fprintf( stdout,"Usage: %s [portno] \n",argv[0] );
  28:	            exit( -1 );
  29:	        }
  30:	        if( argc == 2 )
  31:	            portno = strtol( argv[1],0,10 );
  32:	        else
  33:	            portno = getuid();
  34:	        echo_server( portno );
  35:	}
main() 関数の部分は、fork版 とほと んど同じである。
  36:	
  37:	void
  38:	echo_server( int portno )
  39:	{
  40:	    int acc,com ;
  41:	    pthread_t worker ;
  42:	        acc = tcp_acc_port( portno );
  43:	        if( acc<0 )
  44:	            exit( -1 );
  45:	        print_my_host_port( portno );
  46:	        while( 1 )
  47:	        {
  48:	            if( (com = accept( acc,0,0 )) < 0 )
  49:	            {
  50:	                perror("accept");
  51:	                exit( -1 );
  52:	            }
  53:	            tcp_peeraddr_print( com );
  54:	            if( pthread_create( &worker, NULL, (void *)echo_reply, (void *)com)
  55:	                != 0 )
  56:	            {
  57:	                perror("pthread_create()");
  58:	                exit( 1 );
  59:	            }
  60:	            pthread_detach( worker );
  61:	        }
  62:	}
  63:	

このプログラムの特徴を以下にまとめる。

他の関数は、fork版と同じである。

 % diff -c echo-server-nofork-fdopen.c echo-server-pthread.c 
 *** echo-server-nofork-fdopen.c	Sun May  9 23:19:57 2004
 --- echo-server-pthread.c	Sun May  9 23:19:53 2004
 ***************
 *** 1,16 ****

   /*
 ! 	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>
 ! #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() */

   extern	void echo_server( int portno );
 --- 1,14 ----

   /*
 ! 	echo-server-pthread.c -- 受け取った文字列をそのまま返すサーバ(pthread版)
 ! 	~yas/syspro/ipc/echo-server-pthread.c
 ! 	Created on 2002/02/04 21:17:04
   */
   #include <stdio.h>
 ! #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() */

   extern	void echo_server( int portno );
 ***************
 *** 40,45 ****
 --- 38,44 ----
   echo_server( int portno )
   {
       int acc,com ;
 +     pthread_t worker ;
	 acc = tcp_acc_port( portno );
	 if( acc<0 )
	     exit( -1 );
 ***************
 *** 52,58 ****
		 exit( -1 );
	     }
	     tcp_peeraddr_print( com );
 ! 	    echo_reply( com );
	 }
   }

 --- 51,63 ----
		 exit( -1 );
	     }
	     tcp_peeraddr_print( com );
 ! 	    if( pthread_create( &worker, NULL, (void *)echo_reply, (void *)com)
 ! 		!= 0 )
 ! 	    {
 ! 	        perror("pthread_create()");
 ! 		exit( 1 );
 ! 	    }
 ! 	    pthread_detach( worker );
	 }
   }

 % 
実行例。

サーバ側。サーバは、終了しないので、最後に、^C を押して、割り 込みを掛けて終了させる。

注意:全員がポート番号 1231 を使うとプログラムが動かないことがある。

% ./echo-server-pthread 1231 [←]
run telnet adonis9.coins.tsukuba.ac.jp 1231 
[7298] connection (fd==4) from 130.158.86.28:47333
[7300] received (fd==4) 5 bytes, [012
]
[7298] connection (fd==8) from 127.0.0.1:42170
[7302] received (fd==8) 5 bytes, [abc
]
[7302] received (fd==8) 5 bytes, [def
]
[7302] connection (fd==8) closed.
[7300] received (fd==4) 5 bytes, [345
]
[7300] connection (fd==4) closed.
^C
% []
クライアント側(その1)。
% telnet adonis9.coins.tsukuba.ac.jp 1231 [←]
Trying 130.158.86.29...
Connected to adonis9.coins.tsukuba.ac.jp.
Escape character is '^]'.
012[←]
012
345[←]
345
^]
telnet> quit[←]
Connection closed.
% []
クライアント側(その2)。
% telnet adonis9.coins.tsukuba.ac.jp 1231 [←]
Trying 130.158.86.29...
Connected to adonis9.coins.tsukuba.ac.jp.
Escape character is '^]'.
abc[←]
abc
def[←]
def
^]
telnet> quit[←]
Connection closed.
% []

Last updated: 2005/06/05 21:37:33
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>