TCP / ip recive连接但在尝试读取数据时锁定

时间:2016-01-06 06:49:58

标签: vb.net tcp

有人可以告诉我为什么我的服务器在我的rclient连接并尝试发送数据时锁定了吗?

如果我发表评论:

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

并且只是

TextBox2.Text = ("Remote connected")

服务器选择连接的客户端,所以它必须是我用.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

结束班

2 个答案:

答案 0 :(得分:0)

编辑:对于那些已经下载/测试过的人,我对课程进行了修正,因此如果您要再次使用它们,则需要重新下载这些来源。

如果您想要执行正确的数据传输,您需要使用比仅仅读取随机数据更可靠的方法。正如 usr 所指出的那样:TcpClient.ReceiveBufferSize属性不会告诉您要接收的数据量,以及发送给您的数据量。 ReceiveBufferSize只是一个变量,表示每次读取传入数据时预计会获得多少字节。有关详情,请阅读有关主题的MSDN page

至于数据传输,我创建了两个类,它们将为您进行长度前缀数据传输。只需将它们导入您的项目,您就可以立即开始使用它们。链接:http://www.mydoomsite.com/sourcecodes/ExtendedTcpClient.zip

使用示例

服务器端

  1. 首先为ExtendedTcpClient声明一个新变量,并确保 在声明中包含WithEvents

    Dim WithEvents Client As ExtendedTcpClient
    
  2. 然后你只需要使用普通TcpListener来检查 传入连接。 TcpListener.Pending()方法可以 例如,检查了一个计时器。

    当您接受新的TcpClient时,首先声明一个新的ExtendedTcpClient Me的实例。这堂课要求有一个 作为其所有者的表单,在此应用程序中ExtendedTcpClient.SetNewClient()是当前表单 然后,使用Listener.AcceptTcpClient()方法 TcpClient因为它适用于 来自听众的If Listener.Pending() = True Then Client = New ExtendedTcpClient(Me) Client.SetNewClient(Listener.AcceptTcpClient()) End If

    ExtendedTcpClient
  3. 之后你将不再需要计时器了 PacketReceived有自己的线程来检查数据。

    现在您需要订阅Private Sub Client_PacketReceived(sender As Object, e As ExtendedTcpClient.PacketReceivedEventArgs) Handles Client.PacketReceived End Sub 事件 客户。像这样创建一个子:

    TextBox

    在那里,您可以将收到的数据包作为文本输出到 一个PlainText。只需检查数据包标头是否为e.Packet.Contents然后 你可以转换收到的数据包内容(这是一个数组 通过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

    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
    
  4. 最后,关闭表单时,您只需要断开客户端连接。

    TcpClient
  5. 这就是服务器端。

    客户端

    1. 对于客户端,您只需要正常的Dim Client As New TcpClient ,除非您也不想在那里接收数据)。

      Client.Connect("127.0.0.1", 5555) 'Connects to localhost (your computer) at port 5555.
      
    2. 然后通过您给予监听器的IP和端口连接到服务器。

      Dim MessagePacket As New TcpMessagePacket(System.Text.Encoding.Default.GetBytes(TextBox2.Text), TcpMessagePacket.PacketHeader.PainText)
      MessagePacket.Send(Client) 'Client is the regular TcpClient.
      
    3. 现在,如果您想将纯文本发送到服务器,您可以执行以下操作:

      TcpMessagePacket.vb
    4. 现在一切都应该正常工作!

      链接到完整的示例项目:http://www.mydoomsite.com/sourcecodes/TCP%20Messaging%20System.zip

      如果您想在课程中添加更多标题,只需打开PacketHeader并在Constants枚举(位于名为onCreateOptionsMenu的区域)中添加更多值。

      希望这有帮助!

      示例项目的屏幕截图

      (点击图片查看大图)

      ExtendedTcpClient example project output

答案 1 :(得分:0)

您假设读取返回特定数量的数据,例如ReceiveBufferSize。事实并非如此。读取返回至少一个字节,即全部。

为了澄清,TCP不支持基于邮件的传输。

正确的阅读方式取决于协议。如果知道预期的确切字节数,则需要在循环中读取,直到接收到这么多字节(或者使用BinaryReader为您执行此操作)。

对于基于行的协议,您可以使用StreamReader.ReadLine再次自动循环。

ReceiveBufferSize与可用或将来的数据完全无关。

DataAvailable现在可以无阻塞地读取多少数据。但可能会有更多数据出现。使用它几乎总是一个bug。即使数据在1ms之后出现,也可能随时返回0。