- ベストアンサー
ソケットを使った「非同期」通信について
はじめまして。VB.NETで質問があります。内容は、(スレッドと)ソケットを使った「非同期」通信についてです。 マイクロソフトのページからサンプルコードをコピーして、二行のプロジェクトを作成し以下の二つのコードを追加したんですけど…(ipの指定は、GetHostNameを使っています。) プロジェクト1:非同期クライアント ソケットの例 Button1_Click AsynchronousClient.Main() プロジェクト2:非同期サーバー ソケットの例 Button1_Click AsynchronousSocketListener.Main() マイクロソフトのページ(ソケットのコード例) → http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/cpguide/html/cpconsocketcodeexamples.asp プロジェクト2のフォームが固まってしまいます。 (Waiting for a connection...を出力ウィンドウに表示したままになってしまいます。) 暫定策として、Shellを使って、サーバー(プロジェクト2のexe)を起動してみたのでが、それでも固まってしまいました。 3日間ぐらいかけてネットで検索とMSDN見たけど、分かりませんでした。キーワードは、以下の通り… 「マイクロソフト .NET スレッド フリーズ サンプルコード 非同期 マルチ select -sql」 Select フックなどの言葉も関係があるようなのですがよく分かりません。 ただ、フォーム上のボタンが押せるようになれば、解決です。 なにかキーワードだけでも、教えてください。お願いします。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
> ■まず、クラスファイルは追加できたのですがprjServerの起動クラスの項目(clsPrj2)にどうやって追加するのか分かりませんでした。 起動クラスではなく、メインモジュール(Sub Main())でした。誤った情報を教えてしまってすいません。 > ■また、クラスファイルから(またはメインモジュールから)フォームをShowするやり方が分かりませんでした。(frmServer.show()ができませんでした。) オブジェクト指向の概念を結構無視した作り方ですが、よければ参考にしてください。このやり方で「なんちゃってマルチスレッド」となるはずです。 ※ちょいと寝ぼけ眼で書いてますんで、多少の間違いは勘弁してください。方向性は大丈夫だと思いますんで・・・。 (1)非同期サーバ起動フラグ格納クラス(仮にclsBoolとします)を作成し、publicメンバ変数(仮にboolean型のbFlag)を用意します(初期値:false)。 (2)frmServerクラスに、clsBool型のpublicメンバ変数(仮にcFlag)を追加します。 (3)Main()関数およびfrmServer.btnServer_Click()での処理を以下のようにします。 ===== メインモジュール内 ===== Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Sub Main() Dim cBool As clsBool Dim frmS As frmServer Set frmS = New frmServer Set cBool = New clsBool Load frmS set frmS.cFlag = cBool frmS.Show Do While 1 If cBool.bFlag = true Then exit Do Else DoEvents Sleep 1000 End If Loop AsynchronousClient.Main '非同期サーバ起動 frmS.Hide Unload frmS Set frmS = Nothing Set cBool = Nothing End Sub ======= frmServerクラス内 ======= private sub btnServer_Click() cFlag.bflag = true end sub > ■文字だけの送受信なら、tcpClientクラスやtcpListnerクラスを使って簡単にできると思うのですが、ファイルの転送もできるのでしょうか?(その際、BinaryWriterとBinaryReaderを使えばいいのでしょうか?)しかし、スレッドを使わないとファイルを送受信している間は、他に何もできないのかも?? VBでファイル転送は経験ありませんが、個人的にはftpを使ったほうがいいような気もします。 明確な回答でなくてごめんなさい。
その他の回答 (3)
- 1050 円(@1050YEN)
- ベストアンサー率69% (477/687)
>文字だけの送受信なら、tcpClientクラスやtcpListnerクラスを使って簡単にできると思うのですが、ファイルの転送もできるのでしょうか? についてですが、 TcpClientクラス http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/cpref/html/frlrfSystemNetSocketsTcpClientClassTopic.asp に >データを送受信するには、 GetStream メソッドを使用して とあります 使ったことがないからよくわかっておりませんが、VB6でのWinSockコントロールのメソッドと類似しているので、MSDNを見る限りでは可能と思いますよ。
お礼
NetworkStreamも使うみたいですね。 ただ、私はVB6でWinsockコントロールを使った事があるんですが、[winsockのオブジェクト名].SendData (C:\Temp\Test.txt)みたいに書きたいのに書けない~って困った覚えがあります(汗) そんなに簡単にコーディングできませんね(笑) レスありがとうございます。
補足
実は、VB6のWinSockコントロールで、ファイル転送はできなかったですが、もっと勉強してがんばってみようと思いました。 まずは、VB6で修行(?)をつんで、VB.NETへ行きます(笑) では、ありがとうございました。 (補足の欄にお礼を書いてしまって申し訳ありません)
- Musaffah
- ベストアンサー率36% (37/101)
補足説明ありがとうございます。 もしかしたら、frmServer.BtnServer_click()内でAsynchronousSocketListener.Main()をコールしていることに問題があるのではないでしょうか? .NETに詳しくないので具体的なお答えができませんが、StartListening()内で無限ループ(待ち状態)に入っているため、BtnServer_click()メソッドが終了できずに固まっているように思います。 恐らくプロジェクト2のスタートアップ(起動クラス)をfrmServerにしているのだと思いますので、こうされてみてはどうでしょう? (1)起動クラス(仮にclsPrj2とします)を新規作成。そのクラスではfrmServerフォームを表示後、無限ループ(非同期サーバ起動待ち)に入る。非同期サーバ起動条件は、非同期サーバ起動フラグ(仮にisStartとします)がtrueのときのみとします。(このフラグの初期状態はfalse。falseの時はしばらくSleepして再度isStartフラグをチェックする。) (2)frmServer.BtnServer_Click()メソッドで、非同期サーバ起動開始メンバ関数(仮にclsPrj2.start()とします)をコール。この関数ではisStartをtrueにセットするのみとします。(この関数でAsynchronousSocketListener.Main()をコールするとやはりフォームが固まるように見えてしまいます。) (3)(1)の無限ループで、isStartがtrueになるので、AsynchronousSocketListener.Main()がコールされる。 これで、ボタンが固まるということはなくなると思います。あまり自身がありませんが、これで試してみてください。もし勘違いしてたらごめんなさい。
補足
ヒントありがとうございます。 イメージは掴めたんですがコーディングが・・・。ごめんなさい。 ■まず、クラスファイルは追加できたのですがprjServerの起動クラスの項目(clsPrj2)にどうやって追加するのか分かりませんでした。 ですが、すでに選択できるクラスが AsynchronousSocketListener, frmServer, sub main となっていたので、AsynchronousSocketListenerとしてみました所、フォームが固まるという問題は解決しました。そもそもfrmServerを表示しないという奇策ですが・・・。 「btnServer_click()メソッドが終了できず」という表現がすごく参考になりました。 "<QUIT>"という文字が送られてきた時はサーバを終了するようにして、待ち状態の解除をするようにしました。 ■また、クラスファイルから(またはメインモジュールから)フォームをShowするやり方が分かりませんでした。(frmServer.show()ができませんでした。) Dim frmServer1 As New prjServer.frmServer frmServer1.show() と書いたのですが、frmServer1の「宣言が必要です」とでまして、ビルドエラーになってしまいます。 ■なんか私がやっている事は、マルチスレッドのメリットを相殺している様な気がしてきました。 やっぱりスレッドを使わないでやるしかないのかな、私には。 Public Sub New() End Sub 'New がヒントなんでしょうかね?(汗)(オーバーロード??) ■文字だけの送受信なら、tcpClientクラスやtcpListnerクラスを使って簡単にできると思うのですが、ファイルの転送もできるのでしょうか?(その際、BinaryWriterとBinaryReaderを使えばいいのでしょうか?)しかし、スレッドを使わないとファイルを送受信している間は、他に何もできないのかも?? どなたかご存知の方があれば、ご教授ください。 的外れなことをしていたらごめんなさい>Musaffahさん もうちょっと、がんばってみます。
- Musaffah
- ベストアンサー率36% (37/101)
VB.NETはよくわからないので、何もお手伝いできないかと思いますが、その前に状況をもう少し確認させてください。 (1)「プロジェクト2のButton1をクリックしたら固まる」という解釈でいいですか? (2)その時、プロジェクト1は起動している状態ですか?また、プロジェクト2.Button1をクリックした後にプロジェクト1.Button1をクリックしてその状態になるの(要はソケット通信処理が終了しているのに・・・何故?)ですか? (3)フォーム上にはButton1以外にもボタンがあるのですか?
お礼
問題点の整理をして頂いてどうもありがとうございました。
補足
すみません、補足します。 (1)はい、そうです。 (2)プロジェクト2.Button1(サーバ)を押すとListen状態になり、プロジェクト1.Button1(クライアント)を押す度に、データが送受信され、サーバー側の出力ウィンドウに以下の様に表示されます。 Read 19 bytes from socket. Data : This is a test<EOF> Sent 19 bytes to client. プロジェクト2.Button1(サーバ)を押した時点で、フォームが固まります。 ただし・・・ サーバプロジェクトは、(出力ウィンドウを見る必要がある為)VB.NET で実行しています。 クライアントは、ビルド済みの exe 本体から、起動してます。 (3)ないです。 サンプルコードをコピーして、フォームにあるボタンを押すと、非同期クライアントのmainと非同期サーバー ソケットのmainをCallするようになってます。 サンプルコードをそのまま使えるのなら、プログラマーは要らないわけで、大変皆様に失礼な質問なのですが、先に進む見込みがなくなってしまったので、ここで質問致しました。ヒントを下されば幸いです。 分かりにくいので、frmServer, btnServer, frmClient, btnClientと名前をつけます。
お礼
レス遅れました。 眠いのに一所懸命アドバイスしてくれて、ありがとうございます。 publicメンバ変数というのが、分かりませんでした。メインモジュール内で、 Public Class clsBool Dim bFlag As Boolean = False End Class と書いたのですが、上手くいきませんでした。 クラスファイルを追加してもダメでした。 後は助言して頂いた方法でも、引き続き frmServer.show() ができませんでした。 これ(↓)関係ありそうですが・・・。 http://park16.wakwak.com/~mimi/dotnet/misc/worker_thread.html もうちょっと自分で試行錯誤してみます。 またお世話になるかもしれませんが、その時は宜しくお願いします。
補足
レス遅れました。 マルチタスクにするためには、監視するスレッドが必要なのですね υ VB.NETは、買ったばかりなので、なかなか難しいです。 大変遅くなってしまいましたが、だいぶ、考え方は理解できたので、締め切ろうと思います。 ご協力ありがとうございました。 (お礼と補足が逆になった事、締め切るまでに時間がかかった事をお詫びします。) また、機会があれば教えてください。 私は、勿論、力不足ですが、できる範囲でお返しもしたいです。