none
如何判斷非同步通訊沒收到資料? RRS feed

  • 問題

  • 各位大大好:
    小弟目前在寫非同步網路通訊的程式,並參考msdn的範例
    先說明一下做這支程式的目的,如下:
    連線至遠端的設備並開始非同步的接收設備吐出來的資料,收到資料後Invoke把他顯示在Textbox

    透過此範例修改後是可以達到我要的功能,但是有個需求就是當沒收到資料後,必須要把Textbox上的字清空
    理論上在ReceiveCallback內寫判斷式就可以處理,但經測試發現當沒資料進來時,程式跟本不會跑進去ReceiveCallback,程式就停在哪邊不動等待資料,一直要到有資料才會再進入ReceiveCallback
    我希望能夠利用一個timeout的機制,當發現沒資料進來五秒後表示真的沒資料了,此時,就把Textbox的字清空
    但是查了很多資料和文章,好像並沒直接提供這樣的方式,所以在這邊想請教各位大大
    關於遇到這種問題要如何處理或是有什麼好方法呢?謝謝!!!

    這邊補上MSDN的範例:

    Imports System
    Imports System.Net
    Imports System.Net.Sockets
    Imports System.Threading
    Imports System.Text
    
    
    ' State object for receiving data from remote device.
    
    Public Class StateObject
        ' Client socket.
        Public workSocket As Socket = Nothing
        ' Size of receive buffer.
        Public Const BufferSize As Integer = 256
        ' Receive buffer.
        Public buffer(BufferSize) As Byte
        ' Received data string.
        Public sb As New StringBuilder
    End Class 'StateObject
    
    
    Public Class AsynchronousClient
        ' The port number for the remote device.
        Private Const port As Integer = 11000
    
        ' ManualResetEvent instances signal completion.
        Private Shared connectDone As New ManualResetEvent(False)
        Private Shared sendDone As New ManualResetEvent(False)
        Private Shared receiveDone As New ManualResetEvent(False)
    
        ' The response from the remote device.
        Private Shared response As String = String.Empty
    
    
        Public Shared Sub Main()
            ' Establish the remote endpoint for the socket.
            ' For this example use local machine.
            Dim ipHostInfo As IPHostEntry = Dns.Resolve(Dns.GetHostName())
            Dim ipAddress As IPAddress = ipHostInfo.AddressList(0)
            Dim remoteEP As New IPEndPoint(ipAddress, port)
    
            ' Create a TCP/IP socket.
            Dim client As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
    
            ' Connect to the remote endpoint.
            client.BeginConnect(remoteEP, New AsyncCallback(AddressOf ConnectCallback), client)
    
            ' Wait for connect.
            connectDone.WaitOne()
    
            ' Send test data to the remote device.
            Send(client, "This is a test<EOF>")
            sendDone.WaitOne()
    
            ' Receive the response from the remote device.
            Receive(client)
            receiveDone.WaitOne()
    
            ' Write the response to the console.
            Console.WriteLine("Response received : {0}", response)
    
            ' Release the socket.
            client.Shutdown(SocketShutdown.Both)
            client.Close()
        End Sub 'Main
    
    
        Private Shared Sub ConnectCallback(ByVal ar As IAsyncResult)
            ' Retrieve the socket from the state object.
            Dim client As Socket = CType(ar.AsyncState, Socket)
    
            ' Complete the connection.
            client.EndConnect(ar)
    
            Console.WriteLine("Socket connected to {0}", client.RemoteEndPoint.ToString())
    
            ' Signal that the connection has been made.
            connectDone.Set()
        End Sub 'ConnectCallback
    
    
        Private Shared Sub Receive(ByVal client As Socket)
    
            ' Create the state object.
            Dim state As New StateObject
            state.workSocket = client
    
            ' Begin receiving the data from the remote device.
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, New AsyncCallback(AddressOf ReceiveCallback), state)
        End Sub 'Receive
    
    
        Private Shared Sub ReceiveCallback(ByVal ar As IAsyncResult)
    
            ' Retrieve the state object and the client socket 
            ' from the asynchronous state object.
            Dim state As StateObject = CType(ar.AsyncState, StateObject)
            Dim client As Socket = state.workSocket
    
            ' Read data from the remote device.
            Dim bytesRead As Integer = client.EndReceive(ar)
    
            If bytesRead > 0 Then
                ' There might be more data, so store the data received so far.
                state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead))
    
                ' Get the rest of the data.
                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, New AsyncCallback(AddressOf ReceiveCallback), state)
            Else
                ' All the data has arrived; put it in response.
                If state.sb.Length > 1 Then
                    response = state.sb.ToString()
                End If
                ' Signal that all bytes have been received.
                receiveDone.Set()
            End If
        End Sub 'ReceiveCallback
    
    
        Private Shared Sub Send(ByVal client As Socket, ByVal data As String)
            ' Convert the string data to byte data using ASCII encoding.
            Dim byteData As Byte() = Encoding.ASCII.GetBytes(data)
    
            ' Begin sending the data to the remote device.
            client.BeginSend(byteData, 0, byteData.Length, 0, New AsyncCallback(AddressOf SendCallback), client)
        End Sub 'Send
    
    
        Private Shared Sub SendCallback(ByVal ar As IAsyncResult)
            ' Retrieve the socket from the state object.
            Dim client As Socket = CType(ar.AsyncState, Socket)
    
            ' Complete sending the data to the remote device.
            Dim bytesSent As Integer = client.EndSend(ar)
            Console.WriteLine("Sent {0} bytes to server.", bytesSent)
    
            ' Signal that all bytes have been sent.
            sendDone.Set()
        End Sub 'SendCallback
    End Class 'AsynchronousClient
    2009年12月8日 上午 07:30

解答

  • ...
    用一個公用變數在 ReceiveCallback 記錄最後更新時間
    開一個 Timer ,當目前時間 - 最後更新時間 > 目標秒數,清空 TextBox
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    • 已標示為解答 Lolota Lee 2009年12月11日 上午 05:43
    • 已取消標示為解答 Hsing 2009年12月18日 上午 03:56
    • 已標示為解答 Hsing 2009年12月18日 上午 03:56
    2009年12月8日 上午 07:37

所有回覆

  • ...
    用一個公用變數在 ReceiveCallback 記錄最後更新時間
    開一個 Timer ,當目前時間 - 最後更新時間 > 目標秒數,清空 TextBox
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    • 已標示為解答 Lolota Lee 2009年12月11日 上午 05:43
    • 已取消標示為解答 Hsing 2009年12月18日 上午 03:56
    • 已標示為解答 Hsing 2009年12月18日 上午 03:56
    2009年12月8日 上午 07:37
  • 謝謝~新冷熱情熄

    經你的指點問題是可以解決,只是好奇為何沒資料時他就不會進入ReceiveCallback
    但是看MSDN範例卻有再裡面做判斷有無資料,是為何???

    另外,想請教另一個問題,若現再我想在連接另一台一模一樣的設備,一樣採用此非同步網路通訊來做
    只是收到的資料是要做不一樣的事,是不是我要再新增另一個Thread來處理,可以非同步通訊這部分寫成方法
    新增的Thread只要把連線IP和port等一些參數丟入既可,不知這樣的想法是否正確??謝謝喔~

    2009年12月8日 上午 08:38
  • ... 看函數名就知道吧?
    收到資料才回呼,所以沒收到資料當然不會回呼。

    如果是寫 Server 端,本來就這樣寫,寫 Client 端當然也可以這樣寫。
    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    2009年12月8日 上午 10:51
  • 謝謝心冷熱情熄大大的指導

    感謝你喔!!!

    2009年12月9日 上午 03:01