2013-07-18 10 views
18

में एएसओ सॉकेट ऑब्जेक्ट I C++ 11 सुविधाओं के साथ boost :: asio का उपयोग करके एक्सप्लोर कर रहा हूं। विशेष रूप से, मैं एक उदाहरण "async_tcp_echo_server.cpp" कहा जाता है पर ध्यान केंद्रित कर रहा हूँ, यहाँ (कोड भी मेरे सवाल के अंत में दिखाया गया है) स्थित:दोहराया गया std :: एक बूस्ट पर चाल :: सी ++ 11

http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/example/cpp11/echo/async_tcp_echo_server.cpp

मेरा प्रश्न server की tcp::socket सदस्य socket_ शामिल कक्षा। do_accept()server वर्ग की विधि, socket_async_accept() पर पास की गई है। (एएसओ दस्तावेज के अनुसार, async_accept() को इसके पहले पैरामीटर के रूप में, socket कनेक्शन को स्वीकार करने के लिए आवश्यक है।) अब तक, बहुत अच्छा है।

अगला पैरामीटर, एसिंक्रोनस स्वीकृति ऑपरेशन के लिए कॉलबैक, एक लैम्ब्डा फ़ंक्शन है। लैम्ब्डा का शरीर एक नया session ऑब्जेक्ट बनाता है, जिसके निर्माता को भी socket की आवश्यकता होती है। दिलचस्प बात यह है कि socket वस्तुओं की प्रतिलिपि नहीं बनाई जा सकती है; इसलिए उदाहरण में, socket_ ऑब्जेक्ट, जो server ऑब्जेक्ट का सदस्य है, std::move() का उपयोग करके पारित किया गया है।

मैं समझता हूं कि "एक और केवल" socket_ ऑब्जेक्ट (जो server ऑब्जेक्ट का "स्थायी" सदस्य है) session ऑब्जेक्ट में "स्थानांतरित" हो गया है। ठीक - socket ऑब्जेक्ट कॉपी नहीं किया गया है, लेकिन ले जाया गया - सबको खुश है।

लेकिन async_accept() पर अगली कॉल पर क्या होता है? क्या वही socket_ (server का सदस्य) है, जिसे पहले स्थानांतरित किया गया था, फिर से पारित किया गया था? जब हम एक सदस्य को "स्थानांतरित" करते हैं, तो पीछे क्या बचा है? क्या असीमित socket ऑब्जेक्ट्स का जादुई फव्वारा है?

या यहां कुछ वास्तव में कम से कम स्पष्ट हो रहा है? जब socketsession में ले जाया जाता, की सामग्री है (server की socket_ सदस्य) वस्तु "पीछे छोड़ दिया/से चले गए" की सामग्री के साथ बदली 'नई' session वस्तु के अपने "नहीं अभी तक का निर्माण" socket_ सदस्य? क्या मैं भी समझ में आता हूं?

सारांश

कोड नीचे है। कार्यक्रम प्रवाह काफी सरल है। main() एक एकल server ऑब्जेक्ट बनाता है। serverasync_accept() पर बार-बार कॉल करता है। प्रत्येक async_accept() कॉलबैक एक नया session ऑब्जेक्ट बनाता है, प्रत्येक एक (ताजा?) socket के साथ बनाया गया है। सभी "ताजा" socket ऑब्जेक्ट्स कहां से आते हैं, यदि वे (0) server में उसी socket_ सदस्य से (बार-बार) "स्थानांतरित" होते हैं?

#include <cstdlib> 
#include <iostream> 
#include <memory> 
#include <utility> 
#include <boost/asio.hpp> 

using boost::asio::ip::tcp; 

class session 
: public std::enable_shared_from_this<session> 
{ 
public: 
    session(tcp::socket socket) 
    : socket_(std::move(socket)) 
    {} 

    void start() { 
     do_read(); 
    } 

private: 
    void do_read() { 
     auto self(shared_from_this()); 
     socket_.async_read_some(
      boost::asio::buffer(data_, max_length), 
      [this, self](boost::system::error_code ec, std::size_t length) 
      { 
       if(!ec) { 
        do_write(length); 
       } 
      } 
     ); 
    } 

    void do_write(std::size_t length) { 
     auto self(shared_from_this()); 
     boost::asio::async_write(
      socket_, 
      boost::asio::buffer(data_, length), 
      [this, self](boost::system::error_code ec, std::size_t /*length*/) 
      { 
       if(!ec) { 
        do_read(); 
       } 
      } 
     ); 
    } 

    tcp::socket socket_; 
    enum { max_length = 1024 }; 
    char data_[max_length]; 
}; 


class server { 
public: 
    server(boost::asio::io_service& io_service, short port) 
    : acceptor_(io_service, tcp::endpoint(tcp::v4(), port)) 
    , socket_(io_service) 
    { 
     do_accept(); 
    } 

private: 
    void do_accept() { 
     acceptor_.async_accept(
      socket_, 
      [this](boost::system::error_code ec) 
      { 
       if(!ec) { 
        std::make_shared<session>(std::move(socket_))->start(); // is this a *swap* of socket_ ??? 
       } 

       do_accept(); 
      } 
     ); 
    } 

    tcp::acceptor acceptor_; 
    tcp::socket socket_; 
}; 


int main(int argc, char* argv[]) { 
    try { 
     if(argc != 2) { 
      std::cerr << "Usage: async_tcp_echo_server <port>\n"; 
      return 1; 
     } 

     boost::asio::io_service io_service; 

     server s(io_service, std::atoi(argv[1])); 

     io_service.run(); 

    } catch(std::exception& e) { 
     std::cerr << "Exception: " << e.what() << "\n"; 
    } 

    return 0; 
} 

उत्तर

3

ले जाएं अर्थशास्त्र को संसाधनों के स्वामित्व के रूप में माना जा सकता है। संसाधन अधिग्रहण तत्काल है (आरएआईआई) ऑब्जेक्ट निर्माण के समय संसाधनों के स्वामित्व को आवंटित करने और विनाश पर उन संसाधनों को जारी करने की अवधारणा है। अर्थशास्त्र को ले जाएं निर्माण और विनाश के अलावा अन्य समय संसाधनों के स्वामित्व के हस्तांतरण के लिए अनुमति दें।

इस मामले में, ऑब्जेक्ट (सर्वर :: सॉकेट_) सर्वर :: ओएस सॉकेट संसाधन के स्वामित्व के हस्तांतरण के प्राप्तकर्ता को प्राप्तकर्ता प्राप्तकर्ता है। यह हस्तांतरण किसी बिंदु पर async_accept() रिटर्न के बाद होता है, जब कोई क्लाइंट कनेक्ट होता है। नए जुड़े सॉकेट संसाधन सॉकेट_ में स्थानांतरित हो जाते हैं, और कॉलबैक लैम्ब्डा फ़ंक्शन को कॉल किया जाता है। लैम्ब्डा के दौरान, सॉकेट संसाधन सत्र :: सॉकेट_ में स्थानांतरित हो जाते हैं। सर्वर :: socket_ केवल माइक्रोसॉन्ड के एक अंश के लिए संसाधन का स्वामित्व है।

ले जाएं अर्थशास्त्र ने आरआईएए कक्षाओं को किसी भी संसाधन के स्वामित्व वाली संपार्श्विक स्थिति में मौजूद होने की अनुमति दी है। रिलीज करने के लिए कॉल के बाद एक unique_ptr के बारे में सोचें। (यह किसी भी स्मृति को संदर्भित नहीं करता है।) सर्वर :: socket_ आगे बढ़ने के बाद भी संसाधन को पकड़ने के लिए स्थान है, लेकिन इस पल के लिए इसका कुछ भी नहीं है।

लैम्ब्डा फ़ंक्शन की आखिरी चीज़ कॉल do_accept है, जो async_accept() को फिर से कॉल करती है। Socket_ का संदर्भ पारित किया जाता है। जब कोई अन्य क्लाइंट भविष्य में किसी बिंदु पर कनेक्ट होता है, async_accept() वहां एक नए कनेक्टेड ओएस सॉकेट के स्वामित्व को स्थानांतरित कर देगा।

+0

प्रक्रिया का विवरण देने के लिए धन्यवाद! क्षमा करें मैंने आपके उत्तर को बहुत समय पहले नहीं देखा था। –

16

tcp::socket reference में दस्तावेज के रूप में:

कदम के बाद, ले जाया गया-से वस्तु एक ही स्थिति में है के रूप में यदि basic_stream_socket (io_service &) निर्माता का प्रयोग कर बनाया।

ऊपर का मतलब है कि आप serversession के रूप में कई बार से मूल socket वस्तु move कर सकते हैं के रूप में आप की जरूरत है।

+7

एक और विचार ... क्या यह बदले में कोड नहीं है? क्या यह छिपी हुई कार्यक्षमता का पर्दाफाश नहीं करता है जो अधिक स्पष्ट होना चाहिए? –

+0

@ केविन एच पैटरसन यहां एक छिपी हुई कार्यक्षमता कहां है? कोड मुझे सहज ज्ञान युक्त दिखता है। विकल्प 'सत्र :: सॉकेट_' का पर्दाफाश करने के लिए (गैर C++ 11 उदाहरणों में) होगा, जो कि कार्यान्वयन विस्तार का प्रकार है ... –

+2

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

संबंधित मुद्दे