1

私はC#でネットワークライブラリの作成に取り組んでおり、元々は.NET3.5Frameworkを使用していました。最近、.NET 4.5に切り替えることにしましたが、UDPパケットの送信で問題が発生し始めました。私が遭遇しているのは、UDPパケットの送信が速すぎる場合、メソッドはofでSocket.SendToAsync完了し、パケットは送信されないということです。 SocketErrorAddressFamilyNotSupported

プロジェクトを.NET3.5に切り替えると、どんなに繰り返しても問題が発生することはありません。これは、.NET4.0でも再現できます。

これは、問題を再現するために私がまとめたプロジェクトへのリンクです。「ClientSnd」または「ServerSnd」ボタンをスパムすると、エラーが発生することがわかります。プロジェクトを.NET3.5に切り替えて、必要なすべてのスパムを送信します...問題はまったくありません。

この問題を検索するのに役立つ情報を見つけることができませんでした。何か案は?

編集(問題をデモするサンプルプロジェクトからコードを追加):

クライアントとサーバーの両方でバインドが行われている場所は次のとおりです。

            byte[] clientBuffer = new byte[32768];
            byte[] serverBuffer = new byte[32768];

            IPEndPoint clientLocalEndPoint = GetLocalIPEndPoint(0, AddressFamily.InterNetwork);
            IPEndPoint serverLocalEndPoint = GetLocalIPEndPoint(6337, AddressFamily.InterNetwork);

            m_ClientSocket.ExclusiveAddressUse = true;
            m_ServerSocket.ExclusiveAddressUse = true;
            m_ClientSocket.Bind(clientLocalEndPoint);
            m_ServerSocket.Bind(serverLocalEndPoint);

            m_ClientSendArgs.RemoteEndPoint = GetRemoteIPEndPoint("127.0.0.1", 6337, AddressFamily.InterNetwork);
            m_ClientRecvArgs.RemoteEndPoint = m_ClientSocket.LocalEndPoint;

            m_ServerSendArgs.RemoteEndPoint = GetRemoteIPEndPoint("127.0.0.1", ((IPEndPoint)m_ClientSocket.LocalEndPoint).Port, AddressFamily.InterNetwork);
            m_ServerRecvArgs.RemoteEndPoint = m_ServerSocket.LocalEndPoint;

            m_ClientSendArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnClientCompletion);
            m_ClientRecvArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnClientCompletion);
            m_ServerSendArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnServerCompletion);
            m_ServerRecvArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnServerCompletion);

            m_ClientRecvArgs.SetBuffer(clientBuffer, 0, clientBuffer.Length);
            m_ServerRecvArgs.SetBuffer(serverBuffer, 0, serverBuffer.Length);

            ClientReceive();
            ServerReceive();

およびGetRemoteIPEndPointメソッドGetLocalIPEndPoint

    private static IPEndPoint GetRemoteIPEndPoint(string address, int port, AddressFamily addressFamily)
    {
        IPAddress[] ipAddresses = null;

        ipAddresses = Dns.GetHostAddresses(address);

        List<IPEndPoint> ipEndPointList = new List<IPEndPoint>();

        for (int i = 0; i < ipAddresses.Length; i++)
        {
            IPAddress ipAddress = ipAddresses[i];

            if (ipAddress.AddressFamily == addressFamily)
            {
                IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, port);

                ipEndPointList.Add(ipEndPoint);
            }
        }

        return ipEndPointList.ToArray()[0];
    }

    private static IPEndPoint GetLocalIPEndPoint(int port, AddressFamily addressFamily)
    {
        IPEndPoint localEndPoint = null;

        switch (addressFamily)
        {
            case AddressFamily.InterNetwork:
                {
                    localEndPoint = new IPEndPoint(IPAddress.Any, port);

                    break;
                }
            case AddressFamily.InterNetworkV6:
                {
                    localEndPoint = new IPEndPoint(IPAddress.IPv6Any, port);

                    break;
                }
        }

        return localEndPoint;
    }

これは誰がデータを送信するか(クライアントまたはサーバー)に関係なく発生するため、送信者であるクライアントに焦点を当てます。

ボタンをクリックするClientSnd

    private void Button_ClientSnd_Click(object sender, RoutedEventArgs e)
    {
        lock (SyncRoot)
        {
            byte[] buffer = Encoding.ASCII.GetBytes("Hello there.  Just testing.  Nothing to see here.  Move along.");

            m_ClientSendQueue.Enqueue(buffer);

            if (!m_ClientTransmitting)
            {
                m_ClientTransmitting = true;

                ClientSendBuffer();
            }
        }
    }

クライアントの送信方法:

    private void ClientSendBuffer()
    {
        lock (SyncRoot)
        {
            if (m_ClientSendQueue.Count > 0)
            {
                byte[] buffer = m_ClientSendQueue.Dequeue();

                m_ClientSendArgs.SetBuffer(buffer, 0, buffer.Length);

                ClientSend();
            }
            else
            {
                m_ClientTransmitting = false;
            }
        }
    }

    private void ClientSend()
    {
        if (!m_ClientSocket.SendToAsync(m_ClientSendArgs))
        {
            OnClientCompletion(this, m_ClientSendArgs);
        }
    }

クライアントの完了コールバック:

    private void OnClientCompletion(object sender, SocketAsyncEventArgs e)
    {
        SocketError socketError = e.SocketError;

        if (socketError != SocketError.Success)
        {
            ClientConsoleWrite("SocketError: {0}\r\n", socketError);
        }

        switch (e.LastOperation)
        {
            case SocketAsyncOperation.SendTo:
                {
                    if (socketError == SocketError.Success)
                    {
                        ClientConsoleWrite("Client message sent!\r\n");
                    }

                    ClientSendBuffer();

                    break;
                }
            case SocketAsyncOperation.ReceiveFrom:
                {
                    int bytesTransferred = e.BytesTransferred;

                    byte[] buffer = new byte[bytesTransferred];

                    Buffer.BlockCopy(e.Buffer, e.Offset, buffer, 0, bytesTransferred);

                    string message = Encoding.ASCII.GetString(buffer);

                    ClientConsoleWrite("Message received: {0}\r\n", message);

                    ClientReceive();

                    break;
                }
        }
    }
4

1 に答える 1

2

私はこれを理解しました。この問題は、変数m_ClientSendArgsの基になるバッファーが次を使用して絶えず変更されているために発生していますSetBuffer

byte[] buffer = m_ClientSendQueue.Dequeue();

m_ClientSendArgs.SetBuffer(buffer, 0, buffer.Length);

静的バッファーを割り当ててBuffer.BlockCopyを使用すると、問題は解決しました。

byte[] buffer = m_ClientSendQueue.Dequeue();

Buffer.BlockCopy(buffer, 0, m_ClientSendBuffer, 0, buffer.Length);

m_ClientSendArgs.SetBuffer(0, buffer.Length);

だから私はずっとそれを間違って実装してきました。.NET 3.5の問題でも、.NET 4.0/4.5のTCPの問題でもなかったのは不思議です。

于 2013-03-19T22:54:37.097 に答える