2012-01-12 19 views
19

का उपयोग कर एपीआई मैं कुछ आईपी अज्ञेय कोडिंग करने की कोशिश कर रहा हूं और जैसा कि मैंने sockaddr_storage का उपयोग करने की कोशिश की विभिन्न स्रोतों द्वारा सुझाया गया है। हालांकि सभी एपीआई कॉल (getaddrinfo, getnameinfo) अभी भी स्ट्रक्चर सॉकडर पर निर्भर करते हैं। और उनके बीच कास्टिंग बिल्कुल अच्छा विकल्प नहीं है, जीवीएस कई अन्य समस्याओं में वृद्धि करता है।एपीआई sockaddr_storage

और sockaddr_in और sockaddr_in6 को कास्टिंग अलग-अलग तरह से सॉकड्रर_स्टोरेज का उपयोग करने का प्रयास करने के उद्देश्य से पराजित करता है।

कोई भी जिसने सरल क्लाइंट सर्वर सॉकेट एप्लिकेशन को हटाने में प्रभावी रूप से sockaddr_storage का उपयोग किया है।

उत्तर

23

संयुक्त रूप से आईपीवी 6 और आईपीवी 4 प्रोग्रामिंग करने में समस्या यह है कि एक शुद्ध सॉकडर संरचना स्वयं sockaddr_in6 को पकड़ने के लिए पर्याप्त नहीं है। इसलिए यदि आपको किसी ऐसे पते के चारों ओर अंधेरे से गुज़रने की आवश्यकता है जो या तो sockaddr_in या sockaddr_in6 हो सकता है, तो sockaddr_storage उपयोग करने में थोड़ा आसान है।

दिन के अंत में, चाहे आप sockaddr_in, sockaddr_in6, या sockaddr_storage उपयोग कर रहे हैं, तो आप SendTo recvfrom, कनेक्ट, स्वीकार करने के लिए एक कॉल, और कई अन्य सॉकेट कार्यों बनाने के लिए उन संकेत कास्ट करने के लिए होगा। यह सॉकेट प्रोग्रामिंग का सिर्फ एक ज्ञात ज्ञान है। बस कुछ असुरक्षित करने की भावना को छोड़ दें। आपका कोड ठीक रहेगा।

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

if (addr.ss_family == AF_INET) 
    sendto(sock, buffer, len, 0, (sockaddr*)&addr, sizeof(sockaddr_in)) 
else (addr.ss_family == AF_INET6) 
    sendto(sock, buffer, len, 0, (sockaddr*)&addr, sizeof(sockaddr_in6)); 

और फिर उस प्रकार के "परिवार == AF_INET अगर" अभिव्यक्ति आसानी से अधिक से अधिक खुद को दोहराने के लिए शुरू कर सकते हैं। यही वह है जिसे आप टालना चाहते हैं।

मान लीजिए कि आप सी ++ का उपयोग कर रहे हैं, तो आप पाएंगे कि सॉकेट एड्रेस ऑब्जेक्ट के लिए एक एब्स्ट्रक्शन क्लास अविश्वसनीय रूप से उपयोगी है। मेरे पास github here और here पर एक उदाहरण है। CSocketAddress क्लास का समर्थन {sockaddr, sockaddr_in, sockaddr_in6} के संघ द्वारा किया जाता है और इसे sockaddr_storage के साथ बनाया जा सकता है। अगर मैंने इस कक्षा को शुरू करने से पहले मुझे सॉकड्रर_स्टोरेज के बारे में पता था, तो मैंने यूनियन चीज़ के बजाय इसका इस्तेमाल किया होता। एक "स्वीकार" बयान इस तरह दिखता है

CSocketAddress addr; 
... 
sendto(sock, buffer, len, 0, addr.GetSockAddr(), addr.GetSockAddrLength()); 

इसी तरह,: किसी भी मामले में, यह इस प्रकार के रूप में मेरे कोड लिखने की अनुमति देता

sockaddr_storage addrstorage = {}; 
int len = sizeof(sockaddr_storage); 
accept(sock, (sockaddr*)&addrstorage, &len); 

CSocketAdddress addr(addrstorage); // construct an address object to pass around everywhere else 

इस कोड रास्तों कि बाँध फोन के लिए अविश्वसनीय रूप से मददगार था, भेजें, और recv। अब मेरे STUN सर्वर और क्लाइंट कोड पथ को सॉकेट पते के पारिवारिक प्रकार के बारे में कुछ भी नहीं पता होना चाहिए।वे सिर्फ "CSocketAddress" ऑब्जेक्ट्स के साथ काम करते हैं। एकमात्र आईपीवी 4 और आईपीवी 6 विशिष्ट कोड क्लाइंट और सर्वर प्रारंभिकरण के दौरान होता है - जब पता ऑब्जेक्ट्स वास्तव में निर्मित होते हैं। सौभाग्य से, यह आंशिक रूप से भी बाहर निकाला गया था।

आप सहायक कार्य here पर भी विचार करना चाहेंगे। एक आईपी अज्ञेयवादी तरीके से मेजबाननामों को हल करने, एडाप्टर की गणना आदि के लिए कुछ और उपयोगी चीजें हैं। यह लिनक्स कोड है, लेकिन इसमें से कुछ को विंडोज़ और विंसॉक को ठीक करना चाहिए।

मैं लगभग इस कोड बेस में टीसीपी समर्थन जोड़ रहा हूं। SOCK_STREAM के लिए समर्थन जोड़ने की प्रक्रिया में, मुझे आईपीवी 4 और आईपीवी 6 एड्रेस स्ट्रक्चर में मतभेदों से निपटने के लिए एक भी बदलाव नहीं करना पड़ा और न ही कोई नया कोड जोड़ना पड़ा।

3

मुझे आमतौर पर struct sockaddr_storage की आवश्यकता नहीं दिखाई देती है। इसका उद्देश्य किसी दिए गए प्रोटोकॉल की सॉकड्रर संरचना के लिए पर्याप्त जगह आवंटित करना है, लेकिन आईपी-वर्जन-अज्ञेय कोड में आपको कितनी बार ऐसा करने की आवश्यकता है? आम तौर पर आप getaddrinfo() पर कॉल करते हैं और यह आपको struct sockaddr * एस का गुच्छा देता है, और आपको परवाह नहीं है कि वे sockaddr_in या हैं, तो आप उन्हें bind() और connect() (कोई कास्टिंग आवश्यक नहीं) के साथ पास करते हैं।

विशिष्ट क्लाइंट/सर्वर कोड में, मुख्य स्थान मैं सोच सकता हूं कि struct sockaddr_storage दूसरे पैरामीटर के लिए accept() पर स्थान आरक्षित करना उपयोगी है। इस मामले में मैं सहमत हूं कि इसे struct sockaddr * पर accept() और फिर getnameinfo() के लिए इसे दोबारा डालना है। लेकिन मैं उन जानवरों के चारों ओर एक रास्ता नहीं देख सकता। यह सी संरचना संरचना में हमेशा बहुत सारे कलाकार शामिल होते हैं।

+0

ध्यान दें कि gethostbyname() रिटर्न sockaddr_in के साथ संगत नहीं है - यह चार-बाइट होस्ट पते पर पॉइंटर्स देता है, पूर्ण सॉकडर उदाहरण नहीं। इस प्रकार, आप h_addr_list [0] फ़ील्ड को IPv6 के लिए sockaddr_in के sin_addr फ़ील्ड में और sockaddr_ipv6 के sin6_addr फ़ील्ड में कॉपी करते हैं। –

+0

@ जोनवाटे: सच है, और यह 'gethostbyname() 'का उपयोग न करने का एक और कारण है। इसके बजाए 'getaddrinfo()' का प्रयोग करें। – Celada

+0

हां, कोड बेस में जहां मेरे पास यह स्वतंत्रता है, यह बेहतर है। –