システム・プログラムI 電子・情報工学系 新城 靖 <yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/syspro1-1998/1998-06-16
/sized_io.html
あるいは、次のページから手繰っていくこともできます。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/
http://www.hlla.is.tsukuba.ac.jp/~yas/index-j.html
sized_io ライブラリ(または、streamライブラリ)は、Don Libes 氏により開 発された、UNIX 上で TCP/IP を使うプログラムを書きやすくするためのライ ブラリである。このライブラリを使うことで、UNIX固有の繁雑なソケットを利 用することなく、もともとの TCP/IP のモデルに近い形でTCP/IPを利用するプ ログラムを書くことが可能になる。
stream ライブラリでは、initport() という関数が、中心的な役割を果たす。 initport() は、TCP/IP のクライアント側(接続を行う方)でも、サーバ側 (接続されるのを待つ方)でも使われる。この項では、クライアント側の使い 方を示す。
initport() は、クライアント側では、次の2種類の形式で使われる。
-------------------------------------------------------------------- #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include "inet.h" int s = initport(PORT_NUMBER(port), CLIENT, SOCK_STREAM, host); int s = initport(PORT_NAME(name), CLIENT, SOCK_STREAM, host); int port ; char *name ; char *host; --------------------------------------------------------------------
前者は、ポート番号を指定して、TCP/IP の通信路を開設するものである。重 要な引数は、サーバ側の要求受付用ポートのポート番号 port と、ホスト名 host である。その他の引数 CLIENT と SOCK_STREAM は、定数である。これら は、クライアント側で使う限り、必ず指定されなければならない。
initport() は、結果として、1つのファイル記述子 s を返す。これは、 TCP/IP の双方向ストリームに対応している。よって返されたファイル記述子 に対して次のように write() システム・コールでデータを書き込むと、その データは、接続先のプロセスに送り届けられる。
write( s, buf, size );
逆に、接続先のプロセスから送られてきたデータは、read() システム・コー
ルにより受け取ることができる。
read( s, buf, size );
このように、同じファイル記述子に対して、read() と write() の両方を利用
することができる。
もう1つの形式は、ポート番号の代わりにポート名(サービス名)を指定する 方法である。たとえば、"telnet" というサービスの場合、次のようにして使 うことができる。
s = initport(PORT_NAME("telnet"), CLIENT, SOCK_STREAM, host);
この形式では、initport() は、/etc/services を参照して、与えられたポー
ト名をポート番号に変換して利用する。
いずれの形式においても、エラーが生じると、initport() は、-1 を返す。
-------------------------------------------------------------------- #include <sys/types.h> #include <sys/time.h> #include <sys/socket.h> #include <netinet/in.h> #include "inet.h" int s = initport( PORT_NUMBER( port ), SERVER, SOCK_STREAM ); int port ; --------------------------------------------------------------------これにより、サーバ側に要求受付用ポートが作られる。そのポート番号は、引 数portにより指定される。initport()に対するその他の引数 (SERVER, SOCK_STREAM) は、定数である。これらは、サーバ側で使う限り、必ず指定さ れなければならない。
initport() は、結果として、1つのファイル記述子 s を返す。これは、 TCP/IP のサーバ側における要求受付用ポートと対応している。要求受付用ポー トとは、ポート番号を保持し、クライアントからの接続要求を受け付けるため のものである。このポートを通じて、データを送受することはできない。すな わち、このファイル・記述子に対して、read() システム・コールや write() システム・コールにより、入出力を行うことができない。実際に入出力を行う ためのポート(通信用ポート)は、次の select_server_stream() によって得 られる。
select_server_stream() を使うと、自動的に接続要求を受け付けてくれ、さ れらに、入力可能なストリームを返してくれる。
-------------------------------------------------------------------- int client = select_server_stream( s, &fds ); int s ; fd_set fds ; --------------------------------------------------------------------
select_server_stream() の引数 s は、initport() により返されたファイル 記述子である。fdsは、select_server_stream() 内部で複数の接続扱うための 作業用変数である。fd_set とは、ファイル記述子の集合(配列)を保持する ためのビット配列である。これは、最初に FD_ZERO() により初期化されなけ ればならない。それ以後は、select_server_stream() により管理される。
select_server_stream() は、クライアントからの接続要求が来るか、クライ アントからのデータが到着するまで待つ。クライアントからの接続要求が来る と、それを受け付ける。その結果として、通信用ポートが作られる。そして、 最初のデータがクライアントから送られて来た時に、通信用ポートのファイル 記述子を返す。
select_server_stream() により返されるファイル記述子は、クライアントか らのデータが到着しており、入出力可能なTCP/IPの通信ポートに対応している。 サーバの仕事は、この通信ポートから要求を読みだし、それに応じた処理を行 い、結果をこの通信ポートに書き出すことである。
select_server_stream() は、1つのサーバ・プロセスで複数のクライアント を同時に扱う事を可能にする。サーバ・プロセスは、複数のクライアントの間 に、複数のTCP/IPの接続を同時に保持することができる。そして、それらの接 続の中で、データが届いたものを選び、返す機能がある。
なお、ネットワーク・プログラミングの教科書の多くは、ソケットを直接利用 するように書かれている。この実験においても、stream ライブラリを使うこ となく、直接ソケットを利用してプログラムを作成してもよい。
sized_write()とsized_read()を使うと、ストリーム(TCP/IP)上でSequenced Packets を実現することができる。ストリームでは、境界は保存されないが、 sized_write()とsized_read()を使うと、書き込み時に書いたバイト数でその まま読み出せる。
cc = sized_read(fd,buffer,maxsize) cc = sized_write(fd,buffer,size)
引数は、read(),write() とよくにている。
-------------------------------------------------------------------- This package provides a quick-and-easy means of providing reliable and large-packet communication between processes. It is described further in the man page stream(3) and at length in the document by Don Libes entitled "Packet-Oriented Communications Using a Stream Protocol --or-- Making TCP/IP on Berkeley UNIX a Little More Pleasant to Use", NISTIR 90-4232, January 1990. It is especially nice because initport() does all the hard work of initializing TCP connections, and select_server_stream() does the hard work of connecting processes to each other. If you are running on 4.3BSD, you should add -DBSD4_3 in the Makefile. Otherwise, this will compile for a 4.2BSD system. To install, type make install To test, type make test reader writer (in different window) writer (in yet another window) writer (in yet ...) and so on. reader and writer are two programs that should communicate with each other. Type things into any of the writers and reader will print it out prefaced by the file descriptor the data came in on. Bugs and problems to Don Libes National Bureau of Standards Bldg 220, Rm A-127 Gaithersburg, MD 20899 (301) 975-3535 SYNOPSIS #include <sys/socket.h> #include <netinet/in.h> #include <inet.h> cc [options] [files] sized_io.o stream.o DESCRIPTION This package implements packet or stream IO between a server process and a number of client processes, using the TCP/IP (stream) facilities. A client uses the call: s = initport(PORT_NUMBER(XXX),CLIENT,SOCK_STREAM); s is the server's data socket and is used as a file descriptor in further communication. The port may be specified by name (PORT_NAME("foo")), if it is registered. Similarly, the server uses the following call: s = initport(PORT_NUMBER(XXX),SERVER,SOCK_STREAM); s is the server's connection socket. To receive data or connections, the server calls select_server_stream(). client = select_server_stream(s,&fds); This returns a file descriptor corresponding to a client, when a client has sent a message to the server. It handles initial connections as well as client deaths. s is the server's connection socket that was returned by initport(). fds is an int used by select...() for storing a bit string corresponding to client sockets. Initialize it to 0, and don't mess with it after that. To use the file descriptors in a stream-oriented manner, use read() and write(). To use the file descriptors in a packet-oriented manner, use sized_read() and sized_write(). The sized...() calls read and write one packet at a time, while packet boundaries are ignored in read() and write(). cc = sized_read(fd,buffer,maxsize) cc = sized_write(fd,buffer,size) The arguments for sized_read() and sized_write() are very similar to read() and write(). The only difference is that in sized_read(), maxsize is the maximum size of an acceptable packet. --------------------------------------------------------------------
streamライブラリのアーカイブ名は、sized_ioになっている。よって、archieで 文字列 sized_io を検索するとよい。
1997年6月における archie の結果:-------------------------------------------------------------------- ftp.lab.kdd.co.jp /Unix -rw-r--r-- 22851 Dec 17 1990 sized_io.shar.gz ftp.mei.co.jp /free/others/Libraries -rw-r--r-- 22851 Dec 17 1990 sized_io.shar.gz ftp.tut.ac.jp /.h3/UNIX/lib -rw-rw-r-- 22173 Jun 25 1995 sized_io.tar.gz nadia.ics.es.osaka-u.ac.jp /d0/UUNET91/vol8/pub -rw-r--r-- 34704 Jun 30 1990 sized_io.shar.Z --------------------------------------------------------------------