2013-03-17 3 views
17

मेरा मतलब है, struct sockaddr के कौन से क्षेत्र मुझे तुलना करते हैं जब मैं जांचता हूं कि दो struct sockaddr के पास एक ही आईपी पता और पोर्ट नंबर है? और sockaddr_in के बारे में क्या?सी में सॉकेट पते की तुलना कैसे करें?

मैं सिर्फ sockaddr को sockaddr_in डाली, और एक वास्तविक sockaddr की तुलना कर सकते हैं?

उत्तर

11

सबसे पहले आपको परिवार (आईपीवी 4, आईपीवी 6, या अन्य) की जांच करने की आवश्यकता है। फिर आप प्रत्येक सॉकडर को उचित "व्युत्पन्न" प्रकार जैसे sockaddr_in पर डाल सकते हैं। कैसे एप्पल इसे यहाँ करता देखें:, बंद http://www.opensource.apple.com/source/postfix/postfix-197/postfix/src/util/sock_addr.c

+0

क्या आप जानते हैं कि मैक/आईओएस पर 'sock_addr.h' पहले से ही शामिल है या नहीं? – johk95

+0

@ johk95 जैसा कि आप यूआरएल में देख सकते हैं, sock_addr.h और sock_addr.c का स्रोत कोड वास्तव में पोस्टफिक्स प्रोजेक्ट से हैं। – kevin

+0

[हाँ, हम जानते हैं कि ऐप्पल यह कैसे करता है।] (Https://www.imperialviolet.org/2014/02/22/applebug.html) ^^ – Downvoter

0

सबसे पहले जब आप मूल्यों साथ काम कर रहे हैं, तो आप, struct sockaddr_storage उपयोग करने की आवश्यकता के बाद से struct sockaddr संकेत के लिए ही सुरक्षित है, या आप आकार और संरेखण समस्याओं में चलेंगे।

दूसरा, struct sockaddr "बेस क्लास" के लिए सी में क्या गुजरता है। पहला सदस्य sa_family_t sa_family; है (हालांकि, चूंकि यह struct अलग-अलग नामस्थानों में होने वाले संरचना सदस्यों को पूर्व निर्धारित करता है, प्रत्येक "सबक्लास" एक अद्वितीय उपसर्ग का उपयोग करता है (मैं कम से कम 40 उप-वर्गों में आ गया हूं))।

तीसरा - जबकि आप प्रत्येक struct सोच सकते हैं, यह पता चला है कि कक्षा का आकार कर्नेल/लाइब्रेरी संस्करणों के बीच भिन्न होता है। तो, आप हमेशा को sizeof() वास्तविक struct sockaddr_FOO पास करने के लिए पास करना होगा। उदाहरण के लिए, struct sockaddr_in6 के पुराने संस्करणों में sin6_scope_id सदस्य नहीं थे।

आप शायद विवेक के लिए एक struct में इस लपेट करना चाहिए (और विभिन्न सहायक कार्यों प्रदान करते हैं):

struct SocketAddress 
{ 
    struct sockaddr_storage addr; 
    socklen_t addr_len; 
}; 

फिर, अपनी तुलना कोड दिखाई देगा:

// returns < 0 if (left < right) 
// returns > 0 if (left > right) 
// returns 0 if (left == right) 
// Note that in general, "less" and "greater" are not particularly 
// meaningful, but this does provide a strict weak ordering since 
// you probably need one. 
int socket_cmp(struct SocketAddress *left, struct SocketAddress *right) 
{ 
    socklen_t min_addr_len = MIN(left->addr_len, right->addr_len; 
    // If head matches, longer is greater. 
    int default_rv = right->addr_len - left->addr_len; 
    int rv = memcmp(left, right, min_addr_len); 
    return rv ?: default_rv; 
} 

लेकिन रुकिए! जबकि उपरोक्त कोड पर्याप्त है, यदि आप सावधान रहें, तो सावधान रहना अभी भी बहुत सारे विवरणों में शामिल है। उदाहरण के लिए:

  • सभी सॉकेट अपने कार्यक्रम के एक भी रन के भीतर उत्पन्न करने के लिए जा पते दिए गए हैं, या उनमें से कुछ कुछ बाहरी माध्यम से पढ़ा जाएगा? बाद के मामले के लिए, आप sin6_scope_id जैसे मामलों को कैनोनिकल बनाना चाहते हैं।

  • क्या आपको उसी प्रोग्राम में आईपीवी 4 और आईपीवी 4-ऑन-आईपीवी 6 पते (मैप किए गए ffff::1.2.3.4) से निपटना होगा? सबसे आसान तरीका है अपने कार्यक्रम में विशेष रूप से आईपीवी 6 के साथ सौदा करना, क्योंकि प्रासंगिक कार्य आईपीवी 4 पते भी स्वीकार करते हैं। सर्वोत्तम पोर्टेबिलिटी के लिए, सुनिश्चित करें कि अक्षम करें (setsockopt का उपयोग करके) IPV6_V6ONLY ध्वज। वैकल्पिक रूप से, आप यह ध्वज यह सुनिश्चित करने में सहायता के लिए सक्षम कर सकते हैं कि आईपीवी 6 पते में कभी भी आईपीवी 4 पता न हो। (ध्यान दें कि localhost का लुकअप अलग है - लेकिन यह सभी डोमेन लुकअप के लिए एक सामान्य समस्या है, जो एक से अधिक परिणाम लौटा सकता है)।

  • आपको यह सुनिश्चित करने की ज़रूरत है कि सभी स्ट्रक्चर पैडिंग शून्य हो।
संबंधित मुद्दे