2010-11-10 12 views
17

मेरे पास आईपीएड्रेस पर बाध्य एक सॉकेट के साथ एक असीमित यूडीपी सर्वर क्लास है। कोई भी, और मैं जानना चाहता हूं कि प्राप्त आईपीएड्रेस किस प्राप्त पैकेट को भेजा गया था (... या प्राप्त हुआ)। ऐसा लगता है कि मैं सिर्फ सॉकेट.लोकलएंडपॉइंट प्रॉपर्टी का उपयोग नहीं कर सकता, क्योंकि यह हमेशा 0.0.0.0 देता है (जो समझ में आता है क्योंकि यह उस के लिए बाध्य है ...)।सी # यूडीपी सॉकेट: रिसीवर पता प्राप्त करें

यहाँ कोड मैं वर्तमान में उपयोग कर रहा हूँ के दिलचस्प भागों हैं: 127.0.0.1:1678 0.0.0.0 करने से

प्राप्त 32 बाइट्स:

private Socket udpSock; 
private byte[] buffer; 
public void Starter(){ 
    //Setup the socket and message buffer 
    udpSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 
    udpSock.Bind(new IPEndPoint(IPAddress.Any, 12345)); 
    buffer = new byte[1024]; 

    //Start listening for a new message. 
    EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0); 
    udpSock.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref newClientEP, DoReceiveFrom, udpSock); 
} 

private void DoReceiveFrom(IAsyncResult iar){ 
    //Get the received message. 
    Socket recvSock = (Socket)iar.AsyncState; 
    EndPoint clientEP = new IPEndPoint(IPAddress.Any, 0); 
    int msgLen = recvSock.EndReceiveFrom(iar, ref clientEP); 
    byte[] localMsg = new byte[msgLen]; 
    Array.Copy(buffer, localMsg, msgLen); 

    //Start listening for a new message. 
    EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0); 
    udpSock.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref newClientEP, DoReceiveFrom, udpSock); 

    //Handle the received message 
    Console.WriteLine("Recieved {0} bytes from {1}:{2} to {3}:{4}", 
         msgLen, 
         ((IPEndPoint)clientEP).Address, 
         ((IPEndPoint)clientEP).Port, 
         ((IPEndPoint)recvSock.LocalEndPoint).Address, 
         ((IPEndPoint)recvSock.LocalEndPoint).Port); 
    //Do other, more interesting, things with the received message. 
} 

जैसा कि बताया जा पहले यह हमेशा की तरह एक लाइन प्रिंट: 12345

और मैं चाहता हूँ यह की तरह कुछ होने के लिए: इस पर किसी भी विचार के लिए, 127.0.0.1:1678 से करने के लिए 127.0.0.1:12345

धन्यवाद

प्राप्त 32 बाइट्स अग्रिम में,! --Adam

अद्यतन

ठीक है, मैं एक समाधान पाया है, हालांकि मुझे यह पसंद नहीं है ... असल में, बजाय एक ही UDP सॉकेट IPAddress.Any करने के लिए बाध्य खोलने की है, मैं बनाने के एक प्रत्येक उपलब्ध आईपीएड्रेस के लिए अद्वितीय सॉकेट। ,

public void Starter(){ 
    buffer = new byte[1024]; 

    //create a new socket and start listening on the loopback address. 
    Socket lSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 
    lSock.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345); 

    EndPoint ncEP = new IPEndPoint(IPAddress.Any, 0); 
    lSock.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref ncEP, DoReceiveFrom, lSock); 

    //create a new socket and start listening on each IPAddress in the Dns host. 
    foreach(IPAddress addr in Dns.GetHostEntry(Dns.GetHostName()).AddressList){ 
     if(addr.AddressFamily != AddressFamily.InterNetwork) continue; //Skip all but IPv4 addresses. 

     Socket s = new Socket(addr.AddressFamily, SocketType.Dgram, ProtocolType.Udp); 
     s.Bind(new IPEndPoint(addr, 12345)); 

     EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0); 
     s.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref newClientEP, DoReceiveFrom, s); 
    } 
} 

इस अवधारणा को, इस कोड को उसी रूप में साथ सबसे बड़ी समस्या यह वर्णन करने के लिए बस है कि प्रत्येक सॉकेट एक ही बफर ... जो आम तौर पर है उपयोग करने के लिए कोशिश कर रहा है: तो, नई स्टार्टर समारोह लगता है कि एक बुरा विचार ...

इसके लिए एक बेहतर समाधान होना चाहिए; मेरा मतलब है, स्रोत और गंतव्य यूडीपी पैकेट हेडर का हिस्सा हैं! ओह ठीक है, मुझे लगता है कि जब तक कुछ बेहतर होता है तब तक मैं इसके साथ जाऊंगा।

उत्तर

14

मैं सिर्फ एक ही समस्या थी (अस्वीकरण मैं कभी नहीं सी # की एक पंक्ति में लिखा है, यह सामान्य रूप में विनसॉक पर लागू होता है)। मुझे प्राप्त पैकेट के गंतव्य पते को पुनर्प्राप्त करने के लिए ReceiveFrom या इसके async रूपों का उपयोग करके कोई रास्ता नहीं दिख रहा है।

हालांकि ...यदि आप ReceiveMessageFrom या उसके रूपों का उपयोग करते हैं, तो आपको ReceiveMessageFrom और EndReceiveMessageFrom के संदर्भ में, SocketAsyncEventArgs की संपत्ति के रूप में ReceiveMessageFromAsync में आपके कॉलबैक में पास किया गया होगा)। उस ऑब्जेक्ट में आईपी पता और इंटरफ़ेस नंबर होगा जिसमें पैकेट प्राप्त हुआ था।

(ध्यान दें, इस कोड का परीक्षण नहीं किया गया है, के रूप में मैं ReceiveMessageFromAsync इस्तेमाल किया बजाय fakey-नकली शुरू/अंत कॉल।)

private void ReceiveCallback(IAsyncResult iar) 
{ 
    IPPacketInformation packetInfo; 
    EndPoint remoteEnd = new IPEndPoint(IPAddress.Any, 0); 
    SocketFlags flags = SocketFlags.None; 
    Socket sock = (Socket) iar.AsyncState; 

    int received = sock.EndReceiveMessageFrom(iar, ref flags, ref remoteEnd, out packetInfo); 
    Console.WriteLine(
     "{0} bytes received from {1} to {2}", 
     received, 
     remoteEnd, 
     packetInfo.Address 
    ); 
} 

ध्यान दें, आप जाहिरा तौर पर स्थापित करने के भाग के रूप SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true) बुलाना चाहिए सॉकेट, Bindयह से पहले। ... ReceiveMessageFrom ... विधियां इसे आपके लिए सेट कर देंगी, लेकिन आप विकल्प को सेट करने के बाद विंडोज़ को देखे गए किसी भी पैकेट पर केवल वैध जानकारी देखेंगे। (प्रैक्टिस में, यह कोई मुद्दा नहीं है - लेकिन जब यह कभी हुआ, तो कारण एक रहस्य होगा। इसे पूरी तरह से रोकने के लिए बेहतर है।)

+0

अब यह परीक्षण किया गया है और यह काम करता है। यह इस विषय पर कई प्रश्नों का सबसे अच्छा जवाब है। मैं ReceiveMessageFromAsync संस्करण को देखने के लिए उत्सुक हूं लेकिन यदि आप उत्तर नहीं देते हैं तो शायद यह मेरे लिए काम कर सकता है। –

+0

@ स्टीफनकेनेडी: मुझे नहीं लगता कि मेरे पास अब भी उस कोड को ईमानदार होने के लिए है। : पी यह बहुत जटिल नहीं है, हालांकि, आईआईआरसी; बस 'SocketAsyncEventArgs' सेट अप करें, एक हैंडलर को अपने' पूर्ण 'ईवेंट से संलग्न करें, फिर ऑब्जेक्ट को' ReceiveMessageFromAsync' पर पास करें। – cHao

+0

कोई चिंता नहीं। मेरे पास SendToAsync() काम कर रहा है, इसलिए ReceiveMessageFromAsync() tmw :) के साथ एक play हो सकता है। –

0

मुझे लगता है कि यदि आप IPAddress के बजाय 127.0.0.1 से जुड़ते हैं। आपको कोई भी व्यवहार मिल जाएगा जो आप चाहते हैं।

0.0.0.0 जानबूझकर "हर आईपी पता उपलब्ध" का अर्थ है और यह आपके बाइंड स्टेटमेंट के परिणामस्वरूप इसे बहुत सचमुच लेता है।

+1

जबकि सच है, मैं 127.0.0.1 (या कोई अन्य विशिष्ट आईपी पता) से जुड़ना नहीं चाहता हूं। अगर मैं अस्पष्ट था, तो मैं क्षमा चाहता हूं, लेकिन आदर्श रूप में, मैं इस यूडीपी सर्वर को कई नेटवर्क एडाप्टर (उन सभी को सुनकर) पर चलाने के लिए चाहता हूं, और मैं जानना चाहता हूं कि कौन सा पैकेट भेजा गया था। – chezy525

-1

एडम

यह परीक्षण नहीं किया है ... की कोशिश

private void DoReceiveFrom(IAsyncResult iar){ 
//Get the received message. 
Socket recvSock = (Socket)iar.AsyncState; 
//EndPoint clientEP = new IPEndPoint(IPAddress.Any, 0); 
Socket clientEP = recvSock.EndAccept(iar); 
int msgLen = recvSock.EndReceiveFrom(iar, ref clientEP); 
byte[] localMsg = new byte[msgLen]; 
Array.Copy(buffer, localMsg, msgLen); 

//Start listening for a new message. 
EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0); 
udpSock.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref newClientEP, DoReceiveFrom, udpSock); 

//Handle the received message 
/* 
Console.WriteLine("Recieved {0} bytes from {1}:{2} to {3}:{4}", 
        msgLen, 
        ((IPEndPoint)recvSock.RemoteEndPoint).Address, 
        ((IPEndPoint)recvSock.RemoteEndPoint).Port, 
        ((IPEndPoint)recvSock.LocalEndPoint).Address, 
        ((IPEndPoint)recvSock.LocalEndPoint).Port); 
//Do other, more interesting, things with the received message. 
*/ 
Console.WriteLine("Recieved {0} bytes from {1}:{2} to {3}", 
        msgLen, 
        ((IPEndPoint)recvSock.RemoteEndPoint).Address, 
        ((IPEndPoint)recvSock.RemoteEndPoint).Port, 
        clientEP.RemoteEP.ToString(); 
} 
+1

धन्यवाद, लेकिन मैं काफी हद तक निश्चित हूं कि यह कोड काम नहीं करेगा, या यहां तक ​​कि संकलित भी नहीं होगा ... आप पहले से शुरू किए बिना एसिंक स्वीकार कॉल (सॉकेट.एंडएसेप्ट) को समाप्त नहीं कर सकते हैं (सॉकेट.बिनजिनएसेप्ट), और स्वीकार करते हुए ' एक कनेक्शन रहित सॉकेट पर समझ में नहीं आता है। साथ ही, सॉकेट.इंडरसेसिव कॉल कॉल को एंडॉइंट के संदर्भ की आवश्यकता होती है, सॉकेट नहीं। – chezy525

0

एक तरह से आपको लगता है कि सॉकेट से कोई पता यह प्रेषक को कनेक्ट करने के लिए किया जाएगा मिल जाएगा करते हैं। एक बार ऐसा करने के बाद, आप स्थानीय पता (या कम से कम, प्रेषक को एक रूटेबल) प्राप्त करने में सक्षम होंगे, हालांकि, आप केवल कनेक्टेड एंडपॉइंट से संदेश प्राप्त कर पाएंगे।

अनकनेक्ट करने के लिए, आपको AF_UNSPEC के परिवार के साथ एक पता निर्दिष्ट करने के लिए फिर से कनेक्ट करने की आवश्यकता होगी। दुर्भाग्यवश, मुझे नहीं पता कि यह सी # में कैसे हासिल किया जाएगा।

:

0

बफर समस्या के संबंध में निम्न प्रयास करें:

किसी भी डेटा को स्टोर करने के लिए स्टेटऑब्जेक्ट नामक एक क्लास बनाएं, जिसमें बफर के साथ, यदि आपको इसकी आवश्यकता हो तो सॉकेट भी शामिल है (जैसा कि मैंने देखा है कि आप वर्तमान में udpSock को अपने राज्य ऑब्जेक्ट के रूप में पास कर रहे हैं)। नव निर्मित ऑब्जेक्ट को async विधि में पास करें और फिर आपके कॉलबैक में इसका उपयोग होगा।

public void Starter(){ 
    StateObject state = new StateObject(); 
    //set any values in state you need here. 

    //create a new socket and start listening on the loopback address. 
    Socket lSock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 
    lSock.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345); 

    EndPoint ncEP = new IPEndPoint(IPAddress.Any, 0); 
    lSock.BeginReceiveFrom(state.buffer, 0, state.buffer.Length, SocketFlags.None, ref ncEP, DoReceiveFrom, state); 

    //create a new socket and start listening on each IPAddress in the Dns host. 
    foreach(IPAddress addr in Dns.GetHostEntry(Dns.GetHostName()).AddressList){ 
     if(addr.AddressFamily != AddressFamily.InterNetwork) continue; //Skip all but IPv4 addresses. 

     Socket s = new Socket(addr.AddressFamily, SocketType.Dgram, ProtocolType.Udp); 
     s.Bind(new IPEndPoint(addr, 12345)); 

     EndPoint newClientEP = new IPEndPoint(IPAddress.Any, 0); 

     StateObject objState = new StateObject(); 
     s.BeginReceiveFrom(objState.buffer, 0, objState.buffer.length, SocketFlags.None, ref newClientEP, DoReceiveFrom, objState); 
    } 
} 

इस सवाल खोज में मैंने पाया:

http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.beginreceivefrom.aspx

फिर आप StateObject AsyncState से के रूप में आप वर्तमान में udpSock और अपने बफर के साथ कर रहे हैं, anyother डेटा आप की जरूरत होगा के रूप में डाली रूप में अच्छी तरह कर सकते हैं वहां संग्रहित रहें।

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