You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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一次就会尝试接收,没有数据的时候就触发异常,这就是你看到的问题。

而且你的代码还有两个潜在问题:

  1. ServerPort.Text是字符串类型,直接传给publisher.Connect会导致类型错误(Connect需要Integer类型的端口)
  2. 获取本地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

关键优化点说明

  1. 异步接收机制:用BeginReceive和EndReceive实现异步接收,不会阻塞UI线程,也不会因为没有数据而抛出异常
  2. 输入验证:添加了IP地址和端口号的有效性验证,避免无效输入导致的错误
  3. 本地IP获取:改用Dns.GetHostEntry(替代过时的GetHostByName),并过滤出IPv4地址,确保和Arduino的兼容性
  4. UI线程安全:异步回调中用Me.Invoke更新文本框,避免跨线程操作控件的错误

这样修改后,你的程序应该能正常和Arduino进行UDP通信,发送数据并接收显示响应了。

内容的提问来源于stack exchange,提问作者flirty with code

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 14:27:36