Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 重用UdpClient与处置它_C#_Sockets_Endpoint_Hole Punching - Fatal编程技术网

C# 重用UdpClient与处置它

C# 重用UdpClient与处置它,c#,sockets,endpoint,hole-punching,C#,Sockets,Endpoint,Hole Punching,我正在创建一个聊天应用程序,其中用户位于路由器(NAT)后面。因此,主要问题是向这些客户发送消息。服务器在接收消息时没有问题 这是我的协议(规则): UdpServer侦听来自客户端a的udp数据包 服务器从客户端A接收数据包,并用数据包回复以打开NAT 服务器现在成为客户机(服务器不断向客户机a发送数据包,客户机回复服务器,通知它收到了他的消息)我在NAT打开后反转客户机和服务器。这是因为客户端A始终可以通过tcp向服务器发送消息 如果服务器发现客户端A没有回复其不断发送的数据包,则会将客户端

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

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

  • 如果
    服务器
    发现
    客户端A
    没有回复其不断发送的数据包,则会将
    客户端A
    标记为断开连接,并停止发送数据包

  • 这是密码 侦听新客户端(连接)的线程:

    持续向客户端发送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                            
            }          
        }
    }
    
    这就是问题所在
    一切都很好但是为每个请求创建一个新套接字(UdpClient)是否不好?如果我收到100个请求,我将创建100个新套接字并处理所有这些请求。当我尝试重用udp客户端更新其端点时,会出现异常。我经常需要向
    客户机a
    客户机Z
    发送消息,这就是我存储其端点以了解如何到达它的原因如何重新使用udpClient更新其端点,以便能够访问我感兴趣的客户端?

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

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

    我应该再次推荐直接使用
    Socket
    s,它给了您很大的灵活性。查看以下示例,该示例将一个套接字用于发送和接收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();
        }
    
    private static readonly List clients=new List();
    私有静态只读SocketAsyncEventArgs receiveEventArgs=new-SocketAsyncEventArgs();
    专用静态插座;
    私有静态void Main(字符串[]args)
    {
    receiveEventArgs.Completed+=OnReceive;
    套接字=新套接字(AddressFamily.InterNetwork、SocketType.Dgram、ProtocolType.Udp);
    socket.SetSocketOption(SocketOptionLevel.socket,SocketOptionName.ReuseAddress,true);
    socket.Bind(新的IPEndPoint(IPAddress.Any,6000));
    接收();
    while(true)
    {
    睡眠(3000);
    锁定(客户端)
    {
    foreach(客户端中的var端点)
    SendTo(Encoding.ASCII.GetBytes(“PING”),端点);
    }
    }
    }
    私有静态void Receive()
    {
    receiveEventArgs.SetBuffer(新字节[256],0,256);
    receiveEventArgs.RemoteEndPoint=新的IPEndPoint(IPAddress.Any,6000);
    socket.ReceiveFromAsync(receiveEventArgs);
    }
    私有静态void OnReceive(对象发送方,SocketAsyncEventArgs e)
    {
    如果(例如,ByTestTransferred>0)
    {
    //你的回答是什么?
    var isReply=真/假;
    如果(isReply)
    {
    //做事
    }
    其他的
    锁定(客户端)
    {
    clients.Add(如RemoteEndPoint);
    }
    }
    其他的
    {
    锁定(客户端)
    {
    删除(例如RemoteEndPoint);
    }
    }
    接收();
    }
    
    为什么不更改
    c
    的值,而不是创建一个新的
    UdpClient
    ?该方法是否出现异常?由于某种原因,如果我更改端点的值,客户端将不会接收数据包。也许我做错了什么,继续尝试。我建议转到
    Socket
    ,尤其是
    SendTo
    方法。
    udpServer.Connect(ep); // <---------------- this was the problem
    udpServer.Send(someData);
    
    udpServer.Client.SentTo(data, ep)
    
        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();
        }