3

DataAvailable のときに読み取るストリームを作成する TCPClient があります。

!DataAvailable の 20 秒ごとに、ACK メッセージを使用してソケットに ping を送信し、ストリームが閉じないようにします。

しかし、私はさまざまな結果を得ているようです。ストリームを開くたびに(基本的にサービスを再起動する)、トランスポートエラーが発生するようです。

これは、私の Connect 関数の短縮版です。

client = new StreamClient();
client.Connect(new IPEndPoint(clientAddress, senderPort));
stream = client.GetStream();
bool status = SendMessage(seq, sync, MessageTypes.Init);

SendMessage 関数は次のことを行います。

if (stream == null) return false;
stream.Write(TransmitBuffer, 0, TransmitMessageLength);

My Close 関数は次のことを行います。

if (stream != null)
{
    SendMessage(seq, sync, MessageTypes.Finish);
    stream.Close();
}
stream = null;

client.Close();
client = null;

ソケットの性質上、SendMessage 呼び出しが失敗することがあると予想されます。

しかし、一度接続すると、すべてが正常に実行され、失敗したメッセージが表示されないことがあります。しかし、ACK が失敗する場合もあります。ACK が失敗すると、Close を呼び出します。これにより、Connect が強制され、ソケットのもう一方の端が開いていることが検証されます。それが失敗した場合、私はその終わりがダウンしていることを知っています. ただし、その呼び出しが失敗せず、20 秒後に ACK が失敗する場合があります。

なぜこれが起こるのかについて誰かが私に意見を与えることができますか? 20 秒待つには長すぎますか? ソケットの端を適切に閉じていませんか?

私が戦っている特定のエラーメッセージは次のとおりです。

Unable to write data to the transport connection: An established connection was aborted by the software in your host machine.

そして、それはで発生しますstream.Write(TransmitBuffer, 0, TransmitMessageLength);

4

4 に答える 4

1

ネットワーク通信ライブラリの開発時にも同様の問題が発生しました。ACKを使用するのではなく、最も信頼できる解決策は、nullデータを送信すること(別名、存続)であることがわかりました。この場合、値がゼロのbyte[1]です。これにより、次のいずれかになります。

  1. 送信が成功すると、受信側でデータが無視される可能性があります。
  2. 送信に失敗すると、すぐに接続が閉じられ、再確立されます。

これらの結果のいずれかにより、接続が常に使用可能な状態にあることが保証されました。

于 2013-01-23T15:24:06.597 に答える
1

一般に、プロトコルを TCP の上に置くことは大きな間違いです。接続の信頼性が低下するだけです。TCP はすでに、あるマシンから送信されたデータがネットワーク上の別のマシンによって受信されることを非常に強力に保証しています。それを失敗させることができるのは、非常にひどい外部環境だけです。機器の停電や予定外の再起動など。

いずれかのマシンが意図的にソケットを閉じない限り、接続は切断されません。もちろん、これは常に予測可能な方法で行う必要があります。トランザクションの論理的な終了、またはマシンがサインオフしているという明示的なメッセージ。

「ストリームを閉じないようにする」以外に、この「ACKプロトコル」を接続ロジックに追加する動機はありませんでした。ここに表示されているのは、実際には機能しないということだと思います。実際には、ストリームが閉じるのを妨げているわけではありません。そのため、プロトコル層を追加する前と同じようにまだうまくいかず、予期しない「確立された接続が中止されました」という例外が引き続き発生します。

信頼性を低下させた例は、追加した 20 秒のタイムアウト チェックです。TCP は 20 秒のタイムアウトを使用しません。指数バックオフ アルゴリズムを使用して、タイムアウトをチェックします。通常、少なくとも 45 秒が経過するまであきらめません。したがって、 TCP がそうする前に、接続が切れていると宣言します。

これを進める方法についてアドバイスするのは難しいです。しかし、プロトコルを追加することによるものではないことは明らかです。試してみましたが、うまくいきませんでした。予期せず接続が切断された理由を突き止める必要があります。残念ながら、それには足を運ぶ必要があります。マシンとサーバーの間にあるネットワーク機器とソフトウェアの種類について洞察を得る必要があります。問題がワイヤの反対側にあることをある程度期待してください。これは、診断が最も難しいものであるためです。問題にサイトのネットワーク管理者を関与させることは、重要な最初のステップです。

于 2013-01-21T16:13:06.033 に答える
1

あなたの実装で私が目にする主なことは、ストリームを接続とし​​て扱っているように見えることですが、そうではありません。Stream インスタンスのチェックは、代わりに TcpClient インスタンスのチェックである必要があります。それがあなたの問題の原因かどうかはわかりませんが、私には間違いなく奇妙に見えます。

これの代わりに:

stream = client.GetStream();
if (stream != null)
{
    SendMessage(seq, sync, MessageTypes.Finish);
    stream.Close();
}
stream = null;

私は通常、次のようなことをします。

if (client != null)
{
    if (client.Connected)
    {
        client.GetStream().Close();
    }

    client.Close();
    client = null;
}

ストリーム自体ではなく、ストリームを操作する前に TcpClient.Connected を確認する必要があります。
もう 1 つ言及したいのは、TcpClient との接続、読み取り、書き込みには必ず非同期メソッドを使用することです。同期のものは簡単ですが、私の経験では、それらに依存すると問題が発生する可能性があります。

于 2013-01-21T17:17:38.237 に答える
1

なぜ ACK を送信するのですか? SYN を送信する必要があります。

また、ACK、SYN、RST を送信したり、その他のフラグを設定したりしないでください。あなたはTCP内部に手を出しています。あなたはアプリケーションレベルのプロトコルを作成しており、キープアライブはその一部です.iircが原因です。 %29.aspx接続は、閉じるまで開いたままになります。

于 2013-01-26T07:24:20.477 に答える