将两个UDP客户端连接到一个端口(发送和接收)

15

我尝试了来自这个问题的建议,但效果很差。

请...任何帮助将不胜感激!

以下是我的代码:

static void Main(string[] args)
{

    IPEndPoint localpt = new IPEndPoint(IPAddress.Any, 6000);

    UdpClient udpServer = new UdpClient(localpt); 
    udpServer.Client.SetSocketOption(
        SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

    UdpClient udpServer2 = new UdpClient();
    udpServer2.Client.SetSocketOption(
        SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

    udpServer2.Client.Bind(localpt); // <<---------- Exception here
}

1
你遇到了什么异常? - M.Babcock
我收到的异常信息是: “尝试访问被其访问权限禁止的套接字” - brooc
当尝试绑定udpServer实例时,它是否会抛出相同的异常? - M.Babcock
似乎你没有按照问题链接中呈现的同一代码样本进行操作。我看到了IPAddress.Any、6000,但UdpClient udpServer2 = new UdpClient(5000); 呢?为什么你不像这样包裹Try{} catch{} 呢? - MethodMan
@M.Babcock 如果我没记错的话,当使用端点构建时它已经绑定了。无论如何,我尝试在设置套接字选项后立即执行udpServer.Client.Bind(localpt);,但是得到了不同的异常消息:“提供了无效的参数”。 - brooc
显示剩余2条评论
4个回答

33

在绑定之前,您必须设置套接字选项。

    static void Main(string[] args)
    {
        IPEndPoint localpt = new IPEndPoint(IPAddress.Any, 6000);

        UdpClient udpServer = new UdpClient();
        udpServer.Client.SetSocketOption(
            SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        udpServer.Client.Bind(localpt);

        UdpClient udpServer2 = new UdpClient();
        udpServer2.Client.SetSocketOption(
            SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

        udpServer2.Client.Bind(localpt); // <<---------- No Exception here

        Console.WriteLine("Finished.");
        Console.ReadLine();
    }

或者一个更形象的例子:

    static void Main(string[] args)
    {
        IPEndPoint localpt = new IPEndPoint(IPAddress.Loopback, 6000);

        ThreadPool.QueueUserWorkItem(delegate
        {
            UdpClient udpServer = new UdpClient();
            udpServer.ExclusiveAddressUse = false;
            udpServer.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            udpServer.Client.Bind(localpt);

            IPEndPoint inEndPoint = new IPEndPoint(IPAddress.Any, 0);
            Console.WriteLine("Listening on " + localpt + ".");
            byte[] buffer = udpServer.Receive(ref inEndPoint);
            Console.WriteLine("Receive from " + inEndPoint + " " + Encoding.ASCII.GetString(buffer) + ".");
        });

        Thread.Sleep(1000);

        UdpClient udpServer2 = new UdpClient();
        udpServer2.ExclusiveAddressUse = false;
        udpServer2.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        udpServer2.Client.Bind(localpt);

        udpServer2.Send(new byte[] { 0x41 }, 1, localpt);

        Console.Read();
    }

我在这里发布了一个后续问题:https://dev59.com/zmox5IYBdhLWcg3wi0zF - brooc
为什么你在localpt上进行Bind,而在inEndPoint上进行Receive,这两者有什么不同吗?(如果我在localpt上进行Receive,好像也没有问题) - Benjol
使用inEndPoint的接收将导致它保存数据包来自的远程套接字。你可以使用localpt,但是这样你就没有一个简单的方法来知道你绑定到的本地套接字。 - sipsorcery

2

我查找了您的错误信息,并解释了错误的原因。

以下是确切的错误消息和原因WSAEACCES 10013 (MSDN)

权限被拒绝。

试图访问一个被禁止访问的套接字。例如,在没有使用setsockopt(SO_BROADCAST)设置广播权限的情况下,使用广播地址发送数据包。

WSAEACCES错误的另一个可能原因是当调用bind函数(在Windows NT 4.0及其SP4以后的版本中)时,另一个应用程序、服务或内核模式驱动程序已经绑定到具有独占访问权限的相同地址。这种独占访问权限是Windows NT 4.0及其SP4以后的新功能,通过使用SO_EXCLUSIVEADDRUSE选项实现。


谢谢,但我已经找到这个信息了。我的代码使用SocketOptionName.ReuseAddress,我认为它本质上是SO_EXCLUSIVEADDRUSE,但是以.NET的方式实现。似乎需要另一种方法来做到这一点,但我似乎找不到。 - brooc
这将是一个很好的难题.. 我想我也走在了正确的轨道上.. 我会帮忙挖掘更多并尝试编写代码.. 这可能是如此简单,以至于即使最有经验的编码人员也会忽略它.. - MethodMan
谢谢,我已经看了好几天了... 没有运气... 这应该是一个非常简单的事情... 请尝试运行这段代码。 - brooc
当您调试时,本地端口是否显示为0.0.0:6000? - MethodMan
这不会起作用,因为0.0.0实际上不是一个IP地址,但无论如何,我将在下面发布我的发现。不确定另一个人如何声称他们使其工作...这似乎不可能。 - MethodMan

0
即使我更改了代码,以便可以传递IP地址,但我仍然收到相同的错误消息。似乎无法绑定到相同的端口,并且只能使用一个端口。以下是我使用您的示例并将其更改为从我的本地计算机捕获我的IP的示例代码。
        IPAddress ipAddress = Dns.Resolve(Dns.GetHostName()).AddressList[0];
        IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, 11000);

        //IPEndPoint localpt = new IPEndPoint(ipLocalEndPoint);

        UdpClient udpServer = new UdpClient(ipLocalEndPoint);
        udpServer.Client.SetSocketOption(
            SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        udpServer.Connect(ipLocalEndPoint);
        UdpClient udpServer2 = new UdpClient();
        udpServer2.Client.SetSocketOption(
            SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

        udpServer2.Client.Bind(ipLocalEndPoint); // <<---------- Exception here

这将在 Bind() 方法上产生异常.. 抱歉。


一定有办法可以做到这一点。我的目标是创建一个包含UDP打洞的系统。这依赖于我能够在发送数据的同时监听相同的端口... - brooc

0

为了解决UDP应用程序中的WSAEACCESS 10013异常(MSDN),您可以尝试以下方法:

udpServer.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接