こんにちわ、ケンズです。
Win2k、VB6.0、mswinsck.ocxでのTCPファイル転送をしようとしています。
過去のログを読みながら送信と受信を作ってみたのですが、うまくいきません。
ソースはこんな感じです。
-------------------------受信-------------------------
'データの受信
ReDim RD(bytesTotal)
Winsock(Index).GetData RD(), vbArray + vbByte, bytesTotal
'受信データの保存
Dim FileNum As Integer
FileNum = FreeFile()
Open Filename For Binary As FileNum
Put #FileNum, LOF(FileNum) + 1, RD()
Close FileNum
DoEvents
-------------------------送信-------------------------
Dim SD() As Byte
Dim FileNum As Integer
'FileNum取得
FileNum = FreeFile()
Open FileName For Binary As FileNum
ReDim SD(0 To LOF(FileNum) - 1)
Get FileNum, , SD()
Close FileNum
Winsock1.SendData SD()
------------------------------------------------------
以上です。
このソースで数メガまでは受信ができますが、数十メガになると
受信側のCPU利用率が100%になりVBが落ちてしまいます。
修正版をつくり、1Mごとに同期を取り数十メガの受信に成功しましたが。
CPU利用率が100%→0%→100%→0%となりました。
どちらの使用も、受信側が8kずつ受信(DataArrival発生)しているようです。
※悩んでいることですが、この仕様ですと受信に
ものすごい時間がかかり、CPUにも負荷がかかります。
これはVBの限界なのでしょうか?
何かほかの物でファイルの転送をする方法はありますか?
DoEventsがあるので
受信処理が終わる前に
また受信処理が始まって
またそこで受信処理が始まって・・
の繰り返しで暴走してると思います。
>過去のログを読みながら送信と受信を作ってみたのですが、うまくいきません。
過去ログにそんな邪悪なプログラムがあったとは。。
もしそうじゃなかったら過去ログにあやまりなさいね。
そもそも今更ファイル転送のプロトコルを自作する意味が理解しかねます。
Windowsのファイル共有機能では駄目なんですか?
Webかftpのサーバを立てるのでは駄目なんですか?
>そもそも今更ファイル転送のプロトコルを自作する意味が理解しかねます。
既存のプロトコルではセキュリティに問題があるということで
自作することはよくあることですね。
>Windowsのファイル共有機能では駄目なんですか?
>Webあるかftpのサーバを立てるのでは駄目なんですか?
しかしここの人ってシステム提案したがる人多いですね。
しかも、そういう人に限って少しでもVBと外れてると
「すれ違いです。」「マルチポスト。」とかいうし。。
あんさんのおっしゃる通りおそらく最後のDoEventsでDataArrivalイベント
プロシージャの中でDataArrivalイベントが発生しスタックが不足してきて
いるんじゃないかと思われます。
送信側ですが数十MBもあるようなデータを一気に送ってしまうのは少々
問題あるんじゃないでしょうか。
もう少し小さいフレームにして受信側で誤り訂正が利くようなプロトコル
にしてみてはどうでしょうか。
話はそれますが
>VBと外れてると「マルチポスト。」とかいう
人は見たことないなぁ
なんか頭ごなしに否定しただけみたいになってしまったのでもう少しちゃんとフォローしておきます。
・DataArrivalイベントの発生回数は予測不能である点に注意
TCPはその性質上パケットのサイズに上限があります。
上限を超える大きさのデータの送信では、自動的に複数のパケットに
分割して送信されます。
したがって、送信側では一度に送ったつもりでも、受信側では
DataArrivalイベントが複数回発生することを前提にしなければなりません。
そういう観点で例示されたコードを確認すると、DataArrivalイベントが
複数回発生すると、毎回同じファイルを上書きしているので最後に受信
したパケットの分しかファイルに残らない様に見えますし、030さんの指摘
のとおりDoEventsがスタックオーバーの要因になる可能性も考えられます。
・事前にデータサイズを通知する
ファイルのサイズを通信手順の最初の方で受信側に教えてあげてからデータ送信を開始することで、受信側の準備がより的確に行うことができるようになるかもしれません。
たとえば、IEでファイルをダウンロードする場合に受信が何%進んだか表示できるのも、サーバからあらかじめファイルサイズを教えてもらっていることにより可能になっています。
# こういう既存の実装が既にOSの一部として組み込まれているような物は
# 業務でやるなら「特別な要求事項がない限り時間の無駄」ですから
# 先の「意味が理解できない」ということになります。
# プログラミングやネットワークアプリケーション開発の勉強という意味で
# 取り組んでいるなら、自力で実現することでいろいろノウハウも得られる
# ので、実用的な価値は別にしてでも努力する意味もありますが。
>しかも、そういう人に限って少しでもVBと外れてると
>「すれ違いです。」「マルチポスト。」とかいうし。。
そんな人はいない。
VBの話でなければ当然「板違い」だし、マルチポストは全然意味が違う。
ちなみにスレ違いとは、このスレッドでなされている話の内容と関係ない事を指す。
勉強が必要ですね。
>これはVBの限界なのでしょうか?
>何かほかの物でファイルの転送をする方法はありますか?
私だったらUSBメモリーを使うな、ばかでかファイルをネットワークに
流すと他人が迷惑する。
クライアントとサーバーが離れていたら、FTPを使うくらいしか思いつかない、
間違ってもこの様な通信の仕方はしないのでは。
>そういう観点で例示されたコードを確認すると、DataArrivalイベントが
>複数回発生すると、毎回同じファイルを上書きしているので最後に受信
>したパケットの分しかファイルに残らない様に見えますし、
これは無いんじゃないかしら、その為にスタックに積んでるのだから。
ただしスタックオーバーフローはどうしても出ますね。
WindSockの通信で送信ファイルが長くなるとエラーが発生すると言う話は
余り聞きません、単にDoEventsを取ればいいだけのような。
ただしどんな方法でファイルの受送信をしたとしても、ネットワークに
激しくアクセスするので、CPUの負荷が重くなるのは避けられないと思われる。
試しに上記のコードからDoEventsを除いて100Mのファイルを受送信してみましたが
特に異状は有りませんでした。
解決遅れましてごめんなさい。
皆さんお返事ありがとうございます。
昔作ったチャットのDoEventsをそのまま書いてしまったため
良くなかったようです。
やはり8kずつの受信がボトルネックになっているようです。
過去のログは少し参考にさせていただいただけです。
まるまるのコピーではございません。
FTPの意見が多いようですが、FTPデーモンをどこかから
探してくるという意味でしょうか?
Windowsの環境で安定したFTPDをあまり見かけないので
FTPDは避けたいと思います。
ファイル共有機能もPCが多い環境でバグがあったり、セキュリティの面から
避けたいと考えております。
規模はLANでスイッチングハブ接続でのファイル送信です。
必要以上のデータをネットワークに流す気はありません。
一定容量ごとに同期させるものも作りましたが、スピードは同じでした。
やはりocxでのプログラミングではこの速度が限界ですか?
>この速度が限界ですか?
どの速度か分かりませんが、受信側でデータを受信したときに
1回ずつファイルを開いてSeekして書き込んでCloseという動作
で遅くなっている可能性があります。
最初にオープンしたら最後まで開きっぱなしで、最後でCloseという
処理にした方が速くなると思いますよ(特に大容量の場合)
そのためには最初にデータの全バイト数を相手に伝えるような工夫を
しないといけませんが。
HTTPプロトコルなどは、
途中から受信するなどすることがよくありますよね。
送信側も分割して送信してみたらどうですか?
両方とも書き換えが必要で面倒ですけど。
こんなサンプル役に立ちませんか?
またまた お返事ありがとうございます。
030さんのいうとおりファイルの書き込みのところがボトルネックに
なっていたようです。
ヤマ@文系さんの紹介していただいたソースを参考にcollectionを使い
編集してみました。まだソースを全部読みきれてないですが、
勉強させていただきます。
あらためて、ありがとうございました。
ツイート | ![]() |