2012-02-04 20 views
18

मैं यूडीपी छेद पंचिंग को पूरा करने की कोशिश कर रहा हूं। मैं अपने सिद्धांत को this article और इस WIKI page पर आधारित कर रहा हूं, लेकिन मुझे इसके सी # कोडिंग के साथ कुछ मुद्दों का सामना करना पड़ रहा है। यहां मेरी समस्या है:यूडीपी छेद पंचिंग कार्यान्वयन

here पोस्ट किए गए कोड का उपयोग करके अब मैं रिमोट मशीन से कनेक्ट करने और आने वाले कनेक्शन (उसी पोर्ट पर 2 यूडीपी क्लाइंट को बांधने) के लिए उसी पोर्ट पर सुन सकता हूं।

किसी कारण से एक ही बंदरगाह के दो बाइंडिंग एक दूसरे को डेटा प्राप्त करने से रोकते हैं। मेरे पास एक यूडीपी सर्वर है जो मेरे कनेक्शन का जवाब देता है, इसलिए अगर मैं पोर्ट से किसी अन्य क्लाइंट को बाध्य करने से पहले इसे कनेक्ट करता हूं तो मुझे इसकी प्रतिक्रियाएं मिलती हैं।

यदि मैं बंदरगाह पर किसी अन्य ग्राहक को बांधता हूं तो किसी भी ग्राहक पर कोई डेटा प्राप्त नहीं होगा।

निम्नलिखित 2 कोड टुकड़े हैं जो मेरी समस्या दिखाते हैं। पहले एनएटी डिवाइस पर नियम बनाने के लिए रिमोट सर्वर से कनेक्ट होता है और फिर आने वाले पैकेट को कैप्चर करने के लिए एक श्रोता को एक अलग थ्रेड पर शुरू किया जाता है। कोड तब स्थानीय आईपी में पैकेट भेजता है ताकि श्रोता इसे प्राप्त कर सके। यह सुनिश्चित करने के लिए दूसरा यह केवल स्थानीय आईपी में पैकेट भेजता है। मुझे पता है कि यह वास्तविक छेद पंचिंग नहीं है क्योंकि मैं एनएटी डिवाइस के बिना अपने पैकेट भेज रहा हूं। मुझे इस बिंदु पर एक समस्या का सामना करना पड़ रहा है, और मुझे कल्पना नहीं है कि अगर मैं कनेक्ट करने के लिए एनएटी डिवाइस के बाहर कंप्यूटर का उपयोग करता हूं तो यह अलग होगा।

[संपादित करें] 2/4/2012 मैंने श्रोता का परीक्षण करने के लिए अपने नेटवर्क और वायरशर्क (पैकेट स्निफर) पर एक और कंप्यूटर का उपयोग करने की कोशिश की। मैं अन्य कंप्यूटर से आने वाले पैकेट देखता हूं लेकिन श्रोता यूडीपी क्लाइंट (udpServer) या प्रेषक यूडीपी क्लाइंट (क्लाइंट) द्वारा प्राप्त नहीं होता है।

[संपादित करें] 2/5/2010 मैंने पोर्ट को सुनने के लिए केवल दूसरे यूडीपी क्लाइंट को केवल आरंभिक भेजने और प्राप्त करने के बाद पहले यूडीपी क्लाइंट को बंद करने के लिए एक फ़ंक्शन कॉल जोड़ा है। यह काम करता है और मैं उस बंदरगाह पर नेटवर्क के अंदर से पैकेट प्राप्त कर सकता हूं। अब मैं नेटवर्क से बाहर पैकेट भेजने और प्राप्त करने की कोशिश करूंगा। जैसे ही मुझे कुछ मिल जाए, मैं अपने निष्कर्ष पोस्ट करूंगा।

इस कोड को मैं सुन क्लाइंट पर डेटा प्राप्त का उपयोग करना:

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(); 
} 

अगर मैं निम्नलिखित कोड का उपयोग, मेरे क्लाइंट और सर्वर के बीच संबंध और डेटा स्थानांतरण के बाद, सुन यूडीपी ग्राहक कुछ भी प्राप्त नहीं होगा:

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(); 
} 
+0

आईपी या पोर्ट के बारे में पैकेट खो जाने पर स्थितियों से निपटने के लिए कैसे करें? – user1914692

उत्तर

1

अद्यतन:

UdpClients की जो भी पहले बांधता है कि भेजा जाएगा विंडोज़ द्वारा आने वाले पैकेट। अपने उदाहरण में कोड ब्लॉक को स्थानांतरित करने का प्रयास करें जो शीर्ष पर सुनने वाले धागे को सेट करता है।

क्या आप सुनिश्चित हैं कि समस्या यह नहीं है कि प्राप्त थ्रेड केवल एक ही प्राप्त करने के लिए लिखा गया है? प्राप्त थ्रेड को नीचे के रूप में बदलने का प्रयास करें।

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

मुझे पहला पैकेट नहीं मिल रहा है। थ्रेड को प्राप्त होने पर अवरुद्ध कर दिया जाता है, थोड़ी देर में प्राप्त करने के लिए काम नहीं करेगा। इसके अलावा, मुझे लगता है कि पैकेट को मेरे पीसी में पैकेट स्निफर में सिर्फ क्लाइंट के लिए नहीं मिल रहा है। क्या आपके पास यूडीपी छेद पंचिंग का एक कामकाजी उदाहरण है? – brooc

+0

बस प्रिंट लाइन पर ब्रेक पॉइंट के साथ कोशिश की और यह कभी नहीं पहुंचता है। – brooc

+0

सिद्धांत में आपको एनएटी में बाध्यकारी बनाने के लिए केवल एक सार्वजनिक सॉकेट से एक सार्वजनिक सॉकेट में एक पैकेट भेजना है। उसके बाद एनएटी को उस सार्वजनिक सॉकेट से निजी सॉकेट में सभी पैकेट पास करना चाहिए (कम से कम बाध्यकारी समय तक जो न्यूनतम X मिनट होना चाहिए)। ऐसा लगता है कि आप यही कर रहे हैं ताकि इसे ठीक काम करना चाहिए। – sipwiz

4

आप 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); 
    } 

मुझे आशा है कि इससे मदद मिलती है।

+0

कॉन्फ़िगर किए जाने पर बाहरी आईपी को सर्वर के दोनों को कहां रखा जाए और सर्वर से कनेक्ट होने पर पीयर एक? –

13

यदि मैं सही ढंग से समझता हूं, तो आप छेद पंचिंग के लिए मध्यस्थता सर्वर का उपयोग करके एक अलग एनएटी के पीछे 2 ग्राहकों के बीच पीयर-टू-पीयर संवाद करने की कोशिश कर रहे हैं?

कुछ साल पहले मैं सी # में सही ऐसा ही किया था, मैं कोड अभी तक नहीं मिला है, लेकिन बीमार यदि आप चाहें तो आप कुछ संकेत दे:

पहले, मैं बंधन का उपयोग नहीं होगा() udpclient पर फ़ंक्शन, चूंकि यूडीपी एक कनेक्शन रहित प्रोटोकॉल है, इसलिए यह सब फ़ंक्शन वास्तव में यूडीपी सॉकेट की कार्यक्षमता को छुपाता है।

आप निम्न चरणों निष्पादित कर देना चाहिए:

  1. खुला एक सर्वर पर UDP सॉकेट के साथ यह है बंदरगाहों फ़ायरवॉल द्वारा, एक विशिष्ट पोर्ट (जैसे बाइंड उदाहरण के लिए एक चुने हुए बंदरगाह को यह सॉकेट में अवरुद्ध नहीं 23000)
  2. पहले क्लाइंट पर यूडीपी सॉकेट बनाएं, और 23000 पर सर्वर को कुछ भेजें। इस सॉकेट को को बाध्य न करें। जब एक यूडीपी को पैकेट भेजने के लिए उपयोग किया जाता है, तो विंडोज स्वचालित रूप से सॉकेट
  3. अन्य क्लाइंट
  4. से ऐसा ही करें। सर्वर को अब 2 अलग-अलग एड्रेस पर 2 अलग-अलग एड्रेस पर 2 क्लाइंट प्राप्त हुए हैं बंदरगाहों। परीक्षण करें कि सर्वर एक ही पते और बंदरगाह पर पैकेट वापस भेज सकता है। (यदि यह काम नहीं करता है तो आपने कुछ गलत किया है या आपका एनएटी काम नहीं कर रहा है। अगर आप बंदरगाहों को खोलने के बिना गेम खेल सकते हैं तो आप इसे काम कर सकते हैं: डी)
  5. सर्वर को अब अन्य क्लाइंट का पता और बंदरगाह भेजना चाहिए प्रत्येक जुड़े ग्राहक को।
  6. एक ग्राहक अब सर्वर से प्राप्त पते पर यूडीपी का उपयोग करके पैकेट भेजने में सक्षम होना चाहिए।

आपको ध्यान रखना चाहिए कि नाट पर प्रयुक्त बंदरगाह शायद आपके क्लाइंट पीसी के समान पोर्ट नहीं है !! सर्वर को इस बाहरी बंदरगाह को ग्राहकों को वितरित करना चाहिए। आपको बाहरी एड्रेस और बाहरी बंदरगाहों को भेजने के लिए उपयोग करना होगा!

यह भी ध्यान दें कि आपका एनएटी इस प्रकार के पोर्ट अग्रेषण का समर्थन नहीं कर सकता है। कुछ एनएटी आपके क्लाइंट को असाइन किए गए बंदरगाह पर आने वाले यातायात को आगे बढ़ाते हैं, जो आप चाहते हैं। लेकिन कुछ नट आने वाले पैकेट एड्रेस पर फ़िल्टरिंग करते हैं ताकि यह अन्य क्लाइंट पैकेट को अवरुद्ध कर सके। मानक व्यक्तिगत उपयोगकर्ता राउटर का उपयोग करते समय यह असंभव है।

+0

आपके उत्तर के लिए धन्यवाद! मुझे इसे एक मौका और देना होगा। मुझे लगता है कि मैंने दोनों दिशाओं में पैकेट भेजने की कोशिश नहीं की हो सकती है ... – brooc

+2

ठीक है, अगर आपको यह काम मिल रहा है तो मुझे बताएं :) एक और बात, क्या मैं सही ढंग से समझता हूं कि आप एक ही बंदरगाह पर एकाधिक सॉकेट बाध्य कर रहे हैं? ज्यादातर मामलों में आपको केवल प्रति पोर्ट एक सॉकेट का उपयोग करना चाहिए, मुझे नहीं पता था कि कई सॉकेट को बाध्य करना संभव था: डी – MHGameWork

2

संपादित करें: बहुत अधिक परीक्षण के बाद यह मेरे लिए बिल्कुल काम नहीं करता है जब तक कि मैं यूपीएनपी सक्षम नहीं करता। इसलिए मैंने यहां लिखी कई चीजें उपयोगी पा सकते हैं लेकिन कई लोगों के पास यूपीएनपी सक्षम नहीं है (क्योंकि यह एक सुरक्षा जोखिम है) इसलिए यह उनके लिए काम नहीं करेगा।

यहां कुछ कोड है जो PubNub को रिले सर्वर के रूप में उपयोग कर रहा है :)। मैं परीक्षण के बिना इस कोड का उपयोग करने की अनुशंसा नहीं करता क्योंकि यह सही नहीं है (मुझे यकीन नहीं है कि यह सुरक्षित है या चीजों को करने का सही तरीका है? Idk मैं नेटवर्किंग विशेषज्ञ नहीं हूं) लेकिन यह आपको एक विचार देना चाहिए क्या करना है यह कम से कम एक शौक परियोजना में मेरे लिए काम किया है। चीजें जो गायब हैं वे हैं:

  • क्लाइंट आपके LAN पर परीक्षण कर रहा है या नहीं। मैं सिर्फ उन दोनों को भेजता हूं जो आपके LAN के लिए काम करते हैं और किसी अन्य नेटवर्क पर एक डिवाइस लेकिन यह बहुत अक्षम है।
  • परीक्षण करते समय क्लाइंट सुनना बंद कर देता है, उदाहरण के लिए, उन्होंने प्रोग्राम बंद कर दिया।चूंकि यह यूडीपी है, यह स्टेटलेस है इसलिए इससे कोई फर्क नहीं पड़ता कि हम शून्य में संदेश भेज रहे हैं, लेकिन हमें शायद ऐसा नहीं करना चाहिए यदि कोई उन्हें
  • प्रोग्रामिंग के लिए पोर्ट अग्रेषण करने के लिए Open.NAT का उपयोग करता है लेकिन यह काम नहीं कर सकता है कुछ उपकरणों पर। विशेष रूप से, यह यूपीएनपी का उपयोग करता है जो थोड़ा असुरक्षित है और मैन्युअल रूप से पोर्ट को अग्रेषित करने के लिए यूडीपी पोर्ट 1 9 00 की आवश्यकता होती है। एक बार ऐसा करने के बाद यह अधिकांश राउटर पर समर्थित है लेकिन कई ने अभी तक यह नहीं किया है।

तो सबसे पहले, आपको अपने बाहरी और स्थानीय आईपी प्राप्त करने का एक तरीका चाहिए। यहाँ अपने स्थानीय आईपी प्राप्त करने के लिए कोड है:

// 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 का उपयोग किया था। सबसे पहले, आप पोर्ट्स की एक सूची डालते हैं जो आपको लगता है कि registered UDP ports को देखने के बाद आपके आवेदन के लिए उपयोग करना उचित होगा।

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 रिले सर्वर कोड के लिए

अब (यहाँ उदाहरण के लिए कुछ कर रहे हैं बाद में पी 2 पीपीर परिभाषित किया जाएगा)। एक बहुत तो मैं वास्तव में करने वाला समझा नहीं कर रहा हूँ, लेकिन उम्मीद है कि कोड काफी स्पष्ट आप समझते हैं कि

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); 
     } 
    } 
} 

है यहाँ नहीं है, यहाँ मेरे सारे usings हैं:

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; 

मैं टिप्पणियों और प्रश्नों के लिए खुला रहा हूँ, अगर कुछ यहाँ बुरी प्रथा है या काम नहीं करता प्रतिक्रिया देने के लिए स्वतंत्र लग रहा है। मेरे कोड से अनुवाद में कुछ बग पेश किए गए थे जिन्हें मैं अंततः ठीक कर दूंगा लेकिन इससे कम से कम आपको यह विचार करना चाहिए कि क्या करना है।