この記事では、モジュールが不足しているか、少なくとも真剣にTCPソケットの作成に使用するためのstcpデバイスクローンの利用可能な数を枯渇させてしまう可能性がある一般的なコーディングエラーについて説明したいと思います。
ソケット関数を呼び出すたびに、STCPはstcpデバイスの新しいクローンを作成します。作成できるクローンの最大数は、devices.tinエントリのclone_limitフィールドで制御されます。
/ =name stcp.m17
=モジュール名 m17
=デバイスタイプストリーム
=access_list_name stcp_access
=streams_driver stcp
=clone_limit 5120
=コメント TCP APIを提供します。
|
現在使用されているクローンの数を確認するには、 analyze_system でデバイス構造体をダンプして clone_count の値を確認します。clone_count が clone_limit と等しい場合、ソケット関数の呼び出しは e$clone_limit_exceeded を返します。"デバイスのクローン制限を超えました" というエラーを返します。
as: match clone; dump_dvt -name stcp.m17
clone_limit: 5120
clone_count. 42
cloned_from: -27271
remote_clone_limit: 0
|
一般的に、クローンデバイスを作成するソケットコールの後には 繋ぐ呼び出しまたは 縛って聞くを呼び出します。その時点で「netstatコマンド」を実行すると、対応するエントリが表示されます。
netstat -numeric -all_sockets アクティブな接続(サーバーを含む プロトRecv-Q Send-Q ローカルアドレス 外国人アドレス(州) tcp 0 0 0 172.16.124.217:23 192.168.109.22:50038 ESTABLISHED tcp 0 0 0 172.16.124.217:22 172.16.124.24:54987 ESTABLISHED tcp 0 0 0 10.20.1.1.1:37 10.20.1.26:1528 TIME_WAIT tcp 0 0 0 10.20.1.1.1:37 10.20.1.27:1579 TIME_WAIT tcp 0 0 0 172.16.124.217:61780 192.168.109.22:23 ESTABLISHED tcp 0 0 0 172.16.124.217:22 172.16.124.50:17421 ESTABLISHED tcp 0 0 0 172.16.124.217:22 172.16.124.50:17658 ESTABLISHED tcp 0 0 0 *:23 *:* LISTEN tcp 0 0 0 *:6666 *:* LISTEN tcp 0 0 0 *:21 *:* LISTEN tcp 0 0 0 *:3000 *:* LISTEN tcp 0 0 0 *:7 *:* LISTEN tcp 0 0 0 *:9 *:* LISTEN tcp 0 0 0 *:13 *:* LISTEN tcp 0 0 0 *:19 *:* LISTEN tcp 0 0 0 *:37 *:* LISTEN tcp 0 0 0 *:901 *:* LISTEN tcp 0 0 0 *:1414 *:* LISTEN tcp 0 0 0 *:81 *:* LISTEN tcp 0 0 0 10.20.1.1.1:37 10.20.1.9:3633 TIME_WAIT tcp 0 50 10.10.1.1.1:52653 10.10.1.200:3001 ESTABLISHED tcp 0 0 0 10.10.1.1.1:52624 10.10.1.1.200:3001 FIN_WAIT_1 tcp 0 0 0 10.20.1.1.1:61704 10.20.1.3:48879 ESTABLISHED tcp 0 0 0 *:3001 *:* LISTEN tcp 0 0 0 *:3002 *:* LISTEN tcp 0 0 0 *:3003 *:* LISTEN tcp 0 0 0 *:4000 *:* LISTEN tcp 0 0 0 172.16.124.217:4000 172.16.124.78:1024 ESTABLISHED tcp 0 0 0 172.16.124.217:4000 172.16.124.227:1025 ESTABLISHED tcp 0 0 0 *:4001 *:* LISTEN tcp 0 0 0 *:4002 *:* LISTEN tcp 0 0 0 *:4003 *:* LISTEN tcp 0 0 0 *:4004 *:* LISTEN tcp 0 0 0 *:22 *:* LISTEN tcp 0 0 0 *:4005 *:* LISTEN tcp 0 0 0 *:4006 *:* LISTEN tcp 0 0 0 172.16.124.217:4006 172.16.124.203:49231 ESTABLISHED tcp 0 0 0 *:4007 *:* LISTEN tcp 0 0 0 *:4008 *:* LISTEN tcp 0 0 0 *:4009 *:* LISTEN tcp 0 0 0 172.16.124.217:4008 172.16.124.203:49262 ESTABLISHED tcp 0 0 0 *:4010 *:* LISTEN tcp 0 0 0 *:4011 *:* LISTEN tcp 0 0 0 *:4012 *:* LISTEN tcp 0 0 0 *:4013 *:* LISTEN tcp 0 0 0 *:4014 *:* LISTEN tcp 0 0 0 *:4015 *:* LISTEN tcp 0 0 0 *:80 *:* LISTEN tcp 0 0 0 *:9182 *:* LISTEN tcp 0 0 0 *:445 *:* LISTEN tcp 0 0 0 *:139 *:* LISTEN tcp 0 0 0 10.20.1.1:53495 10.20.1.9:48879 ESTABLISHED tcp 0 0 0 10.20.1.1.1:61703 10.20.1.3:48879 ESTABLISHED tcp 0 0 0 10.20.1.1.1:61707 10.20.1.3:48879 ESTABLISHED tcp 0 0 0 10.20.1.1.1:61705 10.20.1.9:48879 ESTABLISHED tcp 0 0 0 10.20.1.1.1:61709 10.20.1.9:48879 ESTABLISHED tcp 0 0 0 10.20.1.1:61710 10.20.1.9:48879 ESTABLISHED tcp 0 0 0 172.16.124.217:61789 172.16.124.203:4000 ESTABLISHED tcp 0 400 172.16.124.217:22 172.16.124.50:17674 ESTABLISHED |
行数をカウントアップすると42行以上になりますが、これはnetstatで表示されるすべてのエントリがstcpデバイスクローンを使用しているわけではないからです。例えば、OSL 接続や NIO で使用されている X25_cpc 接続などです。詳細は socket_count.cm を参照してください。
接続やバインドを行わずにソケットコールが行われた場合やバインドに失敗した場合、clone_countの値がnetstatで表示されるエントリ数よりも大きくなるという逆の問題が発生する可能性があります。
as: match clone; dump_dvt -name stcp.m17
clone_limit: 5120
clone_count. 4131
cloned_from: -23179
remote_clone_limit: 0
のように
|
私は再びnetstatの出力を含めていませんが、私を信じて、それは前の例から変わっていません。
このような状況は、以下のコードにより、余分な(4131 - 42)、明らかにアカウントされていない STCP デバイスのクローンが作成されました。このコードは、ソケット関数の後にバインド関数を呼び出しています。バインドに失敗するとループします。多くのアプリケーションでは、1秒、60秒、300秒のタイマーを追加して再試行していますが、これはエラーの原因となっている状態が解消されないことを前提に、避けられない事態を遅らせるだけです。
tryAgain = 1; while (tryAgain) { if ((socks0 = socket (AF_INET, SOCK_STREAM, 0)) < 0) { if (debugFlag) perror ("badService: can't create listening socket"); } else { /* build a sockaddr structure holding the address we will bind to. The IP address is INADDR_ANY meaning we will listen on all active IP addresses */ bzero ( (char *) &serv_addr, sizeof (serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl (INADDR_ANY); serv_addr.sin_port = htons (portNumber); /* now bind to the address and port */ if (bind (socks0, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) { if (debugFlag) perror ("badService: can't bind address, trying again"); } else tryAgain = 0; } } |
最も一般的なエラーは、他のプロセスが既に要求されたポートにバインドしている場合です。エラーの理由に関わらず、解決策はバインドエラーを報告した後にソケットを閉じることです。
tryAgain = 1;
while (tryAgain)
{
if ((socks0 = socket (AF_INET, SOCK_STREAM, 0)) < 0)
{
if (debugFlag)
perror ("goodService: can't create listening socket");
}
else {
/* build a sockaddr structure holding the address we will bind to.
The IP address is INADDR_ANY meaning we will listen on all active
IP addresses */
bzero ( (char *) &serv_addr, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl (INADDR_ANY);
serv_addr.sin_port = htons (portNumber);
/* now bind to the address and port */
if (bind (socks0, (struct sockaddr *) &serv_addr,
sizeof (serv_addr)) < 0)
{
if (debugFlag)
perror ("goodService: can't bind address, trying again");
if (close (socks0) < 0)
if (debugFlag)
perror ("goodService: can't close old socket");
}
else
tryAgain = 0;
}
}
|
この投稿では、コーディングエラーのためにclone_limitに到達することについて述べてきましたが、もしエラーがない場合、アプリケーション環境が本当にすべてのクローンデバイスを使用しているとしたらどうでしょうか。その場合、システムリミットの16,000に達していないと仮定して、リミットを上げることができます。devices.tin ファイルの stcp デバイスの clone_limit フィールドを更新し、devices.table を再作成する必要があります。17.1 以降のリリースでは、update_device_info コマンドを使って現在のブートの制限を上げ、次のブートは更新された devices.table に頼ることができます。17.1 より前のリリースでは、再起動するしかありません。現在の必要性と予想される成長に対応する値に制限値を設定する必要があります。現在、クローンデバイスを消費しているアプリケーションのバグがなくても、将来的に発生しないという保証はありません。利用可能なすべてのクローンデバイスを消費しているアプリケーションは、大量のストリームメモリを消費し、 ストリームメモリを使い果たすことは、既存の TCP 接続に悪影響を及ぼします。