VB.NET实现Arduino有线以太网UDP通信时出现Socket error 0x80004005错误的解决方案求助
解决VB.NET与Arduino UDP通信的非阻塞套接字错误
我来帮你搞定这个UDP通信的问题!先说说你遇到的错误原因,再给你修正后的代码和优化建议。
错误原因分析
你在Form1_Load里把subscriber.Client.Blocking = False设置成了非阻塞模式,这时候调用subscriber.Receive(ep)时,如果当前没有数据可以接收,套接字不会等待数据到来,而是立刻抛出A non-blocking socket operation could not be completed immediately这个错误。Timer每Tick一次就会尝试接收,没有数据的时候就触发异常,这就是你看到的问题。
而且你的代码还有两个潜在问题:
ServerPort.Text是字符串类型,直接传给publisher.Connect会导致类型错误(Connect需要Integer类型的端口)- 获取本地IP的方法
Dns.GetHostByName已经过时,而且可能返回IPv6地址,不一定适合和Arduino通信
修正后的完整代码
下面是优化后的代码,用异步接收代替非阻塞同步接收,既不会阻塞UI线程,也不会频繁抛出异常:
Imports System.Net Imports System.Net.Sockets Imports System.Text Public Class udpWindow Dim localIP As String = GetLocalIPv4Address() Dim localPort As Integer = 5000 Dim publisher As New UdpClient(0) Dim subscriber As New UdpClient(localPort) ' 获取本地IPv4地址(过滤掉IPv6) Private Function GetLocalIPv4Address() As String Dim hostEntry = Dns.GetHostEntry(Dns.GetHostName()) Return hostEntry.AddressList.FirstOrDefault(Function(ip) ip.AddressFamily = AddressFamily.InterNetwork)?.ToString() End Function Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click LocalIP_txt.Text = localIP localPort_txt.Text = localPort.ToString() End Sub Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Start.Click ' 验证端口输入是否有效 Dim serverPort As Integer If Not Integer.TryParse(ServerPort.Text, serverPort) Then MsgBox("请输入有效的数字端口号!") Return End If ' 验证IP地址是否有效 Dim serverIp As IPAddress If Not IPAddress.TryParse(ServerIP.Text, serverIp) Then MsgBox("请输入有效的IP地址!") Return End If Try publisher.Connect(serverIp, serverPort) Dim sendBytes() As Byte = Encoding.ASCII.GetBytes("0") publisher.Send(sendBytes, sendBytes.Length) MsgBox("数据已成功发送!") Catch ex As Exception MsgBox("发送失败:" & ex.Message) End Try End Sub Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load ' 启动异步接收,避免阻塞UI线程 BeginAsyncReceive() End Sub ' 开始异步接收数据 Private Sub BeginAsyncReceive() Try Dim remoteEp As IPEndPoint = New IPEndPoint(IPAddress.Any, localPort) subscriber.BeginReceive(AddressOf ReceiveCallback, remoteEp) Catch ex As Exception MsgBox("启动接收失败:" & ex.Message) End Try End Sub ' 异步接收回调函数 Private Sub ReceiveCallback(ByVal ar As IAsyncResult) Dim remoteEp As IPEndPoint = ar.AsyncState Try ' 结束异步接收,获取数据 Dim recvBytes() As Byte = subscriber.EndReceive(ar, remoteEp) Dim receivedMsg As String = Encoding.ASCII.GetString(recvBytes) ' 因为回调在非UI线程,必须用Invoke更新文本框 Me.Invoke(Sub() rcvMsgs.Text = receivedMsg End Sub) Catch ex As Exception MsgBox("接收错误:" & ex.Message) Finally ' 继续等待下一次接收 BeginAsyncReceive() End Try End Sub End Class
关键优化点说明
- 异步接收机制:用
BeginReceive和EndReceive实现异步接收,不会阻塞UI线程,也不会因为没有数据而抛出异常 - 输入验证:添加了IP地址和端口号的有效性验证,避免无效输入导致的错误
- 本地IP获取:改用
Dns.GetHostEntry(替代过时的GetHostByName),并过滤出IPv4地址,确保和Arduino的兼容性 - UI线程安全:异步回调中用
Me.Invoke更新文本框,避免跨线程操作控件的错误
这样修改后,你的程序应该能正常和Arduino进行UDP通信,发送数据并接收显示响应了。
内容的提问来源于stack exchange,提问作者flirty with code
相关产品推荐
相关产品推荐

