クライアントサーバーコンピューティングにおいて、Unixドメインソケットは、同じUnixまたはUnixライクなホストコンピュータ上で実行されている2つのプロセス間でデータを交換できるBerkeleyソケットです。 [1]これは、異なるホストコンピュータ上で実行されている2つのプロセス間でデータを交換できる インターネットドメインソケットに似ています。
通信範囲(同一ホストまたは異なるホスト)に関係なく、 [2]ソケット通信を実行するUnixコンピュータプログラムは似ています。通信範囲の唯一の違いは、ソケットの接続をバインドするために必要なアドレスパラメータに名前を変換する方法です。Unixドメインソケットの場合、名前は です。インターネットドメインソケットの場合、名前は です。どちらの場合も、名前はアドレスと呼ばれます。[3] /path/filenameIP address:Port number
2 つのプロセスは、それぞれがソケットを取得すれば、互いに通信できます。サーバー プロセスは、ソケットをアドレスにバインドし、listenチャネルを開いて、 を継続的にループします。ループ内では、サーバー プロセスは、クライアント接続の受け入れを待機している間、スリープ状態になります。[4]クライアント接続を受け入れると、サーバーはreadシステム コールを実行し、 wait をブロックします。クライアントは、サーバーのアドレスを介してサーバーのソケットに接続します。次に、クライアント プロセスは、サーバー プロセスが読み取るメッセージを書き込みます。アプリケーションのアルゴリズムには、複数の読み取り/書き込みのやり取りが含まれる場合があります。アルゴリズムが完了すると、クライアントは[5]を実行し、サーバーは を実行します。[6] exit()close()
Unixドメインソケットの場合、ソケットのアドレスは/path/filename識別子です。サーバーはファイルシステム/path/filename上にロックファイルセマフォとして機能します。クライアントとサーバーが互いにメッセージを送信する場合、このファイルではI/Oは発生しません。[7]
歴史
ソケットは、 Berkeley Software Distribution 4.2(1983年)で初めて登場しました。 [8] 2000年にPOSIX標準になりました。 [8]アプリケーションプログラミングインターフェイスは、事実上すべてのUnix実装とほとんどの他のオペレーティングシステムに移植されています。[8]
ソケットのインスタンス化
サーバーとクライアントの両方がシステムコールを実行してソケットオブジェクトをインスタンス化する必要があります。その使用法は次のとおりです。[9]socket()
intソケット( intドメイン, intタイプ, intプロトコル);
パラメータdomainは、以下の一般的な通信範囲のいずれかである必要があります。[10]
- 同じホスト内では定数
AF_UNIX[a]を使用して - IPv4プロトコルを介して2つのホスト間で定数を使用して
AF_INET - IPv6プロトコルを介して2つのホスト間で定数を使用して
AF_INET6 - 同じホスト内または2つのホスト間で、ストリーム制御伝送プロトコルを介して定数
SOCK_SEQPACKET[11]を使用して
パラメータの値が の場合、 Unixドメインソケットラベルが使用されます。パラメータの値が またはの場合、インターネットドメインソケットラベルが使用されます。[12]domainAF_UNIXdomainAF_INETAF_INET6
パラメータtypeは、ストリームまたはデータグラムという2つの一般的なソケットタイプのいずれかである必要があります。[10]実験設計には、3番目のソケットタイプであるrawが利用可能です。
SOCK_STREAMストリームソケットを作成します。ストリームソケットは、2つのプロセス間で信頼性の高い双方向の接続指向の通信チャネルを提供します。データは伝送制御プロトコル(TCP)を使用して伝送されます。[10]SOCK_DGRAMデータグラムソケットを作成します。[b]データグラムソケットは信頼性を保証せず、コネクションレスです。その結果、転送はより高速になります。データはユーザーデータグラムプロトコル(UDP)を使用して伝送されます。[14]SOCK_RAWインターネットプロトコル(IP)データグラムソケットを作成します。RawソケットはTCP / UDPトランスポート層をスキップし、パケットを直接ネットワーク層に送信します。[15]
Unixドメインソケットの場合、データ(ネットワークパケット)は、トランスポート層(TCPまたはUDP)を介して接続された2つのプロセス間で渡されます。[16]インターネットドメインソケットの場合、データは、トランスポート層とネットワーク層のインターネットプロトコル(IP)(TCP/IPまたはUDP/IP)を介して接続された2つのプロセス間で渡されます。[16]
ストリームソケットとデータグラムソケットの場合、パラメータprotocolはゼロに設定する必要があります。[2] RAWソケットの場合、protocolパラメータはIPPROTO_RAWに設定する必要があります。[9]
socket() 戻り値
socket_fd = socket ( intドメイン, intタイプ, intプロトコル);
通常のファイルopen()システムコールと同様に、システムコールはファイル記述子socket()を返します。[2] [c]戻り値のサフィックスはファイル記述子を表します。
_fd
サーバーは /path/filename にバインドします
新しいソケットをインスタンス化した後、サーバーはソケットをアドレスにバインドします。Unix ドメイン ソケットの場合、アドレスは です/path/filename。
ソケットアドレスは/path/filenameまたは のいずれかであるためIP_address:Port_number、ソケットアプリケーションプログラミングインターフェースでは、まずアドレスを 構造体に設定する必要があります。Unixドメインソケットの場合、構造体は次のようになります。[17]
構造体sockaddr_un { sa_family_t sun_family ; /* AF_UNIX */ char sun_path [ 92 ]; }
サフィックスはunix_unを表します。インターネットドメインソケットの場合、サフィックスは または になります。プレフィックスはsocket unixを表します。[17]_in_in6sun_
ストリームUnixドメインソケットを作成してバインドするコンピュータプログラム:[7]
#include <stdlib.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include <assert.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/un.h>
/* 91 文字以下にする必要があります。一部の Unix 系ではもう少し長くなります。 */
/* デモンストレーションのみに /tmp ディレクトリを使用します。 */ char * socket_address = "/tmp/mysocket.sock" ;
void main ( void ) { int server_socket_fd ; struct sockaddr_un sockaddr_un = { 0 }; int return_value ;
server_socket_fd = socket ( AF_UNIX 、SOCK_STREAM 、0 ); if ( server_socket_fd == -1 ) assert ( 0 );
/* 以前の実行を削除します (おそらく)。 */
remove ( socket_address );
/* バインドアドレス構造体を構築します。 */
sockaddr_un . sun_family = AF_UNIX ; strcpy ( sockaddr_un . sun_path , socket_address );
return_value = bind ( server_socket_fd 、( struct sockaddr * ) & sockaddr_un 、sizeof ( struct sockaddr_un ) );
/* socket_address がファイルシステム上に存在する場合、bind は失敗します。 */
if ( return_value == -1 ) assert ( 0 );
/* listen および accept コードは省略されています。 */
}
の2番目のパラメータはbind()へのポインタですstruct sockaddr。しかし、関数に渡されるパラメータは のアドレスですstruct sockaddr_un。struct sockaddrは使用されない汎用構造体です。これはの仮パラメータ 宣言で定義されます。通信の各範囲には独自の実パラメータbind()があるため、この汎用構造体はキャストプレースホルダとして作成されました。[18]
サーバーは接続を待機します
アドレスにバインドした後、サーバーはを実行してポートlisten()へのリッスンチャネルを開きます。その使い方は次のとおりです。[19]
int listen ( int server_socket_fd 、intバックログ);
if ( listen ( server_socket_fd 、4096 ) == -1 ) assert ( 0 );
Unixドメインソケットの場合、listen()おそらく成功して を返します0。インターネットドメインソケットの場合、ポートが使用中でlisten()あれば を返します-1。[19]
このbacklogパラメータは、保留中の接続のキューサイズを設定します。[20]クライアントがリクエストを実行するときにサーバーがビジー状態になっている可能性がありますconnect()。この制限までの接続リクエストは成功します。渡されたバックログ値がデフォルトの最大値を超える場合は、最大値が使用されます。[19]
サーバーが接続を受け入れる
リッスンチャネルを開いた後、サーバーは無限ループに入ります。ループ内には へのシステムコールがありaccept()、これによってサーバーはスリープ状態になります。[4]クライアントプロセスが を実行すると、システムaccept()コールはファイル記述子を返しますconnect()。[21]
接続を受け入れるためのスニペット:
ソケットfdを受け入れます;
while ( 1 ) { accept_socket_fd = accept ( server_socket_fd , NULL , NULL ); if ( accept_socket_fd == -1 ) assert ( 0 );
if ( accept_socket_fd > 0 ) /* クライアントが接続されています */ }
ソケット上のサーバーI/O
正の整数を返す場合accept()、サーバーはクライアントとアルゴリズム ダイアログを実行します。
ストリームread()ソケットの入出力は、およびの通常ファイルシステムコールを実行することができるwrite()。[6]send()ただし、ストリームソケットがおよびのソケット固有のシステムコールを実行する場合は、より詳細な制御が可能になるrecv()。 あるいは、データグラムソケットの入出力は、sendto()およびのソケット固有のシステムコールを実行する必要があるrecvfrom()。[22]
基本的なストリーム ソケットの場合、サーバーは を使用してデータを受信しread( accept_socket_fd )、 を使用してデータを送信しますwrite( accept_socket_fd )。
基本的なストリーム ソケットでの I/O を説明するスニペット:
ソケットfdを受け入れます;
while ( 1 ) { accept_socket_fd = accept ( server_socket_fd , NULL , NULL ); if ( accept_socket_fd == -1 ) assert ( 0 );
accept_socket_fd > 0の場合、server_algorithmic_dialog ( accept_socket_fd ) ; } }
#BUFFER_SIZE 1024 を定義します
void server_algorithmic_dialog ( int accept_socket_fd ) { char input_buffer [ BUFFER_SIZE ]; char output_buffer [ BUFFER_SIZE ];
読み取り( accept_socket_fd 、input_buffer 、BUFFER_SIZE );
if ( strcasecmp ( input_buffer , "hola" ) == 0 ) strcpy ( output_buffer , "Hola Mundo" ); else if ( strcasecmp ( input_buffer , "ciao" ) == 0 ) strcpy ( output_buffer , "Ciao Mondo" ); else strcpy ( output_buffer , "Hello World" );
書き込み( accept_socket_fd 、output_buffer 、strlen ( output_buffer ) + 1 ); }
サーバーが接続を閉じる
アルゴリズムダイアログは、アルゴリズムが終了するか、またはread( accept_socket_fd )戻ると終了します< 1。[6]接続を閉じるには、close()システムコールを実行します。[6]
接続を閉じるためのスニペット:
ソケットfdを受け入れます;
while ( 1 ) { accept_socket_fd = accept ( server_socket_fd , NULL , NULL ); if ( accept_socket_fd == -1 ) assert ( 0 );
accept_socket_fd > 0の場合、server_algorithmic_dialog ( accept_socket_fd )を閉じます( accept_socket_fd ) 。
ダイアログの終了を示すスニペット:
#BUFFER_SIZE 1024 を定義します
void server_algorithmic_dialog ( int accept_socket_fd ) { char buffer [ BUFFER_SIZE ]; int read_count ;
/* アルゴリズムダイアログを省略 */
read_count = read ( accept_socket_fd , buffer , BUFFER_SIZE ); if ( read_count < 1 ) return ;
/* アルゴリズムダイアログを省略 */
}
クライアントをインスタンス化し、/path/filenameに接続する
クライアントがソケットをインスタンス化して接続するためのコンピュータプログラム: [5]
#include <stdlib.h> #include <string.h> #include <stdio.h> #include <unistd.h> #include <assert.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/un.h>
/* サーバーの socket_address と一致する必要があります。 */
char * socket_address = "/tmp/mysocket.sock" ;
void main ( void ) { int client_socket_fd ; struct sockaddr_un sockaddr_un = { 0 }; int return_value ;
client_socket_fd = socket ( AF_UNIX 、SOCK_STREAM 、0 ); if ( client_socket_fd == -1 ) assert ( 0 );
/* クライアントアドレス構造体を構築します。 */
sockaddr_un . sun_family = AF_UNIX ; strcpy ( sockaddr_un . sun_path , socket_address );
return_value = connect ( client_socket_fd 、( struct sockaddr * ) & sockaddr_un 、sizeof ( struct sockaddr_un ) );
/* socket_address がファイルシステム上に存在しない場合、 */
/* またはサーバーの接続要求キューがいっぱいの場合、 */ /* connect() は失敗します。 */ if ( return_value == -1 ) assert ( 0 );
/* close( client_socket_fd ); <-- オプション */
終了( EXIT_SUCCESS ); }
ソケット上のクライアントI/O
がゼロを返す場合connect()、クライアントはサーバーとアルゴリズム ダイアログを行うことができます。クライアントは を介してストリーム データを送信しwrite( client_socket_fd )、 を介してストリーム データを受信できますread( client_socket_fd )。
ストリーム ソケット上のクライアント I/O を説明するスニペット:
{
/* 構築コードを省略 */ return_value = connect ( client_socket_fd , ( struct sockaddr * ) & sockaddr_un , sizeof ( struct sockaddr_un ) );
if ( return_value == -1 ) assert ( 0 );
戻り値== 0の場合、client_algorithmic_dialog ( client_socket_fd ) ; }
/* close( client_socket_fd ); <-- オプション */
/* クライアント プロセスが終了したときに、 */
/* サーバーが read() を試みると、 */ /* read_count は 0 または -1 になります。 */ /* これは、サーバーが close() を実行するためのメッセージです。 */ exit ( EXIT_SUCCESS ); }
#BUFFER_SIZE 1024 を定義します
void client_algorithmic_dialog ( int client_socket_fd ) { char buffer [ BUFFER_SIZE ]; int read_count ;
strcpy (バッファ, "hola" ); write ( client_socket_fd ,バッファ, strlen (バッファ) + 1 ); read_count = read ( client_socket_fd ,バッファ, BUFFER_SIZE );
read_count > 0の場合、puts ( buffer ) ; }
参照
- パイプライン (Unix) – メッセージパッシングを使用したプロセス間通信のメカニズム
- Netlink – プロセス間のプロセス間通信のための Linux カーネル インターフェース
参考文献
- ^ Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1149. ISBN 978-1-59327-220-3
ソケットは、同じホスト (コンピューター) 上またはネットワークで接続された異なるホスト上のアプリケーション間でデータを交換できるようにする IPC の方法です
。 - ^ abc Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1150. ISBN 978-1-59327-220-3。
- ^ Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1150. ISBN 978-1-59327-220-3
サーバーは、クライアントがソケットを見つけられるように、ソケットを既知のアドレス (名前) にバインドします
。 - ^ ab Stevens, Richard W.; Fenner, Bill; Rudoff, Andrew M. (2004). Unix ネットワークプログラミング(第 3 版). Pearson Education. p. 14. ISBN 81-297-0710-1通常、
サーバー プロセスはacceptの呼び出しでスリープ状態になり、クライアント接続が到着して受け入れられるまで待機します。
- ^ ab Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1169. ISBN 978-1-59327-220-3。
- ^ abcd Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1159. ISBN 978-1-59327-220-3。
- ^ ab Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1166. ISBN 978-1-59327-220-3。
- ^ abc Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1149. ISBN 978-1-59327-220-3。
- ^ ab Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1153. ISBN 978-1-59327-220-3。
- ^ abc Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1151. ISBN 978-1-59327-220-3。
- ^ ab 「Linuxプログラマーズ・マニュアル(unix - ローカルプロセス間通信用ソケット)」。2018年4月30日。 2019年2月22日閲覧。
- ^ Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1197. ISBN 978-1-59327-220-3。
- ^ Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1183. ISBN 978-1-59327-220-3。
- ^ Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1152. ISBN 978-1-59327-220-3。
- ^ Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1184. ISBN 978-1-59327-220-3。
- ^ ab Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1181. ISBN 978-1-59327-220-3。
- ^ ab Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1165. ISBN 978-1-59327-220-3。
- ^ Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1154. ISBN 978-1-59327-220-3。
- ^ abc 「listen() の Linux マニュアル ページ」。
- ^ Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1157. ISBN 978-1-59327-220-3。
- ^ 「accept() の Linux マニュアル ページ」。
- ^ Kerrisk, Michael (2010). Linuxプログラミングインターフェース. No Starch Press. p. 1160. ISBN 978-1-59327-220-3。
注記
- ^ またはを使用することもできます。
PF_UNIX[ 11] AFは「アドレスファミリ」の略で、PFは「プロトコルファミリ」の略です。AF_LOCAL - ^ データグラムソケットは、ネットワーク層で使用されるデータグラム パケットと混同しないでください。[13]
- ^ UNIX では、すべてがファイルです。
