Я пытаюсь выполнить перфорирование отверстий UDP. Я основываю свою теорию на эту статью и эту страницу WIKI, но мне приходится сталкиваться с некоторыми проблемами с его кодированием на С#. Вот моя проблема:
Использование опубликованного кода здесь Теперь я могу подключиться к удаленному компьютеру и прослушивать один и тот же порт для входящих подключений (привязать 2 клиента UDP к тот же порт).
По какой-то причине две привязки к одному и тому же порту блокируют друг друга от приема каких-либо данных. У меня есть UDP-сервер, который отвечает на мое соединение, поэтому, если я подключаюсь к нему сначала, прежде чем связывать любого другого клиента с портом, я получаю его ответы назад.
Если я привяжу другого клиента к порту, никакие данные не будут получены ни на одном из клиентов.
Ниже приведены 2 фрагмента кода, которые показывают мою проблему. Первый подключается к удаленному серверу для создания правила на устройстве NAT, а затем прослушиватель запускается в другом потоке для захвата входящих пакетов. Затем код отправляет пакеты на локальный IP-адрес, чтобы слушатель получил его. Второе отправляет пакеты только локальному IP, чтобы убедиться, что это работает. Я знаю, что это не фактическая пробивка отверстий, поскольку я отправляю пакеты себе, не проживая устройство NAT вообще. Я столкнулся с проблемой на данный момент, и я не думаю, что это будет по-другому, если я использую компьютер на стороне устройства NAT для подключения.
[EDIT] 2/4/2012 Я попытался использовать другой компьютер в своей сети и WireShark (пакетный сниффер) для тестирования слушателя. Я вижу пакеты, поступающие с другого компьютера, но не получаемые клиентом UDP-клиента (udpServer) или клиентом UDP-отправителя.
[EDIT] 2/5/2010 Теперь я добавил вызов функции, чтобы закрыть первый клиент UDP после первоначальной отправки и приема пакетов, живущих только вторым клиентом UDP, чтобы прослушивать порт. Это работает, и я могу получать пакеты изнутри сети на этом порту. Теперь я попытаюсь отправить и получить пакеты из-за пределов сети. Я опубликую свои результаты, как только найду что-нибудь.
Используя этот код, я получаю данные о слушающем клиенте:
static void Main(string[] args)
{
IPEndPoint localpt = new IPEndPoint(Dns.Resolve(Dns.GetHostName()).AddressList[0], 4545);
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); //this line will block forever
Console.WriteLine("Receive from " + inEndPoint + " " + Encoding.ASCII.GetString(buffer) + ".");
});
Thread.Sleep(1000);
UdpClient udpServer2 = new UdpClient(6000);
// the following lines work and the data is received
udpServer2.Connect(Dns.Resolve(Dns.GetHostName()).AddressList[0], 4545);
udpServer2.Send(new byte[] { 0x41 }, 1);
Console.Read();
}
Если я использую следующий код, после подключения и передачи данных между моим клиентом и сервером, клиент UDP-прослушивания ничего не получит:
static void Main(string[] args)
{
IPEndPoint localpt = new IPEndPoint(Dns.Resolve(Dns.GetHostName()).AddressList[0], 4545);
//if the following lines up until serverConnect(); are removed all packets are received correctly
client = new UdpClient();
client.ExclusiveAddressUse = false;
client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
client.Client.Bind(localpt);
remoteServerConnect(); //connection to remote server is done here
//response is received correctly and printed to the console
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); //this line will block forever
Console.WriteLine("Receive from " + inEndPoint + " " + Encoding.ASCII.GetString(buffer) + ".");
});
Thread.Sleep(1000);
UdpClient udpServer2 = new UdpClient(6000);
// I expected the following line to work and to receive this as well
udpServer2.Connect(Dns.Resolve(Dns.GetHostName()).AddressList[0], 4545);
udpServer2.Send(new byte[] { 0x41 }, 1);
Console.Read();
}