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 HFSS 中的 H 场图与 MATLAB 中绘制的 B1 场 部分对应不上
  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?