2013-01-24 92 views
5

私は非同期I/Oを利用するために、完了ポートを使ってWindows NTにTCPサーバを作成しています。私は、I/O操作が完了したときに呼び出すTcpSocketクラス、TcpServerクラス、およびいくつかの(仮想関数)コールバックを持っています。読み込みが完了したときのonRead()。私は接続が確立されたときのonOpen()と接続が閉じられたときのonEof()なども持っています。 私はいつもソケットの読み込みを保留しています。ソケットが効果的にデータを取得すると(読み込みはサイズ> 0で完了します)、クライアントがクライアント側からソケットを閉じたときにonRead()を呼び出します。 readはsize == 0で完了します)、onEof()が呼び出され、クライアントはclosesocket(server_socket)でソケットを閉じたときにサーバが認識します。その側から。悪名高い「ERROR_NETNAME_DELETED」エラーをエラーとみなすことはできますか?

すべてが正常に動作しますが、私は事に気づいた:

iがclosesocket(client_socket)を呼び出します。接続のサーバー側のエンドポイントで、クライアント側ではなく(linger {true、0}を設定するかどうかで)、保留中の読み取りはエラーとして完了します。つまり、 です。読み取りサイズは= = 0だけでなくGetLastError()もエラー:64、または 'ERROR_NETNAME_DELETED'を返します。私はウェブ上でこれについて多くを検索しましたが、興味深いものは何も見つかりませんでした。

次に私は自分自身に尋ねました:しかし、これは本当の誤りですか?これは本当にエラーとみなされますか?

問題はサーバー側では、私がclosesocket(client_socket)を呼び出したときにonError()コールバックが呼び出されることです。 onEof()の代わりに。だから私はこれを考えた:

私は、この 'ERROR_NETNAME_DELETED ""エラー "が受信されたら、onError()の代わりにonEof()を呼び出すのはどうですか? いくつかのバグや未定義の動作が導入されますか?私はこの質問を作っ もう一つの重要なポイントはこれです:

私は私は特に、NTSTATUSエラーが含まれているoverlapped->内部パラメータと重なる 構造をチェックして、これは「ERROR_NETNAME_DELETED」で完了したことを読んで受け取った

基礎となるドライバのコード NTSTATUSエラーコード[http://www.tenox.tc/links/ntstatus.html]の一覧が表示された場合、 は「ERROR_NETNAME_DELETED」がNTSTATUS 0xC000013Bによって生成されていることを明確に確認できますが、これはエラーですが、「STATUS_LOCAL_DISCONNECT」と呼ばれています。まあ、エラーの名前のようには見えません。エラーである `ERROR_IO_PENDING 'に似ているようですが、正しい動作のステータスもあります。

OVERLAPPED構造体の内部パラメータをチェックするのはどうでしょうか?これが== 'STATUS_LOCAL_DISCONNECT'の場合は、onEof()コールバックの呼び出しが実行されますか?物事を混乱させるだろうか?

さらに、サーバー側から、私がDisconnectEx()を呼び出す前に closesocket(client_socket)を呼び出す必要があります。私はそのエラーを受け取りません。しかし、私はDisconnectEx()を呼びたくないのはどうですか?例えば。サーバーがシャットダウンしていて、DisconnectEx()の完了をすべて待つのではなく、接続されているすべてのクライアントを閉じるだけの場合。

+1

@ハンス、彼は彼がそのエラーに遭遇した方法を説明する素晴らしい仕事をしたと思います。 –

答えて

3

エラー状態をどのように扱うかは、あなた次第です。あなたのケースでは、このエラー状態は完全に予期されており、期待される状態として扱うのは完全に安全です。

このような性質のもう1つの例は、API関数を呼び出すが、提供するバッファの量がわからない場合です。だからあなたは十分に大きくなることを望むバッファを提供します。API呼び出しが失敗した場合は、最後のエラーがERROR_INSUFFICIENT_BUFFERであることを確認します。これは予想されるエラー状態です。その後、大きなバッファで再度試すことができます。

+0

私はあなたに同意します。私が想像することができる唯一の欠点は、エラーERROR_NETNAME_DELETEDがWindowsの他のものに対して生成され、実際のエラー状態が発生したときにonEof()コールバックがonError()の代わりに呼び出されることです。だから多分、オーバーラップされた構造のNTSTATUSをチェックするだけかもしれません。 –

+0

あなたは 'OVERLAPPED'構造体から' NTSTATUS'値を読み取るつもりはありません。それは内部的なものであり、変更される可能性があります。それに関する文書は明らかです。 –

+0

ええ、そうです、内部のメンバーは使用するつもりはないので、おそらくGetLastError()に依存します。 –

2

エラー状態をどのように扱うかはあなた次第ですが、問題はロジックエラーから未定義の動作まで、潜在的な問題の兆候です。

最も重要な点は、closesocketの後にSOCKETハンドルに触れないことです。あなたは何ですかEOFでをやりますか? closesocketはすでに発生しており、ハンドルは無効であるため、ERROR_NETNAME_DELETEDハンドラでは実行できないのは、EOFを検出したときに当面はclosesocketになります。

これは、保留中の読み取りがちょうどclosesocket(使用可能な実データで)完了し、アプリケーションが右closesocketを検出した場合に何が起こるか想像するのも有益です。あなたは入ってくるデータを扱います...同じソケットハンドルを使ってクライアントに答えを返しますか?そのハンドルの次の読み取りをスケジュールしますか?それはすべて間違っていて、あなたにそれについて話すためのERROR_NETNAME_DELETEDはありません。

非常に不幸な瞬間、つまりclosesocketの直前で、保留中の読み取りがEOFで完了するとどうなりますか?通常のOnEofコールバックが発生し、そのコールバックがclosesocketの場合、それは再び間違っています。

closesocketが1つのスレッドで実行され、別のスレッドがI/O完了を待っている間に、より深刻な問題が発生する可能性があります。最初のスレッドがclosesocketを呼び出している間に、別のスレッドがWSARecv/ReadFileを呼び出していないことを確認してください。それは、たとえそれが大部分の時間を費やしたかのように見えるとしても、未定義の動作です。それは閉鎖されたので、それは無用であることソケットハンドルを知らないだ場合、完了(または失敗)の取り扱いコードを要約する

読み込みが正しいことはできません。 closesocketの後に、OVERLAPPED構造体を再利用することができないため、I/O完了が保留されるのを待つと便利です。 通常の動作中に起こったように、ソケットはまだ開いています(エラー/ステータスコードは関係ありません)。

+0

本当に良い点があります。まあ、基本的に私はonEof()を使ってクリーンアップ(例えばdeallocメモリなど)を実行していますが、そのために2つのコールバックを有効にする必要があります:onEof() () - このようにしてonEof()が受信されると、他の部分はあなたが提案したようにclosesocket()を呼び出すことができます。だから、私がそれを持っているなら、保留中のreadがclosesocket()の前に完了し、アプリケーションがそれを検出したなら、このシナリオを知らせるためにERROR_NETNAME_DELETEDがあり、それはその目的ですか? –

+0

いいえ、 "完了前/完了"シナリオには "ERROR_NETNAME_DELETED"がありません。 'ERROR_NETNAME_DELETED'コールバックでクリーンアップを行うのが間違っている理由も説明しています:この"不幸な "タイミングで成功した読み込みができます。何も処理する必要はありません(WSARecvを再スケジュールすることはできません'on closed socket)。 –

0

あなたは間違った方法を呼び出しています。 WSAGetLastError()に電話する必要があります。 Winsock API呼び出し後のGetLastError()の結果は無意味です。

+0

実際にWSAGetLastError()を呼び出しています。また、エラー値も同じです。私は非ネットワークI/Oに対してもI/O完了ポートを使用するので、GetLastError()について言及しましたが、ネットワークI/Oに対してのみエラーが発生すると思います。 –

+0

@MarcoPagliaricciだから実際にあなたの質問はそう言わなければならない。 – EJP

関連する問題