2008-09-08 24 views
21

मैं सीसी में सॉकेट कैसे काम करते हैं?

में सॉकेट प्रोग्रामिंग के बारे में थोड़ा उलझन में हूं, आप एक सॉकेट बनाते हैं, इसे इंटरफ़ेस और आईपी पते से बांधते हैं और इसे सुनने के लिए प्राप्त करते हैं। मुझे उस पर कुछ वेब संसाधन मिले, और इसे ठीक समझा। विशेष रूप से, मुझे बहुत जानकारीपूर्ण होने के लिए एक लेख Network programming under Unix systems मिला।

मुझे सॉकेट पर आने वाले डेटा का समय क्या है भ्रमित करता है।

आप कैसे कह सकते हैं कि पैकेट कब आते हैं, और पैकेट कितना बड़ा है, क्या आपको अपने आप को भारी उठाना है?

मेरी मूल धारणा यह है कि पैकेट चरम लंबाई का हो सकता है, इसलिए एक बार बाइनरी डेटा सॉकेट को दिखने लगते हैं, तो आप उस से पैकेट बनाने के लिए कैसे शुरू करते हैं?

उत्तर

17

संक्षिप्त उत्तर यह है कि आपको अपने आप को भारी उठाना है। आपको अधिसूचित किया जा सकता है कि पढ़ने के लिए डेटा उपलब्ध है, लेकिन आपको नहीं पता होगा कि कितने बाइट उपलब्ध हैं। चरम लंबाई पैकेट का उपयोग करने वाले अधिकांश आईपी प्रोटोकॉल में, पैकेट पर निर्धारित ज्ञात निश्चित लंबाई वाला हेडर होगा। इस हेडर में पैकेट की लंबाई होगी। आप हेडर पढ़ते हैं, पैकेट की लंबाई प्राप्त करते हैं, फिर पैकेट पढ़ें। संचार पूरा होने तक आप इस पैटर्न को दोहराएं (हेडर पढ़ें, फिर पैकेट पढ़ें)।

सॉकेट से डेटा पढ़ने पर, आप बाइट्स की एक निश्चित संख्या का अनुरोध करते हैं। रीड कॉल तब तक अवरुद्ध हो सकता है जब तक बाइट्स की अनुरोधित संख्या पढ़ी न जाए, लेकिन यह अनुरोध किए गए से कम बाइट वापस कर सकता है। जब ऐसा होता है, तो आप शेष बाइट्स का अनुरोध करते हुए, बस पढ़ना पुनः प्रयास करें।

यहाँ एक सॉकेट से बाइट्स की एक निर्धारित संख्या को पढ़ने के लिए एक विशिष्ट सी समारोह है:

/* buffer points to memory block that is bigger than the number of bytes to be read */ 
/* socket is open socket that is connected to a sender */ 
/* bytesToRead is the number of bytes expected from the sender */ 
/* bytesRead is a pointer to a integer variable that will hold the number of bytes */ 
/*   actually received from the sender. */ 
/* The function returns either the number of bytes read, */ 
/*        0 if the socket was closed by the sender, and */ 
/*       -1 if an error occurred while reading from the socket */ 
int readBytes(int socket, char *buffer, int bytesToRead, int *bytesRead) 
{ 
    *bytesRead = 0; 
    while(*bytesRead < bytesToRead) 
    { 
     int ret = read(socket, buffer + *bytesRead, bytesToRead - *bytesRead); 
     if(ret <= 0) 
     { 
      /* either connection was closed or an error occurred */ 
      return ret; 
     } 
     else 
     { 
      *bytesRead += ret; 
     } 
    } 
    return *bytesRead; 
} 
+0

बंद कनेक्शन के बाद प्रारंभिक वापसी नहीं होनी चाहिए "बाइट्स वापसी करें;" "रिटर्न रिट" के बजाय? मुझे लगता है कि readBytes फ़ंक्शन का मतलब बाइट्स की वास्तविक संख्या को वापस करने के लिए है। मुझे लगता है कि यदि कोई त्रुटि हो तो आप इसे गैर-पॉजिटिव पूर्णांक वापस करने के लिए परिभाषित कर सकते हैं, लेकिन आप यह भी पता लगा सकते हैं कि रीडबेट्स अनुरोध से अनुरोध की गई बाइट्स की एक अलग संख्या देता है या नहीं। –

+0

त्रुटि प्रोग्राम को ध्वजांकित करने के लिए ऋणात्मक मान सी प्रोग्रामिंग में सामान्य प्रथा है और एपीआई के उपयोगकर्ता द्वारा भ्रम को रोकने के लिए जितना संभव हो उतना पालन किया जाना चाहिए। – Guss

+0

मैंने पढ़ने के दौरान त्रुटि होने पर बाइट्स की संख्या को वापस करने के लिए मेरे उदाहरण फ़ंक्शन को संशोधित किया। सॉकेट के साथ ध्यान में रखने के लिए एक बिंदु यह है कि शून्य पढ़ने वाला एक पाठ इंगित करता है कि कनेक्शन बंद था, और यह आवश्यक रूप से एक त्रुटि नहीं हो सकती है। – dfjacobs

3

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

1

सॉकेट कच्चे पैकेट की तुलना में उच्च स्तर पर संचालित होते हैं - यह एक फ़ाइल की तरह है जिसे आप पढ़/लिख सकते हैं। साथ ही, जब आप किसी सॉकेट से पढ़ने का प्रयास करते हैं, तो ऑपरेटिंग सिस्टम आपकी प्रक्रिया को तब तक अवरुद्ध कर देगा जब तक कि अनुरोध पूरा करने के लिए डेटा न हो।

+1

यह केवल तभी सच है जब सॉकेट गैर-अवरुद्ध होने के लिए सेट नहीं है। –

13

तो, आपके सवाल का जवाब आप अपने परिवहन के रूप में TCP या UDP का उपयोग कर रहे हैं, इस पर एक निष्पक्ष बिट निर्भर करता है।

यूडीपी के लिए, जीवन बहुत आसान हो जाता है, जिसमें आप अपने इच्छित पैकेट आकार के साथ आरईवी/रिकवर्म/रिकव्सग को कॉल कर सकते हैं (आप संभवतः स्रोत से निश्चित लंबाई वाले पैकेट भेज सकते हैं), और यह धारणा करें कि यदि डेटा उपलब्ध है, तो यह पैकेट-लंबाई आकार के गुणकों में है। (आईई आप अपने भेजने वाले साइड पैकेट के आकार के साथ आरईवी * कहते हैं, और आप सेट हैं।)

टीसीपी के लिए, जीवन थोड़ा और दिलचस्प हो जाता है - इस स्पष्टीकरण के उद्देश्य के लिए, मुझे लगता है कि आप पहले से ही जानते हैं सॉकेट(), बाइंड(), सुनो() और स्वीकार() को कैसे उपयोग करें - बाद में यह है कि आप अपने नव निर्मित कनेक्शन के फ़ाइल डिस्क्रिप्टर (एफडी) कैसे प्राप्त करते हैं।

सॉकेट - अवरुद्ध करने के लिए I/O करने के दो तरीके हैं, जिसमें आप पढ़ते हैं (fd, buf, n) और पढ़ना वहां बैठता है और तब तक प्रतीक्षा करता है जब तक आपने एन बाइट्स को buf में पढ़ा नहीं है - या गैर-अवरुद्ध, जिसमें आपको जांचना है (चयन() या मतदान() का उपयोग करना) चाहे एफडी पठनीय हो, और फिर आपका पढ़ा जाए()।

टीसीपी-आधारित कनेक्शन से निपटने पर, ओएस पैकेट आकारों पर ध्यान नहीं देता है, क्योंकि इसे डेटा की निरंतर स्ट्रीम माना जाता है, अलग-अलग पैकेट आकार वाले भाग नहीं।

यदि आपका एप्लिकेशन "पैकेट" (पैक या अनपॅक किए गए डेटा संरचनाओं का उपयोग करता है जो आप पास कर रहे हैं) का उपयोग करते हैं, तो आपको उचित आकार तर्क के साथ पढ़ने() को कॉल करने में सक्षम होना चाहिए, और सॉकेट से एक संपूर्ण डेटा संरचना को पढ़ना चाहिए समय पर। यदि आप स्रोत और गंतव्य प्रणाली अलग-अलग बाइट एंडियन-नेस के मामले में हैं, तो आपको केवल एक ही चेतावनी के साथ निपटना है, जिसे आप भेज रहे हैं, ठीक से बाइट-ऑर्डर करना याद रखना है। यह यूडीपी और टीसीपी दोनों पर लागू होता है।

जहां तक ​​* निक्स सॉकेट प्रोग्रामिंग का संबंध है, मैं अत्यधिक डब्ल्यू रिचर्ड स्टीवंस की "यूनिक्स नेटवर्क प्रोग्रामिंग, वॉल्यूम 1" (यूएनपीवी 1) और "यूनिक्स पर्यावरण में उन्नत प्रोग्रामिंग" (एपीयूई) की अत्यधिक अनुशंसा करता हूं। पहला नेटवर्क आधारित प्रोग्रामिंग के संबंध में एक टोम है, चाहे परिवहन के बावजूद, और बाद वाला एक अच्छी तरह से प्रोग्रामिंग पुस्तक है क्योंकि यह * NIX आधारित प्रोग्रामिंग पर लागू होता है। इसके अलावा, "टीसीपी/आईपी इलस्ट्रेटेड", वॉल्यूम्स 1 और 2.