約18ヶ月前、OpenVOSリリース17.1におけるacceptの動作変更についてブログを書きました。その際、これらの変更がPOSIXベースのアプリケーションコードでのみ有効となる点を明記し忘れていました。要約すると、17.1以前では、サーバーアプリケーションコードがacceptルーチンを呼び出していない限り、STCPはクライアントの接続要求に応答しませんでした。 コードがacceptを呼び出していない場合、クライアントの接続要求はキューに入れられるものの応答されませんでした。アプリケーションがacceptを呼び出すと、STCPは接続応答を送信します。クライアントがまだ待機中であれば、その時点で接続が確立されます。クライアントが既に待機を諦めていた場合、接続応答に対してリセットを返すと、STCPは接続を破棄し、acceptは(ブロッキングモードを前提として)ハング状態となり、次の接続を待機します。
図1はこのシナリオを示している。左揃えのテキスト行はサーバーアプリケーションからのステータスメッセージであり、インデントされたpacket_monitor行(若干修正済み)はクライアントの動作結果である。 アプリケーション(acceptTestnoPosix)は起動後、ポート12345でリスニングを開始し、リスニング状態になると300秒間スリープする。クライアントはSyn(S)フラグを設定したTCPセグメントをポート12345に送信し、接続を試みる。3回試行後に接続を断念する。300秒後、アプリケーションがスリープから復帰しacceptを呼び出す。 STCPスタックはSynとAck(SA)フラグを設定したTCPセグメントでクライアントに応答します。クライアントは接続記録を保持していないためReset(R)を送信し、この時点でSTCPはブロック状態になります。ソケットがノンブロッキングモードの場合、acceptはEAGAINエラーを返していたでしょう。
acceptTestnoPosix 12345 を実行中 300秒間待機中 11:04:45.923 R TCP 164.152.77.50 164.152.77.217 11071 12345 S 11:04:48.925 R TCP 164.152.77.50 164.152.77.217 11071 12345 S 11:04:54.937 R TCP 164.152.77.50 164.152.77.217 11071 12345 S ポート番号 12345 で接続を受け入れる準備ができました。 11:09:41.852 T TCP 164.152.77.217 164.152.77.50 12345 11071 SA 11:09:41.854 R TCP 164.152.77.50 164.152.77.217 11071 12345 R |
図1 – 17.1以前のバージョンまたは17.1以降の非POSIXバージョンを受け入れる
アプリケーションがPOSIXベースの場合、動作は異なる(図2)。STCPは接続要求(S)に即時応答する(SA)。その後300秒後にアプリケーションが起動し、acceptを呼び出すと、STCPは受理されたソケットを返す。
acceptTestwithPosix 12345 acceptTestnoPosix 12345 を実行中 300秒間待機中 10:58:43.962 R TCP 164.152.77.50 164.152.77.217 11024 12345 S 10:58:43.964 T TCP 164.152.77.217 164.152.77.50 12345 11024 SA 10:58:43.964 R TCP 164.152.77.50 164.152.77.217 11024 12345 A ポート番号 12345 で接続を受け入れる準備ができました 接続を受け入れました |
図2 – POSIXベースのポスト17.1を受け入れる
動作の違いは重大な問題となる可能性があります。クライアントが接続後にサーバーアプリケーションからの応答を待機している場合、アプリケーションが実際にacceptを呼び出す前にタイムアウトが発生し、接続が閉じられる可能性があります。
POSIXでアプリケーションを構築するにはどうすればよいですか?まず次の行を記述します
#define _POSIX_C_SOURCE 200112L |
アプリケーションソースの最初の行であるべきです。次にライブラリパス
(master_disk)>system>posix_object_library
STCPライブラリの後、Cライブラリの前にオブジェクトライブラリパスに配置する必要があります。
これが実行されたかどうかはどうやって確認できますか? アプリケーションがバインドされたオブジェクトライブラリを、`display_program_module -object_dirs` コマンドで確認できます。
display_program_module acceptTestwithPosix -object_dirs
%azvos#m17_mas>SysAdmin>Noah_Davids>temp>acceptTestwithPosix.pm
オブジェクトディレクトリマップ:
11 検索ディレクトリ数
0 非検索ディレクトリ数
11 総ディレクトリ数
DTC ディレクトリパス
1 %azvos#m17_mas>SysAdmin>Noah_Davids>temp
2 %azvos#m17_mas>system>stcp>object_library
3 %azvos#m17_mas>system>stcp>object_library>socket
4 %azvos#m17_mas>system>stcp>object_library>net
5 %azvos#m17_mas>system>stcp>object_library>common
6 %azvos#m17_mas>system>posix_object_library
7 %azvos#m17_mas>system>c_object_library
8 %azvos#m17_mas>system>object_library
9 %azvos#m17_mas>opt>apache>lib
10 %azvos#m17_mas>opt>openssl>lib
11 %azvos#m17_mas>opt>mysql>lib>mysql
|
しかし、これは#defineがソースコードの一部かどうかは教えてくれません。
コードを実行できる場合、ソケットフラグを確認できます。POSIXベースのプログラムではSF_POSIXソケットフラグが設定されています。例えば、acceptTestnoPosix、acceptTestwithPosix、acceptTestwithPosixPathOnlyの3つのプログラムがあります。最後のプログラムはライブラリパスに>system>posix_object_libraryディレクトリを含んでいましたが、ソースコードに#defineを含めていませんでした。これは無効な組み合わせと見なされることに注意してください。 POSIXライブラリでバインドされ、かつコード内にPOSIX_SOURCE #define文が存在するアプリケーションのみが、SF_POSIXフラグ付きソケットを作成しました。
acceptTestnoPosix.pm 12345
acceptTestnoPosix 12345 を実行中
300 秒間待機中
as: match posix; dump_stcbq -full -lport 12345
as:
|
acceptTestwithPosix.pm 12345
acceptTestnoPosix 12345 を実行中
300秒間待機中
実行内容: match posix; dump_stcbq -full -lport 12345
SF_POSIX
実行中:
|
acceptTestwithPosixPathOnly.pm 12345
acceptTestnoPosix 12345 を実行中
300秒間待機中
as: match posix; dump_stcbq -full -lport 12345
as:
|
4つ目の可能性として、#define がソースに含まれていたが posix_object_library が使用されなかった場合が挙げられます。この場合、ソケットルーチンはエラーを返します。
acceptTestwithPosixDefineOnly 12345 acceptTestnoPosix 12345 を実行中 acceptTestnoPosix: リスニングソケットを作成できません: アプリケーションのビルドが不正です: Cランタイムの前にPOSIXランタイムを検索する必要があります。 |
STCPのコマンドとユーティリティはすべてPOSIXで構築されています。構築するアプリケーションもPOSIXを使用することを強く推奨します。
