我正在尝试编写一个小客户端,它将侦听某个端口上的服务器。当我运行我的代码它似乎挂起,然后它只会给我第一条消息,而不是之后再收到?我在这里破坏了我的大脑。任何帮助表示赞赏。
Option Strict On
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Public Class Form1
'Form Controls.
Private lblPort As New Label
Private txtPort As New TextBox
Private lblIp As New Label
Private txtIp As New TextBox
Private lblSend As New Label
Private txtSend As New TextBox
Private WithEvents btnConnectSendReceive As New Button
Private lblReceived As New Label
Private lvwReceived As New ListView
Private txtBoxrecieved As New RichTextBox
'Global Objects.
Private gSocket As Socket = Nothing
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Setup form controls.
With Me
.Text = "SplitPackManagerTest"
.Controls.Add(lblPort)
.Controls.Add(txtPort)
.Controls.Add(lblIp)
.Controls.Add(txtIp)
.Controls.Add(lblSend)
.Controls.Add(txtSend)
.Controls.Add(btnConnectSendReceive)
.Controls.Add(lblReceived)
.Controls.Add(lvwReceived)
.Controls.Add(txtBoxrecieved)
.Height = 600
End With
With lblPort
.Text = "Port:"
.Location = New Point(12, 12)
.AutoSize = True
End With
With txtPort
.Text = "3001" 'Same port that server is listening on.
.Location = New Point(100, 12)
End With
With lblIp
.Text = "IP:"
.Location = New Point(12, 42)
.AutoSize = True
End With
With txtIp
.Text = "127.0.0.1" 'Loop-back IP address (localhost).
.Location = New Point(100, 42)
End With
With lblSend
.Text = "Send:"
.Location = New Point(12, 72)
.AutoSize = True
End With
With txtSend
.Text = Chr(2) & "(login (term-id 2))" & Chr(3)
.Location = New Point(100, 72)
End With
With btnConnectSendReceive
.Text = "Connect"
.Location = New Point(12, 122)
.Width = 260
End With
With lblReceived
.Text = "Received Bytes:"
.Location = New Point(12, 182)
.AutoSize = True
End With
With lvwReceived
.Height = 100
.Dock = DockStyle.Bottom
.View = View.Details
.GridLines = True
.FullRowSelect = True
.MultiSelect = False
.Scrollable = True
.Columns.Add("Dec")
.Columns.Add("Hex")
.Columns.Add("Chr")
For Each vCol As ColumnHeader In .Columns
vCol.Width = CInt(Math.Floor(.Width / .Columns.Count)) - CInt(Math.Floor(30 / .Columns.Count))
Next
End With
With txtBoxrecieved
.Height = 200
.Dock = DockStyle.Bottom
.ScrollBars = RichTextBoxScrollBars.Both
End With
End Sub
Private Function ConnectSendReceive(ByVal pSendData As Byte(), ByVal pIp As String, ByVal pPort As Integer) As Byte()
'Try creating IP endpoint.
If String.IsNullOrEmpty(pIp) Then Return Nothing
If Not IPAddress.TryParse(pIp, Nothing) Then Return Nothing
Dim vIp As IPAddress = IPAddress.Parse(txtIp.Text)
Dim vEndPoint As New IPEndPoint(vIp, CInt(txtPort.Text))
'Timeout will be 0.5 seconds.
Dim vTimeout As Integer = 500000
'For our little example, we expect all messages to be 1024 bytes or below (arbitrary amount).
Dim vMessageLength As Integer = 1002400000
'Remember, when dimensioning arrays, the integer specified is the upper bounds, not the length.
Dim vServerResponse As Byte() = Nothing
'Initiate socket.
Dim gSocket As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
'Connect.
Try
gSocket.Connect(vEndPoint)
Catch ex As Exception
Return Nothing
End Try
If Not gSocket.Connected Then Return Nothing
'Send.
'Socket.SendTimeout = vTimeout
gSocket.Send(pSendData)
txtBoxrecieved.AppendText("Sending.. " & txtSend.Text)
'Receive response.
'Socket.ReceiveTimeout = vTimeout
Dim vBuffer(vMessageLength - 1) As Byte
Dim vNumOfBytesReceived As Integer = 0
Try
vNumOfBytesReceived = gSocket.Receive(vBuffer, 0, vMessageLength, SocketFlags.None)
Catch ex As Exception
Return Nothing
End Try
'Return received bytes.
ReDim vServerResponse(vNumOfBytesReceived - 1)
Array.Copy(vBuffer, vServerResponse, vNumOfBytesReceived)
'Disconnect (since we're using a "Using" statement, the socket will be disconnected here without us explicitly doing it).
Return vServerResponse
End Function
Private Sub btnConnectSendReceive_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConnectSendReceive.Click
'Send message and get response from server.
Dim vServerResponse As Byte() = ConnectSendReceive(Encoding.ASCII.GetBytes(txtSend.Text), txtIp.Text, CInt(txtPort.Text))
'Did we receive a response?
If vServerResponse Is Nothing Then MessageBox.Show("Server not reachable / Received no response from server.") : Exit Sub
'Do something with response.
For Each vByte As Byte In vServerResponse
Dim vLvi As New ListViewItem
With vLvi
'Decimal column.
.Text = vByte.ToString
'Hexidecimal column.
.SubItems.Add(vByte.ToString("X2"))
'Character column.
.SubItems.Add(ChrW(vByte))
End With
With lvwReceived
.Items.Add(vLvi)
.EnsureVisible(.Items.Count - 1)
End With
Next
txtBoxrecieved.AppendText(UnicodeBytesToString(vServerResponse))
End Sub
Private Function UnicodeBytesToString(
ByVal bytes() As Byte) As String
Return System.Text.Encoding.ASCII.GetString(bytes)
End Function
End Class
感谢
大卫
答案 0 :(得分:0)
如果我是你,我会在真理,正义和堆叠溢出之道的圣洁守护者之前重写这个问题。看到它并向下投票给你不合适;没有明确的问题。
但是,我认为你在这种情况下要求有关调试的指导。所以我会尝试回答这个问题。
您需要知道此对话双方发生了什么。要做到这一点,你需要使用像Wireshark这样的工具。下载Wireshark并学习使用它。
我倾向于同意the_lotus的原因是你分配的非常大的缓冲区(忽略可能的大小调整错误)意味着你期望得到相当大的响应。数据包有效负载最高可达64KB,但这种情况并不常见,即使出现这种情况,协议也允许在途中进行分段。
因此,如果数据被分成几个数据包,则需要继续读取,直到您拥有完整的有效负载。这可能需要在流中查找边界标记,如果有可能在同一连接上接收更多有效负载,则需要以允许累积其余有效内容的方式保留下一个有效负载的开始。 / p>
如果你这样做,你可能会看到一个包含部分有效负载的完整数据包,正如我在写作时发布的评论中的the_lotus所描述的那样。
我认为他可能是对的,但他也可能是错的,像Wireshark这样的工具可以让你找到答案,而不是盲目地猜测和黑客攻击你的代码来验证你的假设。
您正在使用的I / O样式称为轮询。有时候必须这样做,例如嵌入式系统通常不支持任何更复杂的东西,没有空间。但是在具有完整.NET框架的系统上,您确实应该使用IOCP。对于单个用户应用程序来说,这不是必需的,但如果您选择了正确的习惯,则不会产生可伸缩性问题。
好的,关于为什么响应被截断,检查你的代码后(VB让我的眼睛受伤)我几乎可以确定the_lotus是对的。您正在从套接字中读取一次,然后您将关闭它,而不会尝试检查您是否有完整的响应或尝试读取更多数据。
这看起来像是第一年的大学任务,所以大概你有一些规范。要确定您是否拥有完整的响应,您需要知道以下任一项
一些伪代码
open the connection
while not CheckForCompletePayload(buffer)
read some data and append it to your buffer
close the connection.