TCP/ip 接收连接但在尝试读取数据时锁定 [英] TCP/ip recive connection but locks up when trying to read data

查看:33
本文介绍了TCP/ip 接收连接但在尝试读取数据时锁定的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请谁能告诉我为什么当我的 rclient 连接并尝试发送数据时我的服务器会锁定?

如果我注释掉:

Dim bytes(rclient.ReceiveBufferSize) As Byterstream.Read(bytes, 0, CInt(rclient.ReceiveBufferSize))RString = Encoding.ASCII.GetString(bytes)TextBox2.Text = RStringcode 在这里

然后就是

TextBox2.Text = ("远程连接")

服务器在连接的客户端上接收,所以它一定是我用 .read 做的吗?

导入 System.Net.Sockets导入 System.Text导入 System.Threading导入 System.IO.PortsDim tclient 作为新的 TcpClientDim tstream 作为网络流Dim rclient 作为新的 TcpClientDim rstream 作为网络流Dim sArray() 作为字符串Dim Tricopter As New TcpListener(2000)Dim Remote As New TcpListener(2001)将 myVal 调暗为字符串Dim TricopterThread 作为新线程(AddressOf TricopterThreadSub)Dim RemoteThread 作为新线程(AddressOf RemoteThreadSub)Dim tre(tclient.ReceiveBufferSize) As Byte昏暗的 TState = 假Dim RState = FalseDim SerialSwitch = False昏暗切换 = 错误Dim TString 作为字符串Dim RString 作为字符串Dim Remo(rclient.ReceiveBufferSize) 作为字节Dim TSendText() 作为字节私有子 RemoteThreadSub()rclient = Remote.AcceptTcpClientrstream = rclient.GetStreamRState = 真结束子私有子 TricopterThreadSub()tclient = Tricopter.AcceptTcpClienttstream = tclient.GetStreamTState = 真结束子Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) 处理我.FormClosing结束子Private Sub Form1_Load(sender As Object, e As EventArgs) 处理 MyBase.LoadCheckForIllegalCrossThreadCalls = FalseTricopter.Start()远程启动()Timer1.Start()TricopterThread.Start()远程线程.Start()结束子Private Sub Timer1_Tick(sender As Object, e As EventArgs) 处理 Timer1.TickmyVal = ">"&TrackBar1.Value &"," &TrackBar2.Value &"," &TrackBar3.Value &"," &TrackBar4.Value &"/n"尝试如果 TState = False 那么TextBox1.Text = ("未连接三轴飞行器")别的TextBox1.Text = myVal如果 Toggle = False 那么TSendText = Encoding.ASCII.GetBytes(myVal)万一如果 Toggle = True 那么TSendText = Encoding.ASCII.GetBytes(RString)万一tstream.Write(TSendText, 0, TSendText.Length)万一如果 RState = False 那么TextBox2.Text = ("无远程连接")别的' TextBox2.Text = ("远程连接")Dim 字节(rclient.ReceiveBufferSize)作为字节rstream.Read(bytes, 0, CInt(rclient.ReceiveBufferSize))RString = Encoding.ASCII.GetString(bytes)TextBox2.Text = RString万一Catch ex 作为例外结束尝试结束子Private Sub Button2_Click(sender As Object, e As EventArgs) 处理Button2.Click如果 Toggle = False 那么CheckBox1.CheckState = 1切换 = 真别的CheckBox1.CheckState = 0切换 = 错误万一结束子

结束课程

解决方案

对于那些已经下载/测试过这个的人,我对这些类做了一个错误修正,所以你需要重新下载源代码如果您打算再次使用它们.

如果您想执行正确的数据传输,您需要使用更可靠的方法,而不仅仅是读取随机数据.正如 usr 指出的那样:TcpClient.ReceiveBufferSize 属性不会告诉你有多少数据要接收,也没有多少数据寄给你.ReceiveBufferSize 只是一个变量,指示每次读取传入数据时预期获得多少字节.阅读

Please can someone tell me why my server locks up when my rclient connects and try to send data?

If I comment out:

Dim bytes(rclient.ReceiveBufferSize) As Byte
            rstream.Read(bytes, 0, CInt(rclient.ReceiveBufferSize))
            RString = Encoding.ASCII.GetString(bytes)
            TextBox2.Text = RStringcode here

and just have

TextBox2.Text = ("Remote connected")

the server picks up on a connected client so it must be something i have done with the .read ?

Imports System.Net.Sockets
Imports System.Text
Imports System.Threading
Imports System.IO.Ports

Dim tclient As New TcpClient
Dim tstream As NetworkStream
Dim rclient As New TcpClient
Dim rstream As NetworkStream
Dim sArray() As String
Dim Tricopter As New TcpListener(2000)
Dim Remote As New TcpListener(2001)
Dim myVal As String
Dim TricopterThread As New Thread(AddressOf TricopterThreadSub)
Dim RemoteThread As New Thread(AddressOf RemoteThreadSub)
Dim tre(tclient.ReceiveBufferSize) As Byte
Dim TState = False
Dim RState = False
Dim SerialSwitch = False
Dim Toggle = False
Dim TString As String
Dim RString As String
Dim Remo(rclient.ReceiveBufferSize) As Byte
Dim TSendText() As Byte


Private Sub RemoteThreadSub()
    rclient = Remote.AcceptTcpClient
    rstream = rclient.GetStream
    RState = True
End Sub

Private Sub TricopterThreadSub()
    tclient = Tricopter.AcceptTcpClient
    tstream = tclient.GetStream
    TState = True
End Sub

Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
End Sub

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    CheckForIllegalCrossThreadCalls = False
    Tricopter.Start()
    Remote.Start()
    Timer1.Start()
    TricopterThread.Start()
    RemoteThread.Start()
End Sub

Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick

    myVal = ">" & TrackBar1.Value & "," & TrackBar2.Value & "," & TrackBar3.Value & "," & TrackBar4.Value & "/n"

    Try

        If TState = False Then

            TextBox1.Text = ("No tricopter connected")

        Else

            TextBox1.Text = myVal

            If Toggle = False Then
                TSendText = Encoding.ASCII.GetBytes(myVal)
            End If


            If Toggle = True Then
                TSendText = Encoding.ASCII.GetBytes(RString)
            End If
            tstream.Write(TSendText, 0, TSendText.Length)
        End If




        If RState = False Then

            TextBox2.Text = ("No Remote connected")

        Else
            ' TextBox2.Text = ("Remote connected")
            Dim bytes(rclient.ReceiveBufferSize) As Byte
            rstream.Read(bytes, 0, CInt(rclient.ReceiveBufferSize))
            RString = Encoding.ASCII.GetString(bytes)
            TextBox2.Text = RString

        End If

    Catch ex As Exception

    End Try

End Sub


Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    If Toggle = False Then
        CheckBox1.CheckState = 1
        Toggle = True
    Else
        CheckBox1.CheckState = 0
        Toggle = False
    End If
End Sub

End Class

解决方案

EDIT: For those of you who have downloaded/tested this already, I made a bugfix to the classes so you'll need to redownload the sources if you're going to use them again.

If you want to perform proper data transfer you'll need to use a more reliable method than just simply reading random data. And as usr pointed out: the TcpClient.ReceiveBufferSize property does not tell you how much data there is to receive, nor how much data there is sent to you. ReceiveBufferSize is just a variable indicating how many bytes you are expected to get each time you read incoming data. Read the MSDN page about the subject for more info.

As for the data transfer, I've created two classes which will do length-prefixed data transfer for you. Just import them to your project and you'll be able to start using them immediatelly. Link: http://www.mydoomsite.com/sourcecodes/ExtendedTcpClient.zip

Example usage

Server side

  1. First declare a new variable for ExtendedTcpClient, and be sure to include WithEvents in the declaration.

    Dim WithEvents Client As ExtendedTcpClient
    

  2. Then you just need to use a normal TcpListener to check for incoming connections. The TcpListener.Pending() method can be checked in for example a timer.

    When you are to accept a new TcpClient, first declare a new instance of the ExtendedTcpClient. The class requires to have a form as it's owner, in this application Me is the current form.
    Then, use the ExtendedTcpClient.SetNewClient() method with Listener.AcceptTcpClient() as it's argument to apply the TcpClient from the listener.

    If Listener.Pending() = True Then
        Client = New ExtendedTcpClient(Me)
        Client.SetNewClient(Listener.AcceptTcpClient())
    End If
    

  3. After that you won't be needing the timer anymore, as the ExtendedTcpClient has it's own thread to check for data.

    Now you need to subscribe to the PacketReceived event of the client. Create a sub like so:

    Private Sub Client_PacketReceived(sender As Object, e As ExtendedTcpClient.PacketReceivedEventArgs) Handles Client.PacketReceived
    
    End Sub
    

    In there you can for example output the received packet as text into a TextBox. Just check if the packet header is PlainText and then you can convert the received packets contents (which is an array of bytes, accessed via e.Packet.Contents) to a string and put it in the TextBox.

    If e.Packet.Header = TcpMessagePacket.PacketHeader.PainText Then
        TextBox1.AppendText("Message recieved: " & System.Text.Encoding.Default.GetString(e.Packet.Contents) & Environment.NewLine)
    End If
    

  4. Lastly, when closing the form you just need to disconnect the client.

    Private Sub ServerWindow_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        If Client IsNot Nothing Then Client.Disconnect()
    End Sub
    

And that's it for the server side.


Client side

  1. For the client side you will only be needing a normal TcpClient (unless you don't want to receive data there too).

    Dim Client As New TcpClient
    

  2. Then connect to the server via the IP and port you've given the listener.

    Client.Connect("127.0.0.1", 5555) 'Connects to localhost (your computer) at port 5555.
    

  3. Now if you want to send plain text to the server you'd do something like this:

    Dim MessagePacket As New TcpMessagePacket(System.Text.Encoding.Default.GetBytes(TextBox2.Text), TcpMessagePacket.PacketHeader.PainText)
    MessagePacket.Send(Client) 'Client is the regular TcpClient.
    

And now everything should be working!

Link to a complete example project: http://www.mydoomsite.com/sourcecodes/TCP%20Messaging%20System.zip

If you want to add more headers to the class, just open TcpMessagePacket.vb and add more values in the PacketHeader enum (located in the region called Constants).

Hope this helps!


Screenshot from the example project

(Click the image for larger resolution)

这篇关于TCP/ip 接收连接但在尝试读取数据时锁定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆