当前位置: 首页 > 知识库问答 >
问题:

是否可能有多个UDP C#套接字具有相同的LocalEndpoint?

令狐新翰
2023-03-14

因此,我可以像为TCP套接字一样为每个客户端创建一个不同的UDP套接字吗?
注意:如果可能,请使用socket类来解释,而不是UDPClient类。

    private void SocketAsyncEventArgs_Completed(object sender, SocketAsyncEventArgs e)
    {
        if (e.SocketError == SocketError.Success)
        {
            switch (e.LastOperation)
            {
                case SocketAsyncOperation.Accept:
                case SocketAsyncOperation.Connect:
                    UDP.Bind(TCP.LocalEndPoint);

代码说明:我以为建立TCP连接(Connect/Accept)后可以在两边(客户机/服务器)绑定一个UDP套接字。对于服务器上只有一个客户机是很好的。对于新客户机,server会引发异常,因为它无法将多个套接字与一个localEndPoint绑定在一起。和客户端可以超过所有可用端口。所以我不能为每个客户端绑定一个UDP套接字到一个不同的localEndPoint。
我知道我可以创建一个唯一的UDP套接字并将接收消息传递给服务器上的相应客户端对象,但这有点麻烦。谢谢!

共有1个答案

漆雕奇逸
2023-03-14

您可以针对唯一的源ip:port组合运行一个任务。这将允许您轻松地为每个唯一的传入源ip:port组合维护一个状态机。system.io.pipelines使将其绑定在一起变得非常容易。

首先设置一个类似于TCPListenerUdpListener任务,为每个新的ip:port升级一个任务以处理该端口,创建一个管道,并且每个时间的数据都来自该IPEndpoint,将数据放入PipeWriter

    static async Task StartUdpListener()
    {
        // Use a Dictionary to match packets from given connections to give Pipes
        ConcurrentDictionary<string, Pipe> connections = new ConcurrentDictionary<string, Pipe>();

        var udpServer = new UdpClient(new IPEndPoint(IPAddress.Any, 33000));
        while (true)
        {
            // Wait for some data to arrive
            var result = await udpServer.ReceiveAsync();

            if(connections.ContainsKey(result.RemoteEndPoint.ToString()))
            {
                // If we have seen this IPEndpoint before send the traffic to the pipe
                // the task associated with that Pipe willpick the traffic up
                connections.TryGetValue(result.RemoteEndPoint.ToString(), out var p);
                await p.Writer.WriteAsync(result.Buffer);
            }
            else
            {
                // If we have not seen it, make the pipe, stick the data in the pipe
                // and spin up a task to Read/Process the data
                var p = new Pipe();
                connections.TryAdd(result.RemoteEndPoint.ToString(), p);
                await p.Writer.WriteAsync(result.Buffer);
                _ = Task.Run(() => UdpServerClient(result.RemoteEndPoint.ToString(), p));
            }
        }
    }

这是内核在接收到TCPPacket时所做的操作的一个简单视图,它将其粘贴在套接字缓冲区中,供您通过流读取。

UDP服务器客户端任务如下所示:

    static async Task UdpServerClient(string serverName,Pipe p)
    {
        while (true)
        {
            var readResult = await p.Reader.ReadAsync();
            var message = Encoding.ASCII.GetString(readResult.Buffer.FirstSpan.ToArray());
            Console.WriteLine($"Server: {serverName} Received: {message}");
            p.Reader.AdvanceTo(readResult.Buffer.End);
        }
    }

为了完整起见,有几个客户机,它们通常在不同的机器上,但为了简单起见,我们将它们作为任务运行。

    static async Task UdpClientClient(string messageToSend)
    {
        var client = new UdpClient();
        client.Connect("127.0.0.1", 33000);
        for(var i=0;i<5;i++)
        {
            var message = ASCIIEncoding.ASCII.GetBytes(messageToSend + " #"+ i.ToString());
            await client.SendAsync(message, message.Length);
            await Task.Delay(1000);
        }
    }
}

将它们全部链接在一起:

    static async Task Main(string[] args)
    {
        _ = Task.Run(() => StartUdpListener());

        _ = UdpClientClient("hi Server!");
        _ = UdpClientClient("I am here server...");
        await UdpClientClient("Me too server!");
    }
Server: 127.0.0.1:53183 Received: Me too server! #0
Server: 127.0.0.1:53182 Received: I am here server... #0
Server: 127.0.0.1:53181 Received: hi Server! #0
Server: 127.0.0.1:53182 Received: I am here server... #1
Server: 127.0.0.1:53183 Received: Me too server! #1
Server: 127.0.0.1:53181 Received: hi Server! #1
Server: 127.0.0.1:53182 Received: I am here server... #2
Server: 127.0.0.1:53183 Received: Me too server! #2
Server: 127.0.0.1:53181 Received: hi Server! #2
Server: 127.0.0.1:53182 Received: I am here server... #3
Server: 127.0.0.1:53181 Received: hi Server! #3
Server: 127.0.0.1:53183 Received: Me too server! #3
Server: 127.0.0.1:53183 Received: Me too server! #4
Server: 127.0.0.1:53181 Received: hi Server! #4
Server: 127.0.0.1:53182 Received: I am here server... #4
 类似资料:
  • 问题内容: 我的MySQL数据库中有这些表: 通用表: Facebook表: 首席表: 基本上,常规表包含一些( 显然 )常规数据。基于generalTable.scenario,您可以在其他两个表中查找更多详细信息,这些表在某些熟悉的列中(例如,expiresAt),而在其他一些列中则不然。 我的问题是,如何仅通过一个查询就可以获取generalTable和正确的明细表的联接数据。 所以,我想这

  • 问题内容: 我们有n个变量,它们没有任何结构。 例如在python中,我可以这样做: 在Java中,我必须这样做: 您知道一种改进此语法的简单方法吗?(想象一下很长的变量名以及很多) 谢谢。 问题答案: 如果您有很多这样的变量,是否考虑过将它们放在集合中,而不是将它们作为单独的变量?此时有多种选择。 如果发现自己经常这样做,则可能要编写辅助方法,可能使用varargs语法。例如: glowcode

  • 问题内容: 我以前用C编写过代码,但是我是Java的新手,我正在为OOP类编写教程,这几乎是我第一次正式学习该语言。 在本教程中,我的教授制作了一个类,该类将用于测试我必须自己做的I / O助手类 (顺便说一句,该教程是(a)可选的,(b)不是用于标记的,所以我是(c)我以前从未使用过Java,而我的许多其他同学都没有使用过Java,所以我落后了)。 无论如何。在他制作的测试类中,他将方法“ ge

  • 我正在使用java。util。ServiceLoader创建轻量级插件框架。 我目前正在努力解决如何拥有多个具有相同FQN的实现类。我想在类路径上拥有同一个插件的两个副本,并且可以访问META-INF/services目录中给出的两个实现类。 以下是一些简单的eclipse项目,它们说明了我的意思:https://docs.google.com/open?id=0B4MxFm-ACB3IUmswN

  • 问题内容: 我是Swift的新手,我已经遍历了一些教程,其中许多教程使用同一个名称多次定义了一个函数。 我已经习惯了其他编程语言,否则将无法执行此操作。 因此,我检查了官方的Swift手册,还检查了override关键字,以了解可以得到的结果,但是仍然无法理解以下代码: 从我看到的函数tableView设置在第1行和第5行,我注意到的唯一区别是第一个tableView函数返回,而第二个函数返回(U

  • 问题内容: 。 我有下表: 我需要用计算所有行。可能与聚合有关吗? 现在,我按如下操作: 问题答案: 如果您只需要对1的行数进行计数,则可以执行以下操作: 如果要计算 每 行的行数,则需要使用: