【问题标题】:Testing UDP Locally C#在本地测试 UDP C#
【发布时间】:2016-11-27 15:11:12
【问题描述】:

我正在编写一个需要使用 UDP 的单声道 C# 应用程序。我正在编写我的测试套件,以便确保使用 NUnit 正确接收数据包。

我用UdpCom 类制作了一个最小的工作示例,该类应该现在就监听并打印出它在回调方法中接收到的字节。

我最小的UdpCom 类看起来像:

using System;
using System.Net;
using System.Net.Sockets;


namespace UdpPractice
{
    public class UdpState
    {
        public UdpClient client;
        public IPEndPoint endpoint;
        public UdpState(UdpClient c, IPEndPoint iep)
        {
            this.client = c;
            this.endpoint = iep;
        }
    }
    public class UdpCom
    {
        public UdpState uState;
        public UdpClient uClient;
        public IPAddress address;
        public int port;
        public IPEndPoint uEndpoint;

        public UdpCom (IPAddress address, int port)
        {
            uEndpoint = new IPEndPoint (address, port);
            uClient = new UdpClient (uEndpoint);
            uState = new UdpState (uClient, uEndpoint);
            uClient.BeginReceive (new AsyncCallback(RxCallback), uState);
        }

        public void RxCallback(IAsyncResult result)
        {
            UdpState rState = (UdpState)(result.AsyncState);
            UdpClient rClient = rState.client;
            IPEndPoint rEndPoint = rState.endpoint;
            byte[] rxBytes = rClient.EndReceive (result, ref rEndPoint);
            Console.WriteLine ("Received Bytes ___________________________");
            Console.WriteLine (rxBytes.ToString ());

            rClient.BeginReceive (new AsyncCallback(RxCallback), rState);
        }
    }
}

我的简单测试实例化了这个类,然后向它发送一个虚拟字节包。我现在不测试结果,只是在我的RxCallback 方法中放置一个断点。

这是我的 NUNIT 测试:

using NUnit.Framework;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UdpPractice;

namespace UdpTest
{
    [TestFixture ()]
    public class Test
    {
        [Test ()]
        public void TestCase ()
        {
            // Setup Receiver
            IPAddress address = new IPAddress (new byte[] { 127, 0, 0, 1 });
            int port = 14580;
            UdpCom com = new UdpCom (address, port);
            com.uClient.Connect (com.uEndpoint);
            // Set up sender
            UdpClient sender = new UdpClient(new IPEndPoint (address, port));
            sender.Connect (address, port);

            // Dummy Data
            byte [] dummyData = new byte[] {1, 2, 3, 4, 4, 5};

            sender.Send (dummyData, dummyData.Length);
            Thread.Sleep (100);

            // Close
            sender.Close ();
            com.uClient.Close ();
        }
    }
}

我的问题是,当我在尝试检索字节的行中的 RxCallback 方法时,我得到了这个异常:

System.ObjectDisposedException has been thrown
Cannot access a disposed object.
Object name: System.Net.Sockets.UdpClient

我希望能够将这些字节存储在我的 UdpCom 类中的队列中,但我一开始就无法访问它们。

我在这里可能无法理解一些基本的 UDP 概念,但它看起来很简单。

我一直关注的 udp 示例是:

编辑 我更新了我的课程和测试如下,所以我不使用本地环回。但我仍然得到同样的例外。 UdpCom 现在是:

using System;
using System.Net;
using System.Net.Sockets;


namespace UdpPractice
{
    public class UdpState
    {
        public UdpClient client;
        public IPEndPoint endpoint;
        public UdpState(UdpClient c, IPEndPoint iep)
        {
            this.client = c;
            this.endpoint = iep;
        }
    }
    public class UdpCom
    {
        public UdpState uState;
        public UdpClient uClient;
        public IPAddress address;
        public int port;
        public IPEndPoint uEndpoint;

        public UdpCom (IPAddress address, int port)
        {
            uEndpoint = new IPEndPoint (address, port);
            uClient = new UdpClient (uEndpoint);
            uState = new UdpState (uClient, uEndpoint);
            uClient.BeginReceive (new AsyncCallback(RxCallback), uState);
        }

        public void RxCallback(IAsyncResult result)
        {
            UdpState rState = (UdpState)(result.AsyncState);
            UdpClient rClient = rState.client;
            IPEndPoint rEndPoint = rState.endpoint;
            byte[] rxBytes = rClient.EndReceive (result, ref rEndPoint);
            Console.WriteLine ("Received Bytes ___________________________");
            Console.WriteLine (rxBytes.ToString ());

            rClient.BeginReceive (new AsyncCallback(RxCallback), rState);
        }
    }
}

测试是:

using NUnit.Framework;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UdpPractice;

namespace UdpTest
{
    [TestFixture ()]
    public class Test
    {
        [Test ()]
        public void TestCase ()
        {
            // Setup Receiver
            IPAddress address = new IPAddress (new byte[] { 192, 168, 1, 161 });
            int port = 14580;
            UdpCom com = new UdpCom (IPAddress.Any, port);
            // com.uClient.Connect (com.uEndpoint);
            // Set up sender
            UdpClient sender = new UdpClient(new IPEndPoint (address, port));
            sender.Connect (address, port);

            // Dummy Data
            byte [] dummyData = new byte[] {1, 2, 3, 4, 4, 5};

            sender.Send (dummyData, dummyData.Length);
            Thread.Sleep (100);

            // Close
            sender.Close ();
            com.uClient.Close ();
        }
    }
}

【问题讨论】:

  • 您可以使用的另一个资源:stackoverflow.com/a/19787486/5233410
  • 您只能有一个具有相同 3 个属性的连接:源 IP、目标 IP、端口号。在本地连接时,您必须确保客户端和服务器没有使用相同的 3 个属性,解决方案是让服务器在 IPAny 上侦听,客户端连接到 PC 的 IP 地址。您正在使用 PC 127.0.0.1 的 LoopBack 地址,通常是 LocalHost。 Net库不允许客户端使用环回IP,会报异常。
  • 所以我拿出我的com.uClient.Connect (com.uEndpoint); 线,让com 客户端使用UdpCom com = new UdpCom (IPAddress.Any, port); 在IPAny 上侦听,发件人UdpClient 连接到192.168.1.161。我得到了同样的例外。我更新了我的问题以反映这些变化。
  • 这种行为是正常的。中断异步套接字操作的唯一方法是关闭套接字。当你这样做时,任何挂起的回调都将被调用,但套接字已经被释放。解决方案是在.EndReceive 周围做一个catch (ObjectDisposedException)。是的,我知道通常你不应该捕捉ObjectDisposedException,但否则你必须添加一个线程安全标志来检测处置,这更复杂,收获甚微。另见here

标签: c# unit-testing udp


【解决方案1】:

我想我在与如何与 UDP 通信的基本误解中苦苦挣扎。

UdpCom:

using System;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;

namespace UdpPractice
{
    public class UdpState
    {
        public UdpClient client;
        public IPEndPoint endpoint;
        public UdpState(UdpClient c, IPEndPoint iep)
        {
            this.client = c;
            this.endpoint = iep;
        }
    }
    public class UdpCom
    {
        public UdpState uState;
        public IPAddress address;
        public int port;
        public IPEndPoint uEndpoint;
        public bool receiveFlag;
        public List<byte[]> rxBytesBuffer;

        public UdpCom (IPAddress address, int port)
        {
            uEndpoint = new IPEndPoint (address, port);
            // uClient = new UdpClient (uEndpoint);
            uState = new UdpState (new UdpClient(new IPEndPoint(IPAddress.Parse("127.0.0.1"), port)), uEndpoint);
            receiveFlag = false;
            uState.client.BeginReceive (new AsyncCallback(RxCallback), uState);
            rxBytesBuffer = new List<byte[]> ();
        }

        public void RxCallback(IAsyncResult result)
        {
            UdpState rState = (UdpState)result.AsyncState;
            UdpClient rClient = ((UdpState)result.AsyncState).client;
            IPEndPoint rEndPoint = ((UdpState)result.AsyncState).endpoint;
            byte[] rxBytes = rClient.EndReceive (result, ref rEndPoint);
            rxBytesBuffer.Add (rxBytes);
            Console.WriteLine ("Received Bytes ___________________________");
            Console.WriteLine (rxBytes.ToString ());
            receiveFlag = true;
            rClient.BeginReceive (new AsyncCallback(RxCallback), result.AsyncState);
        }
    }
}

测试:

using NUnit.Framework;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UdpPractice;

namespace UdpTest
{
    [TestFixture ()]
    public class Test
    {
        [Test ()]
        public void TestCase ()
        {
            // Setup Listener
            int port = 14580;
            IPEndPoint locep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), port);
            // Server (Listener)
            UdpCom com = new UdpCom (IPAddress.Any, port);
            // Set up sender
            UdpClient sender = new UdpClient();
            // Dummy Data
            byte [] dummyData = new byte[] {1, 2, 3, 4, 4, 5};
            sender.Send (dummyData, dummyData.Length, locep);
            sender.Send (dummyData, dummyData.Length, locep);
            Thread.Sleep (100);
            Assert.AreEqual(true, com.receiveFlag);
        }
    }
}

我需要让听众收听IPAddress.Any,然后我主要使用Send方法和EndPoint参数。我不得不在那里添加延迟,否则接收标志没有被设置。

【讨论】:

    猜你喜欢
    • 2021-03-31
    • 1970-01-01
    • 2016-08-22
    • 2013-09-06
    • 1970-01-01
    • 2014-03-04
    • 1970-01-01
    • 1970-01-01
    • 2016-07-02
    相关资源
    最近更新 更多