2017-11-07 64 views
0

当社のアプリケーションには、顧客の社内工場ネットワークに積極的に接続し、検査イベントが発生したときにメッセージを送信する機能があります。顧客は、自分のマシンとアプリケーションのIPアドレスとポート番号を当社のソフトウェアに入力します。Windowsソケットエラーの解決WSAENOBUFS(10055)

私はブロックモードでTClientSocketを使用しており、OnConnectOnErrorイベントに対してコールバック関数を提供しています。アプリケーションの起動時には、私は別のスレッドで、次のコードを呼び出すときに、上記の機能を仮定すると、活性化されている:

// Attempt active connection 
try 
    m_socketClient.Active := True; 
except 
end; 

// Later... 
// If `OnConnect` and socket is connected...send some data! 
// If `OnError`...call `m_socketClient.Active := True;` again 

IP +ポートが有効な場合は、機能がうまく動作します。しかし、そうでない場合、最終的にWindowsソケットエラー10055(WSAENOBUFS)が発生し、アプリケーションがクラッシュし、数千のエラー(および数時間または数日後)が発生します。このようthis one from ServerFrameworkthis one from Microsoft話として

様々な記事を約exhausting the Windows non-paged poolと言及(1)積極的に未処理の非同期操作を送信数を管理し、(2)I/O操作に使用されたデータ・バッファを解放します。

私の質問はこれを実現する方法ですと3倍です:

A)私はメモリがリークされていることを何か間違ったことをやっていますか?たとえば、OnErrorハンドラにクリーンアップコードがありませんか?

B)I/Oバッファが枯渇しているかどうかを監視するにはどうすればよいですか?私はProcess Explorerを使用してアプリケーションがリークの原因であることを確認しましたが、理想的にはこれをプログラム的に測定する方法が必要です。

C)アプリケーションを再起動する以外に、I/O操作データバッファをクリアまたは解放するようWindowsに依頼する方法はありますか?

Delphi、C/C++、C#fineのコードサンプル。

+0

おそらく、 'TClientSocket'はDelphi 6以降では廃止されていますが、今は16年半前です。これらのコンポーネントが適切にハンドルをクリーンアップしない場合、私は驚くことはありません。 (シェルコンポーネントのように)あまり書かれていなかった他のDelphiコンポーネントも廃止され、後で削除されました。 –

+0

ありがとうございましたGünther、実際に私はそれを知らなかった。私が使用するコンポーネントをリフレッシュする必要があります!調査とテストの日の後、私は問題(これらのTCP/IPコンポーネントの使用経験がないことを反映しています)を発見したと思います。ソケットがタイムアウトしてOnErrorイベントを起動すると、 'm_socketClient.Socket.Close()'を呼び出します。私の調査を完了するのに忙しくて、それに基づいて答えを打ち明けます。 – AlainD

+0

'TClientSocket'は廃止されるかもしれませんが、かなり堅実なコンポーネントです。私はこれまでメモリ/リソースに関する問題は一度も経験しておらず、私はこれを非常に長い間使ってきました。しかし、OnErrorイベントで 'Active:= True'を設定しようとしたことはありません。そのイベントで失敗したソケットを常に 'Close()'してから、スレッドがソケットを再び開くタイミングを決定させます。接続を開くときにエラーが発生した場合は、接続をもう一度開こうとする前に、数秒待つことをお勧めします。 I/Oの読み込み/書き込み中にエラーが発生した場合は、直ちに再接続してください。 –

答えて

0

A)リソースリークの原因はプログラミングエラーです。 OnErrorイベントが発生すると、ソケットに関連付けられた低レベルのリソースを解放するためにSocket.Close()を呼び出す必要があります。

B)メモリリークは標準のWorking Setプロセスのメモリ使用量には表示されません。あなたのプロセスに属するオープンハンドルは、GetProcessHandleCountで可能であることが監視される必要があります。 Delphiのthis answerを参照してください。これはうまく動作しています。このanswer in C++はテストされていませんでしたが、答えは受け入れられるので、うまくいくはずです。もちろん、GetProcessHandleCountをC++で直接使用できるはずです。

C)多くの研究の末、通常のメモリリークと同様に、Windowsの後に「クリーンアップ」するよう求めることはできません。ハンドルリソースがアプリケーションによってリークされたため、原因を見つけて修正する必要があります(上記のAとBを参照)。

関連する問題