- PR -

ソケット通信の問題

1
投稿者投稿内容
スパイク
常連さん
会議室デビュー日: 2002/07/05
投稿数: 24
投稿日時: 2002-11-08 22:34
CSocket(CSocketFile、CArchiveは使用セズ)を派生させたTCP/IPクライアント
プログラムを作りました。
サーバ側はWindowsでないOSです。
データはサーバ側から定期的に送られてきて、受け取った側は、
「受け取ったよ」というメッセージ(以下:ACK)をサーバに返し、
サーバはそれを受信後、次のメッセージを送信しています。
また、この受け取った、メッセージは、別のWindowsマシン(3台)に配信しています。
(配信方法は、サーバとのやりとりと同じ方法)
このやり取りをしていると、突然、サーバとのデータの送受信ができなくなります。
サーバ側が、ACKを受信していないのか、こちらでデータを受信しきれていないのかは、
不明ですが、サーバ側に原因がないことは確かです。(サーバは別のマシンにも同じよ
うなデータを送っていて、そのマシン上では問題が起きていないため)
この状態で、一定時間をおいて、ソケットの切断と接続を行うと、データが詰まって
いたかのように一気に流れてくるのです。

この現象は、マルチCPUまたは、ハイパースレッディング搭載のXeonのマシン上で
起きることがわかりました。(シングルCPUでは絶対起きない)

以下の修正と別マシンへの配信を止めたら正常に動作するようになったのですが、
根拠がわかりません。

現状のデータ受信方法:
・CSocket:nReceive()が呼ばれる。
・CSocket::Receive()関数で一部分を読み込む。
・その一部にデータ長が設定されているので、そのデータ長分
CSocket::Receive()関数で本文(残り全部)を読み込む。

変更後:
・CSocket:nReceive()が呼ばれる。
・CSocket::Receive()関数で一部分を読み込んだら、関数を終了する。
・CSocket:nReceive()が呼ばれる。
・CSocket::Receive()関数で本文(残り全部)を読み込む。

何か解決の糸口となるアドバイスや情報なりを頂けないでしょうか。
よろしくお願いします。

#訳あって、パケットキャプチャができない環境にあります。
H2
ぬし
会議室デビュー日: 2001/09/06
投稿数: 586
お住まい・勤務地: 港
投稿日時: 2002-11-09 07:25
> この状態で、一定時間をおいて、ソケットの切断と接続を行うと、
> データが詰まっていたかのように一気に流れてくるのです。

CSocketのことはよく分かりませんが、socketにwriteした内容がバッファで溜められているからではないでしょうか?実際に送り出すためにはflushをする必要があるのかもしれません。見当違いでしたらごめんなさい。

[ メッセージ編集済み 編集者: H2 編集日時 2002-11-09 07:28 ]
MyTime
ベテラン
会議室デビュー日: 2002/01/03
投稿数: 83
投稿日時: 2002-11-09 22:58
 UP環境で正常に動作し、SMP環境でデッドロックが起きているのならば、ブロッキングによってデッドロックが発生しているためだと思われます。
 SOCK_STREAM 型のソケットなら、受信サイズをMTUの数倍程度にした上で、別スレッドでIsBlockingを使ってタイムアウト処理を実装し、データ受信待ちの間にブロックされているたのメッセージを定期的に処理させる必要があるのではないでしょうか? 
 あまり大きなサイズのデータを一度に受け取ろうとはしない方が、良いですよ。例えば、Windows2000の場合、soketの送受信バッファのデフォルトは、64MB以上のメモリを搭載している環境では8KBとなっています。(ちなみにRedHat Linuxなんかだとデフォルトの最大値が10KBになっています。)
スパイク
常連さん
会議室デビュー日: 2002/07/05
投稿数: 24
投稿日時: 2002-11-10 00:29
スパイクです。

このUP環境で起きなくて、SMP環境で起きるというのは、
SMPの環境で、どういうことが起きて「ブロッキングにてデットロック状態」
という状態に陥るのか、教えて頂けないでしょうか?(どこどこを読め、
というポインタでも構いません)

そもそも、UP(Uni-Processor)とかSMP(Symmetric Multiprocessing)の
アーキテクチャがよくわかっていません。

この意味が理解できれば、納得した上でプログラムの対応ができると思います。
よろしくお願いします。
MyTime
ベテラン
会議室デビュー日: 2002/01/03
投稿数: 83
投稿日時: 2002-11-10 13:33
 ブロッキングを行う同期ソケットのCSocketクラスは、もともとブロッキングを行わない非同期ソケットのCAsyncSocketクラスの派生クラスとして実装されていることに注目する必要があります。もともと非同期でI/Oを行っているシステムに対して排他制御を使用することにより、同期ソケットをエミュレートしています。
 どうやら、この排他制御に関する動作がUPの場合とSMPの場合で異なるようなのです。複数パケットにまたがるようなサイズを受信サイズに指定した場合に、CAsyncSocketクラスでブロッキングせずに通信している場合には、正常に動作しているのに、SMP環境でCSocketクラスで同期通信をしていて、システムが受信したパケット列の中に他のソケット宛のパケットが紛れ込んでいた場合に、ロックが発生するケースがありました。MTUのサイズを指定してデータを受信すれば、スループットは悪くなるものの、デッドロックは起きませんでした。疑問に思いネットワーク上に流れるデータをスニファリングしたところ、このことが分かりました。
 実際のところ、どうなっているのかは、CSocketクラスのソースでも解析してみなければ分かりませんが、何のためにIsBlockingなんて単一スレッドでは何の利点もないものが実装されているのかを考えてみれば、この現象はCSocketクラスの仕様であると結論付けせざるを得ませんでした。
 
MyTime
ベテラン
会議室デビュー日: 2002/01/03
投稿数: 83
投稿日時: 2002-11-10 13:59
追伸:
 UP環境で排他処理を行う場合には、単一プロセッサ上で動作しているスレッドおよびプロセス間の排他処理だけを考えればよいのですが、SMP環境では、複数のプロセッサ上で動作しているスレッドおよびプロセス間の排他処理を考えなくてはなりません。SMP環境では、論理的に複数のスレッドおよびプロセスが同時に動作しているだけでなく、物理的にもプロセッサ数分のスレッドおよびプロセスが同時に動作しています。排他処理の挙動が異なるのは当然です。

 余談になりますが、一部のビデオカードやDVD-RAMなどのドライバが、SMP環境について非対応としているのは、このあたりに原因があるのかもしれません。新世代のPentium4によりハイパースレッディングによるSMPが一般化すると、ドライバの都合でハイパースレッディングを有効にできないケースや、SMP環境特有のトラブルが多発するのではないかと、危惧しています。
スパイク
常連さん
会議室デビュー日: 2002/07/05
投稿数: 24
投稿日時: 2002-11-11 22:42
「MyTime」さん、「H2」さんご意見ありがとうございました。
現在の状況が理解できました。
対応策としては、非ブロックキングでデータを受信するワーカスレッドを
作成することで、対処するようにしてみます。
大変ためになりました。
ありがとうございました。

1

スキルアップ/キャリアアップ(JOB@IT)