संयुक्त रूप से आईपीवी 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 एड्रेस स्ट्रक्चर में मतभेदों से निपटने के लिए एक भी बदलाव नहीं करना पड़ा और न ही कोई नया कोड जोड़ना पड़ा।
ध्यान दें कि gethostbyname() रिटर्न sockaddr_in के साथ संगत नहीं है - यह चार-बाइट होस्ट पते पर पॉइंटर्स देता है, पूर्ण सॉकडर उदाहरण नहीं। इस प्रकार, आप h_addr_list [0] फ़ील्ड को IPv6 के लिए sockaddr_in के sin_addr फ़ील्ड में और sockaddr_ipv6 के sin6_addr फ़ील्ड में कॉपी करते हैं। –
@ जोनवाटे: सच है, और यह 'gethostbyname() 'का उपयोग न करने का एक और कारण है। इसके बजाए 'getaddrinfo()' का प्रयोग करें। – Celada
हां, कोड बेस में जहां मेरे पास यह स्वतंत्रता है, यह बेहतर है। –