- PR -

TCP通信受信時で新規ウインドウがフリーズする

1
投稿者投稿内容
やまと
会議室デビュー日: 2003/08/21
投稿数: 11
投稿日時: 2003-08-21 16:38
どうか皆様お教えください。

vb.netで、チャットクライアントのようなものを作っております。

メッセージを受け取ると、新しいウインドウを表示するような
仕組みを作りたいのですが、新しいウインドウを
表示すると、新ウインドウのみフリーズする現象が発生します。

どのようにすれば解決できるでしょうか?

以下のコードは、問題点をわかりやすくする為に実際のコードを
大幅に簡略化したコードです。

ServerForm は、Button1 を押すと接続待機し、クライアントから
"test"という文字列が送られると 新ウインドウを表示します。
ClientForm は、Button1 を押すとサーバに接続し、"test"という
文字列を送ります。

--[ServerForm]---------------
Imports System.Net
Imports System.Net.Sockets

Public Class ServerForm : Inherits System.Windows.Forms.Form

#Region " Windows フォーム デザイナで生成されたコード "
(中略)
#End Region

Private m_Listener As Socket
Private m_Worker As Socket
Private m_buffer(1023) As Byte
Private m_NewForm As NewForm

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim ipHostInfo As IPHostEntry = Dns.Resolve(Dns.GetHostName())
Dim ip As IPAddress = ipHostInfo.AddressList(0)
Dim localEndPoint As New IPEndPoint(ip, 11000)
m_Listener = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
m_Listener.Bind(localEndPoint)
m_Listener.Listen(100)
m_Listener.BeginAccept(New AsyncCallback(AddressOf AcceptCallback), Nothing)
End Sub

Public Sub AcceptCallback(ByVal ar As IAsyncResult)
m_Worker = m_Listener.EndAccept(ar)
m_Worker.BeginReceive(m_buffer, 0, 1024, 0, New AsyncCallback(AddressOf ReadCallback), Nothing)
End Sub

Public Sub ReadCallback(ByVal ar As IAsyncResult)
m_Worker.EndReceive(ar)
Dim receiveMessage As String = System.Text.UnicodeEncoding.Unicode.GetString(m_buffer)
If receiveMessage.IndexOf("test") > -1 Then
m_NewForm = New NewForm
m_NewForm.Show()
End If
End Sub
End Class
-----------------------------
--[ClientForm]---------------
Imports System.Net
Imports System.Net.Sockets

Public Class clientForm : Inherits System.Windows.Forms.Form

#Region " Windows フォーム デザイナで生成されたコード "
(中略)
#End Region

Private m_clientSocket As Socket

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim ip As IPAddress = IPAddress.Parse("(任意のIPアドレス)")
Dim remoteEP As New IPEndPoint(ip, 11000)
m_clientSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
m_clientSocket.BeginConnect(remoteEP, AddressOf ConnectCallback, Nothing)
End Sub

Private Sub SendCallback(ByVal ar As IAsyncResult)
m_clientSocket.EndSend(ar)
End Sub
End Class
-----------------------------

読みづらくて大変申し訳ありませんが、
ご存知の方いらっしゃいましたら、どうかお教えください。

やまと
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2003-08-21 17:47
こんにちは。

 フリーズとは、どのような状態ですか?ウインドウは表示されるけれども再描画されない?期待通りと違うことを「フリーズ」と表現している?この情報だと、コーディング通りの動作をしていると思うのですが??

 NewFormクラスのインスタンスを作って表示させていますが、NewFormクラスのデフォルトコンストラクタ、OnShowイベントハンドラでは何をしているのでしょうか?何もしていないのであれば、「表示されるだけ」で正しいと思います。また、「そこに受け取ったメッセージが表示されるはず」であれば、NewFormクラスのインスタンスに対して、使用するソケットの情報を一切合切引き渡してやらなければならないと思うのですが、その辺はコード化されているのでしょうか?

NewFormクラスのコードがないので、なぜNewFormのインスタンスが「フリーズ」してしまうのか、わかりません。
やまと
会議室デビュー日: 2003/08/21
投稿数: 11
投稿日時: 2003-08-21 18:07
Jitta様、ご返答頂き有難うございます。

ご指摘の通り、表現に不足がありましたので補足いたします。

フリーズとは、本件では、
新規ウインドウの上にカーソルを載せると
砂時計表示状態になり、ウインドウ自体の移動もできない
状態のことと致します。

また、NewForm クラスについては、VS.net にて、
「WindowsForm の追加」として、VS.netが自動生成した
コードにまったく手を加えていない状態です。

ですので、デフォルトコンストラクタはVS.net によって
自動生成されたコードのままで、かつ、
イベントハンドラの追加は致しておりません。

簡略的にコードを明記するため、NewForm クラスのコードを
省略したことを、ご説明し忘れておりました。

大変申し訳ありません、ご指摘感謝いたします。

やまと
やまと
会議室デビュー日: 2003/08/21
投稿数: 11
投稿日時: 2003-08-21 22:23
上記説明だと、わかりにくいかもしれませんので、
コードをダウンロードできるようにしてみました。

どうかご覧頂いて問題をご指摘頂ければと思います。

http://ycg.serveirc.com/code/tcpNewFormProblem.zip

clientForm に、serverForm を動作させるマシンのIPアドレスを
記入してからコンパイルしてください。

やまと
mei
大ベテラン
会議室デビュー日: 2003/04/08
投稿数: 114
投稿日時: 2003-08-21 23:33
こんばんは、meiです。

引用:

やまとさんの書き込み (2003-08-21 18:07) より:
フリーズとは、本件では、
新規ウインドウの上にカーソルを載せると
砂時計表示状態になり、ウインドウ自体の移動もできない
状態のことと致します。



コード:
m_NewForm.Show()


この直後に、Application.Run()を呼んでみて下さい。
NewFormに対するイベントを受け付けるようなりませんか?

m_NewForm.Show()を行っているスレッドで、
メッセージループが開始していない為だと思います。

ただ、そのままだとReadCallbackメソッドが止まってしまうので、
別の方法(もう一つスレッドを起こすとか)を取る必要がありそうですね。
やまと
会議室デビュー日: 2003/08/21
投稿数: 11
投稿日時: 2003-08-22 00:07
mei様、ご返答頂き有難うございました。

mei様のご指摘の通り、メッセージ受信のスレッドが
アプリケーションメッセージループを開始していない
ことが問題だったようです。

mei様のご指摘があるまで、スレッドというものを
深く考えずにコーディングしてしまっておりました。
また、アプリケーションメッセージループというものを
詳しく知らないでおりました。
お恥ずかしい限りです。

以下のようにコーディングしなおしましたところ
問題解決いたしました。

コード:
Public Class ServerForm : Inherits System.Windows.Forms.Form

(同一部分略)

    Public Sub ReadCallback(ByVal ar As IAsyncResult)
        m_Worker.EndReceive(ar)
        Dim receiveMessage As String = System.Text.UnicodeEncoding.Unicode.GetString(m_buffer)
        If receiveMessage.IndexOf("test") > -1 Then
            System.Threading.ThreadPool.QueueUserWorkItem(New Threading.WaitCallback(AddressOf ShowNewForm))
            Debug.WriteLine("ReadCallback は継続中")
        End If
        m_Worker.BeginReceive(m_buffer, 0, 1024, 0, New AsyncCallback(AddressOf ReadCallback), Nothing)
    End Sub

    Private Sub ShowNewForm(ByVal state As Object)
        m_NewForm = New NewForm
        m_NewForm.Show()
        Application.Run()
    End Sub
End Class



お教え頂きまして大変ありがとうございました。

やまと
1

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