none
TCP/IPで通信中に突然パケット欠損・切断 RRS feed

  • 質問

  • TCP/IPで今まで何の問題なく通信していたのに突如として

    送信処理しているのに、エラーも出ずに送信されない。

    または、送信はしているけど受信しなくなるといったことはありますでしょうか?

     

    また、受信してEndReadすると例外が発生してしまう

    ということはありますでしょうか?(相手に問題がないのに)

     

    ご存知の方いらっしゃれば教えて頂ければありがたいです。

    2008年4月18日 12:19

回答

  • こんにちは、無限極限さん。

     

    TCP/IPで今まで何の問題なく通信していたのに突如として

    送信処理しているのに、エラーも出ずに送信されない。

    または、送信はしているけど受信しなくなるといったことは、ネットワークではよくあると思います。

     

    エンドポイント同士が問題なくても、途中のルートでセッションが無効になると、まさにそのような状況になります。

    適切な時間でタイムアウトさせて、接続からやり直すなどが必要です。

     

     

    また、受信してEndReadすると例外が発生してしまう

    ということは相手に問題がなくてもあります。

     

    例外内容に原因がズバリ書いてあると思います。

     

     

    ネットワークトレースを有効化すると、有効な情報が得られるかもしれません。

    ※.NET Framework 2.0以降のみ

     

    NET Framework 開発者ガイド

    ネットワーク トレースの有効化

    http://msdn2.microsoft.com/ja-jp/library/a6sbz1dx(VS.80).aspx

    2008年4月22日 4:25
  •  無限極限 さんからの引用

    リトライの仕組みですがエラーが出るならば対処できますが

    エラーも出ずに送信してるけど受信できないとかだと

    どうやって異常を検知するかが悩みどころです。

     

    TCPは伝達を保証する仕組みです。

    送信が正常に終了された場合、

    相手に正常に届いていると見なしていいはずです。

     

    それができないということは、

    間に変なプロキシとかが入ってない限りは経路の問題ではなく、

    送信側か受信側、もしくはその両方に問題がある

    ということになります。

     

    コードを見直したほうがよいと思います。

    2008年4月27日 0:58
  • あー・・・。

    すみません、下記の事例は間違いです。

     

    「なお、このシステムでは接続を維持したまま、データを再送してもダメでした。」が間違い。

    「データ受信のタイミングでエラー発生、60秒待って受信リトライしてもダメでした。」の例でした。

     

     

     西脇 さんからの引用

    無限極限さんのいうような事例が、私の経験でもあります。

     

    とある端末~センター間の通信をTCP/IPで行っているシステムでの例です。

     

    全試行回数:22156回

    問題発生数:10回

     

    発生率にすると0.0451%です。

     

     

    なお、このシステムでは接続を維持したまま、データを再送してもダメでした。

    接続をいったん切り、接続からやり直すと正常にTCP/IP通信ができます。

     

    なので、接続からやり直すようにリトライする仕組みを導入、問題が表面化しないようにしました。

    このような方法なら、無限極限さんの手の届く範囲のことで対処しようがあると思いますがいかがでしょうか?

    2008年4月28日 8:20
  •  無限極限 さんからの引用

    ちなみにプロキシが入るとまずいのでしょうか?

     

    いいえ。まずいことなどありません。

    ただいろいろ説明がめんどくさいだけです。

     

     西脇 さんからの引用

    TcpClientクラスを使った標準的なコーディングでは、送信が正常に終了された場合、それはあくまで.NET Framework内部で利用している Windows Sockets の send() が完了したことを意味し、相手に正常に届くまでは保証されません。

    つまり、TCPは伝達を保証しますが、TcpClientクラスは伝達を保証しません。

    正確な実装がどうなっているかは、マイクロソフトへ確認して下さい。

     

    ただの言葉の問題ですが。

    「伝達を保証する」というのは、「絶対に届く」という意味ではありません。

    「届いていない場合にそれがわかる」という意味です。

     

    突然LANケーブルは抜かれる、という状況でメッセージを絶対に送れるようにする技術は不可能ですから。

     

    そういう意味では、

    System.Net.TCPClientもSystem.Net.SocketもWinsockのSendも同様に「伝達を保証します」。

     

    ただ、その保証は遅延があります。

    効率を上げるために、ドライバや間のルーターなど、さまざまな層にバッファが存在しえます。

    そのため、sendは正常に完了したが、その後相手まで届かなかった、という場合ありえます。

    その場合、次の呼び出しの時にエラーがあがります。

     

    バッファや遅延の量は環境によって違いますので、それに依存したプログラムを組んではいけません。

     

    また、

     西脇 さんからの引用

    送信後に何らかの応答を相手が送信し、それを受信する処理を1セットとし、応答の受信タイムアウトを、アプリケーションプロトコルとしての失敗として処理するとよいと思います。

    という戦略は、「できる限り避けるべき」です。

    受信確認のためだけにメッセージを送るのは、トラフィックの無駄です。

    2008年4月29日 4:07
  • ちなみにこのエラーは非同期の場合でも発生しますか?

    やはり、同期で積極的に受信していないと発生しないものなのでしょうか?

     

    同期・非同期によらず発生します。

    でないと伝達できたか知りようがないですから。

     

    また、厳密に言うと次のSend時に発生すると決まってるわけではありません。

    大抵は次のSend時になりますが。

     

    次の次のSendになる場合もありますし、

    ShutdownやReceiveのときにエラーになる場合もあります。

    2008年5月10日 1:53

すべての返信

  • 経験がないので回答はできません。

     

     無限極限 さんからの引用

    TCP/IPで今まで何の問題なく通信していたのに突如として

    送信処理しているのに、エラーも出ずに送信されない。

    または、送信はしているけど受信しなくなるといったことはありますでしょうか?

     

    また、受信してEndReadすると例外が発生してしまう

    ということはありますでしょうか?(相手に問題がないのに)

    「ある」か「ないか」は経験者の方に委ねます。

    しかし、仮に「あった」として無限極限さんのところで出ている現象と同一とは限りません。

    また、初歩的なミスからライブラリの不具合まで幅広い可能性がある中で、これだけの情報で適切なアドバイスができる人は少ないかと思います。

     

    言いたいのは「もっと、現象について情報を書きませんか」ということです。

    2008年4月18日 15:09
    モデレータ
  • 返信ありがとうございます。

     

    現象についてですが、書いてある通りでございます。

    現象がなさ過ぎて、僕もどう対処したらよいかわからなく

    質問させて頂いたしだいです。

    2008年4月19日 3:51
  • こんにちは、無限極限さん。

     

    TCP/IPで今まで何の問題なく通信していたのに突如として

    送信処理しているのに、エラーも出ずに送信されない。

    または、送信はしているけど受信しなくなるといったことは、ネットワークではよくあると思います。

     

    エンドポイント同士が問題なくても、途中のルートでセッションが無効になると、まさにそのような状況になります。

    適切な時間でタイムアウトさせて、接続からやり直すなどが必要です。

     

     

    また、受信してEndReadすると例外が発生してしまう

    ということは相手に問題がなくてもあります。

     

    例外内容に原因がズバリ書いてあると思います。

     

     

    ネットワークトレースを有効化すると、有効な情報が得られるかもしれません。

    ※.NET Framework 2.0以降のみ

     

    NET Framework 開発者ガイド

    ネットワーク トレースの有効化

    http://msdn2.microsoft.com/ja-jp/library/a6sbz1dx(VS.80).aspx

    2008年4月22日 4:25
  • 西脇さん。貴重なお話ありがとうございます。

    よくあることなんですか。

    これは困りました。

    僕の手の届く範囲のことなら対処しようがあるのに、間の話となると・・・

     

    接続しなおしですか。これは、大変だ。

    とても参考になりました。

     

    2008年4月22日 13:42
  • 無限極限さんのいうような事例が、私の経験でもあります。

     

    とある端末~センター間の通信をTCP/IPで行っているシステムでの例です。

     

    全試行回数:22156回

    問題発生数:10回

     

    発生率にすると0.0451%です。

     

     

    なお、このシステムでは接続を維持したまま、データを再送してもダメでした。

    接続をいったん切り、接続からやり直すと正常にTCP/IP通信ができます。

     

    なので、接続からやり直すようにリトライする仕組みを導入、問題が表面化しないようにしました。

    このような方法なら、無限極限さんの手の届く範囲のことで対処しようがあると思いますがいかがでしょうか?

    2008年4月25日 4:35
  • 具体的な数字まで示して頂きありがとうございます。

     

    感想なのですがパーセンテージは僕が感じているよりぐっと低い数値でした。

    僕のシステムだとぐっと高い気がします。

    具体的な数字は出していないのですが、環境にかなり影響される気がします。

     

    リトライの仕組みですがエラーが出るならば対処できますが

    エラーも出ずに送信してるけど受信できないとかだと

    どうやって異常を検知するかが悩みどころです。

     

    2008年4月26日 5:32
  •  無限極限 さんからの引用

    リトライの仕組みですがエラーが出るならば対処できますが

    エラーも出ずに送信してるけど受信できないとかだと

    どうやって異常を検知するかが悩みどころです。

     

    TCPは伝達を保証する仕組みです。

    送信が正常に終了された場合、

    相手に正常に届いていると見なしていいはずです。

     

    それができないということは、

    間に変なプロキシとかが入ってない限りは経路の問題ではなく、

    送信側か受信側、もしくはその両方に問題がある

    ということになります。

     

    コードを見直したほうがよいと思います。

    2008年4月27日 0:58
  • れいさん。アドバイスありがとうございます。

    見直してみます。

    ちなみにプロキシが入るとまずいのでしょうか?

    2008年4月27日 14:17
  • あー・・・。

    すみません、下記の事例は間違いです。

     

    「なお、このシステムでは接続を維持したまま、データを再送してもダメでした。」が間違い。

    「データ受信のタイミングでエラー発生、60秒待って受信リトライしてもダメでした。」の例でした。

     

     

     西脇 さんからの引用

    無限極限さんのいうような事例が、私の経験でもあります。

     

    とある端末~センター間の通信をTCP/IPで行っているシステムでの例です。

     

    全試行回数:22156回

    問題発生数:10回

     

    発生率にすると0.0451%です。

     

     

    なお、このシステムでは接続を維持したまま、データを再送してもダメでした。

    接続をいったん切り、接続からやり直すと正常にTCP/IP通信ができます。

     

    なので、接続からやり直すようにリトライする仕組みを導入、問題が表面化しないようにしました。

    このような方法なら、無限極限さんの手の届く範囲のことで対処しようがあると思いますがいかがでしょうか?

    2008年4月28日 8:20
  • ごれんらくありがとうございます。

    どうやらTCP/IPはかなり優秀のようで

    僕が書いたコードがだめなようですね。

    見直します。

    2008年4月28日 14:44
  • 自分の書いたコードの確認は確かに重要です。

     

    TcpClientクラスを使った標準的なコーディングでは、送信が正常に終了された場合、それはあくまで.NET Framework内部で利用している Windows Sockets の send() が完了したことを意味し、相手に正常に届くまでは保証されません。

     

    つまり、TCPは伝達を保証しますが、TcpClientクラスは伝達を保証しません。

    正確な実装がどうなっているかは、マイクロソフトへ確認して下さい。

     

     

    送信後に何らかの応答を相手が送信し、それを受信する処理を1セットとし、応答の受信タイムアウトを、アプリケーションプロトコルとしての失敗として処理するとよいと思います。

     

     

     無限極限 さんからの引用

    ごれんらくありがとうございます。

    どうやらTCP/IPはかなり優秀のようで

    僕が書いたコードがだめなようですね。

    見直します。

    2008年4月29日 1:03
  • 驚愕なのですがTCP/IPは大丈夫だけどもTcpClient

    には保証がないのですか。

    ・・・

    そんなことってあるのですね。

     

    送信した後に相手から送信してもらうやり方は僕もここ数日考えておりました。

    コードを根本的に書き直さなきゃいけないので、もっと楽な方法はないものかと

    考えておりましたが、やっぱりそれしかなさそうですね。

     

    ありがとうございます。

    2008年4月29日 4:01
  •  無限極限 さんからの引用

    ちなみにプロキシが入るとまずいのでしょうか?

     

    いいえ。まずいことなどありません。

    ただいろいろ説明がめんどくさいだけです。

     

     西脇 さんからの引用

    TcpClientクラスを使った標準的なコーディングでは、送信が正常に終了された場合、それはあくまで.NET Framework内部で利用している Windows Sockets の send() が完了したことを意味し、相手に正常に届くまでは保証されません。

    つまり、TCPは伝達を保証しますが、TcpClientクラスは伝達を保証しません。

    正確な実装がどうなっているかは、マイクロソフトへ確認して下さい。

     

    ただの言葉の問題ですが。

    「伝達を保証する」というのは、「絶対に届く」という意味ではありません。

    「届いていない場合にそれがわかる」という意味です。

     

    突然LANケーブルは抜かれる、という状況でメッセージを絶対に送れるようにする技術は不可能ですから。

     

    そういう意味では、

    System.Net.TCPClientもSystem.Net.SocketもWinsockのSendも同様に「伝達を保証します」。

     

    ただ、その保証は遅延があります。

    効率を上げるために、ドライバや間のルーターなど、さまざまな層にバッファが存在しえます。

    そのため、sendは正常に完了したが、その後相手まで届かなかった、という場合ありえます。

    その場合、次の呼び出しの時にエラーがあがります。

     

    バッファや遅延の量は環境によって違いますので、それに依存したプログラムを組んではいけません。

     

    また、

     西脇 さんからの引用

    送信後に何らかの応答を相手が送信し、それを受信する処理を1セットとし、応答の受信タイムアウトを、アプリケーションプロトコルとしての失敗として処理するとよいと思います。

    という戦略は、「できる限り避けるべき」です。

    受信確認のためだけにメッセージを送るのは、トラフィックの無駄です。

    2008年4月29日 4:07
  • トラフィックの無駄ですか。

     

    ただ、

    ----------------------------------------------------------------------

    その場合、次の呼び出しの時にエラーがあがります。

    ----------------------------------------------------------------------

    とのことですから、エラーが出れば再接続は可能ですし、

    ちょっと安心しました。

    がんばってみます。ありがとうございます。

     

     

    2008年5月2日 9:44
  •  れい さんからの引用

    そのため、sendは正常に完了したが、その後相手まで届かなかった、という場合ありえます。

    その場合、次の呼び出しの時にエラーがあがります。

     

    バッファや遅延の量は環境によって違いますので、それに依存したプログラムを組んではいけません。

     

    ちなみにこのエラーは非同期の場合でも発生しますか?

    やはり、同期で積極的に受信していないと発生しないものなのでしょうか?

    2008年5月4日 19:10
  • ちなみにこのエラーは非同期の場合でも発生しますか?

    やはり、同期で積極的に受信していないと発生しないものなのでしょうか?

     

    同期・非同期によらず発生します。

    でないと伝達できたか知りようがないですから。

     

    また、厳密に言うと次のSend時に発生すると決まってるわけではありません。

    大抵は次のSend時になりますが。

     

    次の次のSendになる場合もありますし、

    ShutdownやReceiveのときにエラーになる場合もあります。

    2008年5月10日 1:53
  • れいさん。ありがとうございます。

    最初は、どうしようかと思いましたが

    エラーも普通に出てくれるようですし、安心しました。

    2008年5月10日 3:30
  • みなさんこんにちは、森田です。

     

    回答を寄せてくださったみなさん、有用な情報をありがとうございました!

     

    無限極限さん、フォーラムのご利用ありがとうございます!

    今回、回答を寄せてくださった皆さんの情報は、有用なものだと思われましたので、

    勝手ながら回答済みチェックをつけさせていただきました。

    無限極限さんは、チェックを解除することもできますので、

    ご確認ください。

     

    また、追加で質問などございましたら、是非投稿をお願いします!

     

     

    それでは、これからもMSDNフォーラムをよろしくお願いいたします。

     

    2008年5月20日 7:46
  • 回答済みにするのを忘れました。すいません。

    続きの質問がございます。よろしければまた相談にのっていただけると

    ありがたいです。

     

    TCP/IPで不通になるとUDPも不通になるのか?
    http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=3398610&SiteID=7

    2008年5月26日 4:14