Alibabar 2020-06-09 04:33 采纳率: 0%
浏览 173
已结题

请教一个SocketAsyncEventArgs的复用问题?

使用SocketAsyncEventArgs进行UDP异步发送,SAEA复用的情况下,会出现一些不能理解的问题,具体描述在代码中三个发送函数总有注释,望大神能指点一二,感激不尽。

异步UDP代码

Imports System.Net
Imports System.Net.Sockets

Public Class UDP

    Private m_SaeaReceive As New SocketAsyncEventArgs
    Private m_SaeaSend1 As New SocketAsyncEventArgs
    Private m_SaeaSend2 As New SocketAsyncEventArgs
    Private m_BufferSend(65506) As Byte
    Private m_BufferReceive(65506) As Byte
    Private m_Udp As Socket

    Public Sub Start(ByVal Port As UInt16)
        m_Udp = New Socket(IPAddress.Any.AddressFamily, SocketType.Dgram, ProtocolType.Udp)
        m_Udp.Bind(New IPEndPoint(IPAddress.Any, Port))

        m_SaeaReceive.SetBuffer(m_BufferReceive, 0, m_BufferReceive.Length)
        m_SaeaReceive.RemoteEndPoint = New IPEndPoint(IPAddress.Any, 0)
        m_SaeaSend2.SetBuffer(m_BufferSend, 0, m_BufferSend.Length)

        AddHandler m_SaeaReceive.Completed, AddressOf Saea_Completed
        AddHandler m_SaeaSend1.Completed, AddressOf Saea_Completed
        AddHandler m_SaeaSend2.Completed, AddressOf Saea_Completed

        StartReceive()
    End Sub

    Public Sub SendTo1(ByVal Remote As IPEndPoint, ByVal Data() As Byte)
        If Remote Is Nothing Then Return
        If Data Is Nothing Then Return
        If Data.Length = 0 Then Return

        '重复使用一个Saea,会在使用一定次数后出现SocetError=AddressFamilyNotSupported的情况
        '出现次数相对固定,本机测试一次发送10240字节的数据,第一次差不多在210次左右出现。
        '与此同时SendAsync第一次进入了同步发送完毕,即SendAsync()返回False。
        '这个Saea不能再使用,如果尝试用此Saea重发,仍会出现上述情况。
        '在发送异步回调处理中使用故障Saea的Remote和Buffer重新创建一个Saea,再重新发送,可以发送成功。
        '上述问题一般会出现两次,且两次的次数都相对固定,很难再现第三次。
        Try
            m_SaeaSend1.RemoteEndPoint = Remote
            m_SaeaSend1.SetBuffer(Data, 0, Data.Length)
            If m_Udp.SendToAsync(m_SaeaSend1) = False Then
                '同步完成,上述问题均出现在同步完成的情况下。
                SendedToHandler(m_SaeaSend1)
            End If
        Catch ex As Exception
            Return
        End Try
    End Sub

    Public Sub SendTo2(ByVal Remote As IPEndPoint, ByVal Data() As Byte)
        If Remote Is Nothing Then Return
        If Data Is Nothing Then Return
        If Data.Length = 0 Then Return

        Try
            '给Saea预先分配一个缓冲,之后每次将数据复制到此缓冲中,不会出现发送问题
            m_SaeaSend2.RemoteEndPoint = Remote
            Array.Copy(Data, 0, m_SaeaSend2.Buffer, 0, Data.Length)
            m_SaeaSend2.SetBuffer(0, Data.Length)
            If m_Udp.SendToAsync(m_SaeaSend2) = False Then
                SendedToHandler(m_SaeaSend2)
            End If
        Catch ex As Exception
            Return
        End Try
    End Sub

    Public Sub SendTo3(ByVal Remote As IPEndPoint, ByVal Data() As Byte)
        If Remote Is Nothing Then Return
        If Data Is Nothing Then Return
        If Data.Length = 0 Then Return

        Try
            '每次都新建一个Saea来发送,不会出现问题
            Dim saea As New SocketAsyncEventArgs
            AddHandler saea.Completed, AddressOf Saea_Completed
            saea.RemoteEndPoint = Remote
            saea.SetBuffer(Data, 0, Data.Length)
            If m_Udp.SendToAsync(saea) = False Then
                SendedToHandler(saea)
            End If
        Catch ex As Exception
            Return
        End Try
    End Sub

    Private Sub StartReceive()
        If m_Udp.ReceiveFromAsync(m_SaeaReceive) = False Then
            ReceivedFromHandler(m_SaeaReceive)
        End If
    End Sub

    '异步完成事件处理,分流
    Private Sub Saea_Completed(ByVal sender As Object, ByVal e As SocketAsyncEventArgs)
        Select Case e.LastOperation
            Case SocketAsyncOperation.SendTo
                SendedToHandler(e)
            Case SocketAsyncOperation.ReceiveFrom
                ReceivedFromHandler(e)
        End Select
    End Sub

    Private Sub SendedToHandler(ByVal e As SocketAsyncEventArgs)
        Static index As Integer = 0

        index = index + 1
        If e.SocketError = SocketError.Success Then
            Debug.Print(index.ToString.PadLeft(5, "0") & "  sended success:" & e.BytesTransferred & " bytes")
        ElseIf e.SocketError = SocketError.AddressFamilyNotSupported Then
            Debug.Print(index.ToString.PadLeft(5, "0") & "  send failed:" & e.SocketError.ToString & "  ================================================================")

            '重建一个Saea重新发送可以成功
            'm_SaeaSend1 = New SocketAsyncEventArgs
            'm_SaeaSend1.RemoteEndPoint = e.RemoteEndPoint
            'm_SaeaSend1.SetBuffer(e.Buffer, e.Offset, e.Count)
            'AddHandler m_SaeaSend1.Completed, AddressOf Saea_Completed
            'If m_Udp.SendAsync(m_SaeaSend1) = False Then
            '    SendedToHandler(m_SaeaSend1)
            'End If
        Else
            Debug.Print(index.ToString.PadLeft(5, "0") & "  send failed:" & e.SocketError.ToString)
        End If
    End Sub

    Private Sub ReceivedFromHandler(ByVal e As SocketAsyncEventArgs)
        Static index As Integer = 0

        index = index + 1
        If e.SocketError = SocketError.Success Then
            Debug.Print("                    " & index.ToString.PadLeft(5, "0") & "  received success:" & e.BytesTransferred & " bytes")
            StartReceive()
        Else
            Debug.Print("                    " & index.ToString.PadLeft(5, "0") & "  receive failed:" & e.SocketError.ToString)
        End If
    End Sub
End Class

测试代码

Imports System.Net
Imports System.Threading

Public Class Form2

    Private server As New UDP
    Private client As New UDP
    Private buff_comm(10240 - 1) As Byte

    Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        server.Start(6000)
        client.Start(7000)
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Do
            Dim buff(1024 * 10 - 1) As Byte
            client.SendTo1(New IPEndPoint(IPAddress.Parse("192.168.1.3"), 6000), buff)
            Thread.Sleep(50)
        Loop
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Do
            Dim buff(1024 * 10 - 1) As Byte
            client.SendTo2(New IPEndPoint(IPAddress.Parse("192.168.1.3"), 6000), buff)
            Thread.Sleep(50)
        Loop
    End Sub

    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Do
            Dim buff(1024 * 10 - 1) As Byte
            client.SendTo3(New IPEndPoint(IPAddress.Parse("192.168.1.3"), 6000), buff)
            Thread.Sleep(50)
        Loop
    End Sub

    Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        Do
            client.SendTo1(New IPEndPoint(IPAddress.Parse("192.168.1.3"), 6000), buff_comm)
            Thread.Sleep(50)
        Loop
    End Sub
End Class
  • 写回答

1条回答 默认 最新

  • dabocaiqq 2020-06-09 10:38
    关注
    评论

报告相同问题?

悬赏问题

  • ¥15 三因素重复测量数据R语句编写,不存在交互作用
  • ¥15 微信会员卡等级和折扣规则
  • ¥15 微信公众平台自制会员卡可以通过收款码收款码收款进行自动积分吗
  • ¥15 随身WiFi网络灯亮但是没有网络,如何解决?
  • ¥15 gdf格式的脑电数据如何处理matlab
  • ¥20 重新写的代码替换了之后运行hbuliderx就这样了
  • ¥100 监控抖音用户作品更新可以微信公众号提醒
  • ¥15 UE5 如何可以不渲染HDRIBackdrop背景
  • ¥70 2048小游戏毕设项目
  • ¥20 mysql架构,按照姓名分表