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

重用UdpClient还是丢弃它

秋飞鸾
2023-03-14

我正在创建一个聊天应用程序,其中用户在路由器(NAT)后面。所以主要问题是向这些客户端发送消息。服务器接收消息没有问题。

>

  • UdpServer侦听来自客户端A
  • 的udp数据包
  • 服务器客户端A接收数据包并回复数据包以打开NAT
  • 服务器现在变成了客户端(服务器不断向客户端A发送数据包,客户端回复服务器,通知它收到了他的消息)现在NAT打开了,我将客户端和服务器反转。这是因为客户端A总是可以通过tcp向服务器发送消息。

    如果Server看到客户端A没有回复其不断发送的数据包,则将客户端A标记为已断开连接并停止发送数据包。

    // class that holds infor about client
    class ClientBehindNat
    {
         public IPEndPoint EndpointListening;
         public string Id;
    }
    

    侦听新客户端(连接)的线程:

    while(true)
    {
        IPEndPoint ep = new IPEndPoint(IPAddress.Any, 1234);
        // create a new udpServer
        using(var udpServer = new UdpClient())
        {
            // allow reusing port 1234
            udpServer.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            // wait to receive data
            var data = udpServer.Receive(ref ep);
    
            // analyze data make sure it is reliable....
    
            // maybe data is a reply from a client 
            if(data.IsReply())
            {
                 // mark that client replied
                 // ....
                 continue;
            }
            else
            {
                // save new client
                ConnectedClients.Add(new ClientBehindNat(){EndpointListening=ep});
            }
    
            udpServer.Connect(ep);
            udpServer.Send( // data notifying client that we got his message)
    
        }
    }
    

    不断向客户端发送udp数据包以保持nat打开的线程

    // send packets every 15 seconds in order to leave nat open
    timer.elapsed += (a,b)=> {
    
        foreach (var c in connectedClients)
        {
            // create a copy of udp server so that client can get our response
            using (var copySocket = new UdpClient())
            {
                // allow reusing port 1234
                copySocket.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                copySocket.Client.Bind(new IPEndPoint(IPAddress.Any, 1234));
                // log that we will send this request
                // Requests[someId] = ....
    
                // send it
                copySocket.Send(someData, someData.Length, c.EndpointListening);
    
                // first thread should be responsible for receiving this response
    
                // dispose this client                            
            }          
        }
    }
    

    一切都很好,但为每个请求创建一个新的Socket(UdpClient)是不是很糟糕?如果我收到100个请求,我会创建100个新套接字并处理所有这些请求。当我尝试重用udp客户端更新其endpoint时,我遇到了一个异常。我经常需要向Client aClient Z发送消息,这就是我存储其endpoint以了解如何访问它的原因。如何重用udpClient更新其endpoint,以便能够访问我感兴趣的客户端?

  • 共有2个答案

    诸葛阳成
    2023-03-14

    发现问题了。当我回复客户时,我得到的回复是这样的:

    udpServer.Connect(ep); // <---------------- this was the problem
    udpServer.Send(someData);
    

    如果我从不连接并使用@Sourush声明的 SneTo 方法,它使我能够继续侦听数据包。因此,现在我有:

    udpServer.Client.SentTo(data, ep)
    
    吴升
    2023-03-14

    我应该再次推荐直接使用< code>Socket,它给了你很大的灵活性。看看下面的例子,它使用一个套接字进行发送和接收UDP连接:

        private static readonly List<EndPoint> clients = new List<EndPoint>();
        private static readonly SocketAsyncEventArgs receiveEventArgs = new SocketAsyncEventArgs();
        private static Socket socket;
    
        private static void Main(string[] args)
        {
            receiveEventArgs.Completed += OnReceive;
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            socket.Bind(new IPEndPoint(IPAddress.Any, 6000));
            Receive();
    
            while (true)
            {
                Thread.Sleep(3000);
                lock (clients)
                {
                    foreach (var endPoint in clients)
                        socket.SendTo(Encoding.ASCII.GetBytes("PING"), endPoint);
                }
            }
        }
    
        private static void Receive()
        {
            receiveEventArgs.SetBuffer(new byte[256], 0, 256);
            receiveEventArgs.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 6000);
            socket.ReceiveFromAsync(receiveEventArgs);
        }
    
        private static void OnReceive(object sender, SocketAsyncEventArgs e)
        {
            if (e.BytesTransferred > 0)
            {
                // Is reply?
                var isReply = true/false;
                if (isReply)
                {
                    // Do domething
                }
                else
                    lock (clients)
                    {
                        clients.Add(e.RemoteEndPoint);
                    }
            }
            else
            {
                lock (clients)
                {
                    clients.Remove(e.RemoteEndPoint);
                }
            }
            Receive();
        }
    
     类似资料:
    • 除了前一节介绍的权重衰减以外,深度学习模型常常使用丢弃法(dropout)[1] 来应对过拟合问题。丢弃法有一些不同的变体。本节中提到的丢弃法特指倒置丢弃法(inverted dropout)。 方法 回忆一下,“多层感知机”一节的图3.3描述了一个单隐藏层的多层感知机。其中输入个数为4,隐藏单元个数为5,且隐藏单元$h_i$($i=1, \ldots, 5$)的计算表达式为 $$h_i = \p

    • 问题内容: 我正在Linux下编写一个从TCP套接字获取数据的接口。用户提供一个缓冲区,在其中存储接收到的数据。如果提供的缓冲区太小,我只想返回一个错误。第一个问题是确定缓冲区是否过小。recv()函数仅向我返回实际写入缓冲区的字节数。如果我使用recv()联机帮助页上所述的MSG_TRUNC标志,它仍然返回相同的内容。第二个问题是丢弃仍在套接字中排队的数据。因此,如果我确定提供的Buffer很小

    • 这个问题只是为了让我理解这个概念。空值怎么能转换成(可丢弃的)?null不是一个类,对吗?这个问题可能很愚蠢。 我知道:

    • 我正在通过、和进行实时视频处理。 我已经在下面添加了核心代码。 驱动此操作的代码如下所示:

    • 我将事件发送到AWS Kinesis,这些事件由AWS lambda函数处理。但是,如果lambda抛出一些错误,则不会丢弃记录,并且会一次又一次地进行处理,从而阻止处理新记录。 我宁愿跳过错误的记录,消化新的记录。我不知道该怎么做。 lambda函数捕获任何异常,因此不应给出任何执行错误。 下面是python中的片段。 我知道lambda应该在“保留”期间重试(默认为24小时),但我希望放弃并最

    • 似乎都没用。