【发布时间】:2018-05-06 12:59:40
【问题描述】:
我正在创建一个聊天应用程序,其中用户位于路由器 (NAT) 后面。所以主要问题是向这些客户发送消息。服务器接收消息没有问题。
这是我的协议(规则):
-
UdpServer监听来自client A的 udp 数据包 -
Server接收到来自client A的数据包并回复一个数据包以打开 NAT Server现在成为客户端(服务器不断向client A发送数据包,客户端回复服务器,通知它收到了他的消息)我现在反转客户端和服务器,因为 NAT已打开。这是因为client A总是可以通过tcp向服务器发送消息。如果
Server看到client A没有回复它不断发送的数据包,它会将client 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 客户端时,我得到一个异常。我经常需要向Client A 或Client Z 发送消息,这就是为什么我存储它的端点以知道如何到达它。 如何重复使用更新其端点的 udpClient 以便能够访问我感兴趣的客户端?
【问题讨论】:
-
为什么不改变
c的值而不是创建一个新的UdpClient呢?你用那个方法有什么异常吗? -
由于某种原因,如果我更改端点的值,客户端不会收到数据包。也许我做错了什么要继续努力。
-
我建议转移到
Socket,尤其是SendTo方法。
标签: c# sockets endpoint hole-punching