Подтвердить что ты не робот

Перфорирование отверстий UDP

Я пытаюсь выполнить перфорирование отверстий 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();
}
4b9b3361

Ответ 1

Если я правильно понимаю, вы пытаетесь установить одноранговое соединение между двумя клиентами за другим NAT, используя сервер посредничества для перфорации отверстий?

Несколько лет назад я сделал то же самое в С#, я еще не нашел код, но, если вам нравится, вам нужно указать некоторые указатели:

Во-первых, я бы не использовал функцию Connect() на udpclient, так как UDP - это протокол без установления соединения, вся эта функция действительно скрывает функциональность сокета UDP.

Вы должны выполнить следующие шаги:

  • Откройте сокет UDP на сервере, при этом порты не блокируются брандмауэром на определенном порту (например, привязать этот сокет к выбранному порту, например, 23000)
  • Создайте сокет UDP на первом клиенте и отправьте что-то на сервер с номером 23000. Не привязывайте этот сокет. Когда udp используется для отправки пакета, окна автоматически назначают свободный порт для сокета
  • Сделайте то же самое с другого клиента
  • Теперь сервер получил 2 пакета от 2 клиентов с двумя разными адресами с двумя разными портами. Проверьте, может ли сервер отправлять пакеты обратно на один адрес и порт. (Если это не работает, вы сделали что-то неправильно или ваш NAT не работает. Вы знаете, что он работает, если вы можете играть в игры без открытия портов: D)
  • Теперь сервер должен отправить адрес и порт других клиентов каждому подключенному клиенту.
  • Теперь клиент должен иметь возможность отправлять пакеты, используя UDP, к адресам, полученным с сервера.

Вы должны заметить, что порт, используемый на nat, вероятно, не тот же порт, что и на вашем клиентском ПК!! Сервер должен распространять этот внешний порт для клиентов. Вы должны использовать внешние адреса и внешние порты для отправки на!

Также обратите внимание, что ваш NAT может не поддерживать такую ​​переадресацию портов. Некоторые NAT перенаправляют весь входящий трафик на назначенный порт для вашего клиента, и это то, что вы хотите. Но некоторые фиды фильтруют по входящим адресам пакетов, поэтому могут блокировать другие пакеты клиентов. Это маловероятно, хотя при использовании стандартного персонального маршрутизатора пользователя.

Ответ 2

Вы пытались использовать функции Async, вот пример того, как вы можете заставить его работать, может потребоваться небольшая работа, чтобы сделать его на 100% функциональным:

    public void HolePunch(String ServerIp, Int32 Port)
    {
        IPEndPoint LocalPt = new IPEndPoint(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0], Port);
        UdpClient Client = new UdpClient();
        Client.ExclusiveAddressUse = false;
        Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        Client.Client.Bind(LocalPt);

        IPEndPoint RemotePt = new IPEndPoint(IPAddress.Parse(ServerIp), Port);

        // This Part Sends your local endpoint to the server so if the two peers are on the same nat they can bypass it, you can omit this if you wish to just use the remote endpoint.
        byte[] IPBuffer = System.Text.Encoding.UTF8.GetBytes(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0].ToString());
        byte[] LengthBuffer = BitConverter.GetBytes(IPBuffer.Length);
        byte[] PortBuffer = BitConverter.GetBytes(Port);
        byte[] Buffer = new byte[IPBuffer.Length + LengthBuffer.Length + PortBuffer.Length];
        LengthBuffer.CopyTo(Buffer,0);
        IPBuffer.CopyTo(Buffer, LengthBuffer.Length);
        PortBuffer.CopyTo(Buffer, IPBuffer.Length + LengthBuffer.Length);
        Client.BeginSend(Buffer, Buffer.Length, RemotePt, new AsyncCallback(SendCallback), Client);

        // Wait to receve something
        BeginReceive(Client, Port);

        // you may want to use a auto or manual ResetEvent here and have the server send back a confirmation, the server should have now stored your local (you sent it) and remote endpoint.

        // you now need to work out who you need to connect to then ask the server for there remote and local end point then need to try to connect to the local first then the remote.
        // if the server knows who you need to connect to you could just have it send you the endpoints as the confirmation.

        // you may also need to keep this open with a keepalive packet untill it is time to connect to the peer or peers.

        // once you have the endpoints of the peer you can close this connection unless you need to keep asking the server for other endpoints

        Client.Close();
    }

    public void ConnectToPeer(String PeerIp, Int32 Port)
    {
        IPEndPoint LocalPt = new IPEndPoint(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0], Port);
        UdpClient Client = new UdpClient();
        Client.ExclusiveAddressUse = false;
        Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        Client.Client.Bind(LocalPt);
        IPEndPoint RemotePt = new IPEndPoint(IPAddress.Parse(PeerIp), Port);
        Client.Connect(RemotePt);
        //you may want to keep the peer client connections in a list.

        BeginReceive(Client, Port);
    }

    public void SendCallback(IAsyncResult ar)
    {
        UdpClient Client = (UdpClient)ar.AsyncState;
        Client.EndSend(ar);
    }

    public void BeginReceive(UdpClient Client, Int32 Port)
    {
        IPEndPoint ListenPt = new IPEndPoint(IPAddress.Any, Port);

        Object[] State = new Object[] { Client, ListenPt };

        Client.BeginReceive(new AsyncCallback(ReceiveCallback), State);
    }

    public void ReceiveCallback(IAsyncResult ar)
    {
        UdpClient Client = (UdpClient)((Object[])ar.AsyncState)[0];
        IPEndPoint ListenPt = (IPEndPoint)((Object[])ar.AsyncState)[0];

        Byte[] receiveBytes = Client.EndReceive(ar, ref ListenPt);
    }

Надеюсь, это поможет.

Ответ 3

Изменить: после гораздо большего тестирования это, похоже, не работает для меня, если я не включу UPnP. Поэтому многие вещи, которые я написал здесь, могут оказаться полезными, но многие люди не поддерживают UPnP (потому что это риск безопасности), поэтому они не будут работать для них.

Вот какой код использует PubNub как сервер ретрансляции:). Я не рекомендую использовать этот код без тестирования, потому что он не идеален (я не уверен, что он даже безопасный или правильный способ сделать что-то? Idk Я не эксперт по сети), но он должен дать вам представление о том, что делать. По крайней мере, он работал у меня до сих пор в хобби. Недостатки:

  • Тестирование, если клиент находится в вашей локальной сети. Я просто отправляю оба, которые работают для вашей локальной сети и устройства в другой сети, но это очень неэффективно.
  • Тестирование, когда клиент останавливает прослушивание, если, например, они закрыли программу. Поскольку это UDP, он является апатридом, поэтому не имеет значения, отправляем ли мы сообщения в пустоту, но мы, вероятно, не должны этого делать, если никто не получает их.
  • Я использую Open.NAT для выполнения переадресации портов, но это может не работать на некоторых устройствах. В частности, он использует UPnP, который немного небезопасен и требует, чтобы порт UDP 1900 был перенаправлен в порт вручную. Как только они это сделают, он поддерживается большинством маршрутизаторов, но многие еще этого не сделали.

Итак, прежде всего, вам нужен способ получить свои внешние и локальные IP-адреса. Вот код для получения локального IP:

// From http://stackoverflow.com/questions/6803073/get-local-ip-address
public string GetLocalIp()
{
    var host = Dns.GetHostEntry(Dns.GetHostName());
    foreach (var ip in host.AddressList)
    {
        if (ip.AddressFamily == AddressFamily.InterNetwork)
        {
            return ip.ToString();
        }
    }
    throw new Exception("Failed to get local IP");
}

И вот какой код для получения внешнего IP-адреса через несколько веб-сайтов, предназначенных для возврата внешнего IP-адреса

public string GetExternalIp()
{
    for (int i = 0; i < 2; i++)
    {
        string res = GetExternalIpWithTimeout(400);
        if (res != "")
        {
            return res;
        }
    }
    throw new Exception("Failed to get external IP");
}
private static string GetExternalIpWithTimeout(int timeoutMillis)
{
    string[] sites = new string[] {
      "http://ipinfo.io/ip",
      "http://icanhazip.com/",
      "http://ipof.in/txt",
      "http://ifconfig.me/ip",
      "http://ipecho.net/plain"
    };
    foreach (string site in sites)
    {
        try
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(site);
            request.Timeout = timeoutMillis;
            using (var webResponse = (HttpWebResponse)request.GetResponse())
            {
                using (Stream responseStream = webResponse.GetResponseStream())
                {
                    using (StreamReader responseReader = new System.IO.StreamReader(responseStream, Encoding.UTF8))
                    {
                        return responseReader.ReadToEnd().Trim();
                    }
                }
            }
        }
        catch
        {
            continue;
        }
    }

    return "";

}

Теперь нам нужно найти открытый порт и перенаправить его на внешний порт. Как упоминалось выше, я использовал Open.NAT. Во-первых, вы собрали список портов, которые, по вашему мнению, будут разумными для использования вашим приложением после просмотра зарегистрированных портов UDP. Вот несколько примеров:

public static int[] ports = new int[]
{
  5283,
  5284,
  5285,
  5286,
  5287,
  5288,
  5289,
  5290,
  5291,
  5292,
  5293,
  5294,
  5295,
  5296,
  5297
};

Теперь мы можем пропустить их и, надеюсь, найти тот, который не используется для использования переадресации портов:

public UdpClient GetUDPClientFromPorts(out Socket portHolder, out string localIp, out int localPort, out string externalIp, out int externalPort)
{
  localIp = GetLocalIp();
  externalIp = GetExternalIp();

  var discoverer = new Open.Nat.NatDiscoverer();
  var device = discoverer.DiscoverDeviceAsync().Result;

  IPAddress localAddr = IPAddress.Parse(localIp);
  int workingPort = -1;
  for (int i = 0; i < ports.Length; i++)
  {
      try
      {
          // You can alternatively test tcp with  nc -vz externalip 5293 in linux and
          // udp with  nc -vz -u externalip 5293 in linux
          Socket tempServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
          tempServer.Bind(new IPEndPoint(localAddr, ports[i]));
          tempServer.Close();
          workingPort = ports[i];
          break;
      }
      catch
      {
        // Binding failed, port is in use, try next one
      }
  }


  if (workingPort == -1)
  {
      throw new Exception("Failed to connect to a port");
  }


  int localPort = workingPort;

  // You could try a different external port if the below code doesn't work
  externalPort = workingPort;

  // Mapping ports
  device.CreatePortMapAsync(new Open.Nat.Mapping(Open.Nat.Protocol.Udp, localPort, externalPort));

  // Bind a socket to our port to "claim" it or cry if someone else is now using it
  try
  {
      portHolder = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
      portHolder.Bind(new IPEndPoint(localAddr, localPort));
  }
  catch
  {
      throw new Exception("Failed, someone is now using local port: " + localPort);
  }


  // Make a UDP Client that will use that port
  UdpClient udpClient = new UdpClient(localPort);
  return udpClient;
}

Теперь для кода сервера ретрансляции PubNub (P2PPeer будет определен ниже ниже). Здесь много, поэтому я не собираюсь это объяснять, но, надеюсь, код достаточно ясен, чтобы помочь вам понять, что происходит.

public delegate void NewPeerCallback(P2PPeer newPeer);
public event NewPeerCallback OnNewPeerConnection;

public Pubnub pubnub;
public string pubnubChannelName;
public string localIp;
public string externalIp;
public int localPort;
public int externalPort;
public UdpClient udpClient;
HashSet<string> uniqueIdsPubNubSeen;
object peerLock = new object();
Dictionary<string, P2PPeer> connectedPeers;
string myPeerDataString;

public void InitPubnub(string pubnubPublishKey, string pubnubSubscribeKey, string pubnubChannelName)
{
    uniqueIdsPubNubSeen = new HashSet<string>();
    connectedPeers = new Dictionary<string, P2PPeer>;
    pubnub = new Pubnub(pubnubPublishKey, pubnubSubscribeKey);
    myPeerDataString = localIp + " " + externalIp + " " + localPort + " " + externalPort + " " + pubnub.SessionUUID;
    this.pubnubChannelName = pubnubChannelName;
    pubnub.Subscribe<string>(
        pubnubChannelName,
        OnPubNubMessage,
        OnPubNubConnect,
        OnPubNubError);
    return pubnub;
}

//// Subscribe callbacks
void OnPubNubConnect(string res)
{
    pubnub.Publish<string>(pubnubChannelName, connectionDataString, OnPubNubTheyGotMessage, OnPubNubMessageFailed);
}

void OnPubNubError(PubnubClientError clientError)
{
    throw new Exception("PubNub error on subscribe: " + clientError.Message);
}

void OnPubNubMessage(string message)
{
    // The message will be the string ["localIp externalIp localPort externalPort","messageId","channelName"]
    string[] splitMessage = message.Trim().Substring(1, message.Length - 2).Split(new char[] { ',' });
    string peerDataString = splitMessage[0].Trim().Substring(1, splitMessage[0].Trim().Length - 2);

    // If you want these, I don't need them
    //string peerMessageId = splitMessage[1].Trim().Substring(1, splitMessage[1].Trim().Length - 2);
    //string channelName = splitMessage[2].Trim().Substring(1, splitMessage[2].Trim().Length - 2);


    string[] pieces = peerDataString.Split(new char[] { ' ', '\t' });
    string peerLocalIp = pieces[0].Trim();
    string peerExternalIp = pieces[1].Trim();
    string peerLocalPort = int.Parse(pieces[2].Trim());
    string peerExternalPort = int.Parse(pieces[3].Trim());
    string peerPubnubUniqueId = pieces[4].Trim();

    pubNubUniqueId = pieces[4].Trim();

    // If you are on the same device then you have to do this for it to work idk why
    if (peerLocalIp == localIp && peerExternalIp == externalIp)
    {
        peerLocalIp = "127.0.0.1";
    }


    // From me, ignore
    if (peerPubnubUniqueId == pubnub.SessionUUID)
    {
        return;
    }

    // We haven't set up our connection yet, what are we doing
    if (udpClient == null)
    {
        return;
    }


    // From someone else


    IPEndPoint peerEndPoint = new IPEndPoint(IPAddress.Parse(peerExternalIp), peerExternalPort);
    IPEndPoint peerEndPointLocal = new IPEndPoint(IPAddress.Parse(peerLocalIp), peerLocalPort);

    // First time we have heard from them
    if (!uniqueIdsPubNubSeen.Contains(peerPubnubUniqueId))
    {
        uniqueIdsPubNubSeen.Add(peerPubnubUniqueId);

        // Dummy messages to do UDP hole punching, these may or may not go through and that is fine
        udpClient.Send(new byte[10], 10, peerEndPoint);
        udpClient.Send(new byte[10], 10, peerEndPointLocal); // This is if they are on a LAN, we will try both
        pubnub.Publish<string>(pubnubChannelName, myPeerDataString, OnPubNubTheyGotMessage, OnPubNubMessageFailed);
    }
    // Second time we have heard from them, after then we don't care because we are connected
    else if (!connectedPeers.ContainsKey(peerPubnubUniqueId))
    {
        //bool isOnLan = IsOnLan(IPAddress.Parse(peerExternalIp)); TODO, this would be nice to test for
        bool isOnLan = false; // For now we will just do things for both
        P2PPeer peer = new P2PPeer(peerLocalIp, peerExternalIp, peerLocalPort, peerExternalPort, this, isOnLan);
        lock (peerLock)
        {
            connectedPeers.Add(peerPubnubUniqueId, peer);
        }

        // More dummy messages because why not
        udpClient.Send(new byte[10], 10, peerEndPoint);
        udpClient.Send(new byte[10], 10, peerEndPointLocal);


        pubnub.Publish<string>(pubnubChannelName, connectionDataString, OnPubNubTheyGotMessage, OnPubNubMessageFailed);
        if (OnNewPeerConnection != null)
        {
            OnNewPeerConnection(peer);
        }
    }
}

//// Publish callbacks
void OnPubNubTheyGotMessage(object result)
{

}

void OnPubNubMessageFailed(PubnubClientError clientError)
{
    throw new Exception("PubNub error on publish: " + clientError.Message);
}

И вот P2PPeer

public class P2PPeer
{
    public string localIp;
    public string externalIp;
    public int localPort;
    public int externalPort;
    public bool isOnLan;

    P2PClient client;

    public delegate void ReceivedBytesFromPeerCallback(byte[] bytes);

    public event ReceivedBytesFromPeerCallback OnReceivedBytesFromPeer;


    public P2PPeer(string localIp, string externalIp, int localPort, int externalPort, P2PClient client, bool isOnLan)
    {
        this.localIp = localIp;
        this.externalIp = externalIp;
        this.localPort = localPort;
        this.externalPort = externalPort;
        this.client = client;
        this.isOnLan = isOnLan;



        if (isOnLan)
        {
            IPEndPoint endPointLocal = new IPEndPoint(IPAddress.Parse(localIp), localPort);
            Thread localListener = new Thread(() => ReceiveMessage(endPointLocal));
            localListener.IsBackground = true;
            localListener.Start();
        }

        else
        {
            IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(externalIp), externalPort);
            Thread externalListener = new Thread(() => ReceiveMessage(endPoint));
            externalListener.IsBackground = true;
            externalListener.Start();
        }
    }

    public void SendBytes(byte[] data)
    {
        if (client.udpClient == null)
        {
            throw new Exception("P2PClient doesn't have a udpSocket open anymore");
        }
        //if (isOnLan) // This would work but I'm not sure how to test if they are on LAN so I'll just use both for now
        {
            client.udpClient.Send(data, data.Length, new IPEndPoint(IPAddress.Parse(localIp), localPort));
        }
        //else
        {
            client.udpClient.Send(data, data.Length, new IPEndPoint(IPAddress.Parse(externalIp), externalPort));
        }
    }

    // Encoded in UTF8
    public void SendString(string str)
    {
        SendBytes(System.Text.Encoding.UTF8.GetBytes(str));
    }


    void ReceiveMessage(IPEndPoint endPoint)
    {
        while (client.udpClient != null)
        {
            byte[] message = client.udpClient.Receive(ref endPoint);
            if (OnReceivedBytesFromPeer != null)
            {
                OnReceivedBytesFromPeer(message);
            }
            //string receiveString = Encoding.UTF8.GetString(message);
            //Console.Log("got: " + receiveString);
        }
    }
}

Наконец, вот все мои сообщения:

using PubNubMessaging.Core; // Get from PubNub GitHub for C#, I used the Unity3D library
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

Я открыт для комментариев и вопросов, не стесняйтесь давать отзывы, если что-то здесь плохое или не работает. Несколько ошибок были введены в переводе с моего кода, который я исправлю здесь в конце концов, но это должно по крайней мере дать вам представление о том, что делать.

Ответ 4

Update:

Независимо от того, что связывается с UdpClients, это тот, который будет отправлен входящими пакетами Windows. В вашем примере попробуйте переместить блок кода, который устанавливает поток прослушивания вверх.

Вы уверены, что проблема заключается не только в том, что поток приема написан только для обработки одного приема? Попробуйте заменить принимаемый поток следующим образом.

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 + ".");

    while (inEndPoint != null)
    {
        byte[] buffer = udpServer.Receive(ref inEndPoint);
        Console.WriteLine("Bytes received from " + inEndPoint + " " + Encoding.ASCII.GetString(buffer) + ".");
    }
});