2013-02-25 27 views
6

Mam dwie następujące funkcje do wysyłania i odbierania pakietów.boost :: asio :: buffer: pobieranie rozmiaru bufora i zapobieganie przepełnieniu bufora?

void send(std::string protocol) 
{ 
    char *request=new char[protocol.size()+1]; 
    request[protocol.size()] = 0; 
    memcpy(request,protocol.c_str(),protocol.size()); 

    request_length = std::strlen(request); 
    boost::asio::write(s, boost::asio::buffer(request, request_length)); 
} 
void receive() 
{ 
    char reply[max_length]; 
    size_t reply_length = boost::asio::read(s, boost::asio::buffer(reply, request_length)); 
    std::cout << "Reply is: "; 
    std::cout.write(reply, reply_length); 
    std::cout << "\n"; 
} 

pytania dotyczą tej części boost::asio::buffer(reply, request_length) gdzie długość prośba jest długością łańcucha, który był początkowo setup gdy pakiet został wysłany. Jak sprawdzić rozmiar bufora bez znajomości request_length? Kolejne pytanie brzmi: jak zapobiec przepełnieniu bufora?

Odpowiedz

15

Aby uzyskać rozmiar bufora, można użyć funkcji boost::asio::buffer_size(). Jednak w twoim przykładzie najprawdopodobniej będzie to mało przydatne.

Jak wyjaśniono w buforze overview, Boost.Asio używa klas buforów do reprezentowania buforów. Te klasy zapewniają abstrakcję i chronią operacje Boost.Asio przed przekroczeniami buforów. Chociaż wynik boost::asio::buffer() jest przekazywany do operacji, meta-dane, takie jak rozmiar bufora lub jego typ bazowy, nie są przesyłane. Ponadto te bufory nie są właścicielami pamięci, więc obowiązkiem aplikacji jest upewnienie się, że pamięć podstawowa pozostaje ważna przez cały czas trwania okresu abstrakcji bufora.

Funkcja boost::asio::buffer() zapewnia wygodny sposób tworzenia klas buforów, w których rozmiar bufora jest wyprowadzany z możliwego typu. Gdy Boost.Asio jest w stanie wydedukować długość bufora, operacje Boost.Asio nie będą wywoływać przepełnienia bufora podczas korzystania z wynikowego typu bufora. Jeśli jednak kod aplikacji określa rozmiar bufora na boost::asio::buffer(), obowiązkiem aplikacji jest upewnienie się, że rozmiar nie jest większy niż pamięć podstawowa.

Podczas odczytywania danych wymagany jest bufor. Podstawowym pytaniem staje się, w jaki sposób można wiedzieć, ile pamięci do przydzielenia, jeśli Boost.Asio nie przekazuje rozmiaru. Istnieje kilka rozwiązań tego problemu:

  • Zapytanie gniazdo na ile dane są dostępne poprzez socket::available(), a następnie przydzielić bufor odpowiednio.

    std::vector<char> data(socket_.available()); 
    boost::asio::read(socket_, boost::asio::buffer(data)); 
    
  • Użyj klasy, która Boost.Asio mogą rosnąć w pamięci, takich jak boost::asio::streambuf. Niektóre operacje, takie jak boost::asio::read(), akceptują obiekty jako bufor i przydzielają pamięć, jaka jest wymagana dla operacji. Należy jednak podać warunek ukończenia; w przeciwnym razie operacja będzie kontynuowana aż do zapełnienia bufora.

    boost::asio::streambuf data; 
    boost::asio::read(socket_, data, 
            boost::asio::transfer_at_least(socket_.available())); 
    
  • jako Öö Tiib sugeruje włączenia długości jako część protokołu komunikacyjnego. Sprawdź przykład Boost.Asio examples, aby zapoznać się z przykładami protokołów komunikacyjnych. Skoncentruj się na protokole, niekoniecznie na Boost.Asio API.

    • W protokole o ustalonym rozmiarze zarówno producent danych, jak i konsument korzystają z wiadomości o tym samym rozmiarze. Ponieważ czytelnik zna rozmiar wiadomości, czytelnik może wcześniej przydzielić bufor.
    • W protokole o zmiennej długości wiadomości są często dzielone na dwie części: nagłówek i treść. Nagłówek ma zwykle ustalony rozmiar i może zawierać różne meta-informacje, takie jak długość ciała. To pozwala czytnikowi odczytać nagłówek do bufora o ustalonym rozmiarze, wyodrębnić długość ciała, przydzielić bufor dla ciała, a następnie odczytać ciało.

      // Read fixed header. 
      std::vector<char> data(fixed_header_size); 
      boost::asio::read(socket_, boost::asio::buffer(data)); 
      
      protocol::header header(data); 
      network_to_local(header); // Handle endianess. 
      
      // Read body. 
      data.resize(header.body_length()); 
      boost::asio::read(socket_, boost::asio::buffer(data)); 
      
      protocol::body body(data); 
      network_to_local(body); // Handle endianess.  
      
+0

Świetne rzeczy. 'boost :: asio :: streambuff' z' boost :: asio :: read_until() 'działało dobrze dla mnie w przypadku, gdy wiadomości kończą się ogranicznikiem. –

1

myślę, że pytanie jest mylące, ale to może pomóc:

void receive() { 
    enum { max_length = 1024 }; 
    char reply[max_length]; 
    size_t reply_length; 
    std::cout << "Reply is: "; 
    while ((reply_length = ba::read(s, basio::buffer(reply, max_length))) > 0) { 
    std::cout.write(reply, reply_length); 
    } 
    std::cout << "\n"; 
} 
+0

Opcja 'boost :: asio :: bufor (,)' zwraca co dokładnie. Widzę, że zwraca coś do 'ba :: read (s, buffer (,))' ale co to jest? – pandoragami

+0

@lost_with_coding: Typ reprezentujący pamięć, ale nie będący jego właścicielem. Funkcja [function] (http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference/buffer.html) pomaga przystosować powszechnie używane typy, tak aby spełniały one wymagania typu dla wielu funkcji Boost Operacje .Aio. To [overview] (http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/overview/core/buffers.html) dostarcza pewnych informacji. –

+0

W tym przykładzie nie trzeba przekazywać wartości max_length do asio :: buffer(). (Ponieważ Asio może go uzyskać za pomocą 'sizeof'.) –

5

Zazwyczaj wykorzystuje protokół komunikacyjny zarówno stałych wiadomości długość lub wiadomości, które zawierają nagłówek, który mówi długość wiadomości.

Boost.Asio online documentation zawiera duży zestaw przykładów i samouczków, więc powinieneś zacząć od tego. Wikipedia jest dobrym źródłem do wyjaśnienia terminologii, poprawa dokumentacji asio nie robi tego.

+1

Przeglądałem już samouczki ASIO doładowania, ale te po prostu połyskują na przykładach i nie wyjaśniają szczegółowo, co wywołują funkcje, co zwracają itp. Wiem, że mogłem zajrzeć do plików hpp również, ale to jak igła w stogu siana i jeszcze bardziej bezużyteczne niż same przykłady. PLus Jestem pewien, że wiele rzeczy nie zostało powiedziane w przykładach doładowania/tutorialach, ale tylko w plikach hpp, które mogą pochłonąć lata ćwiczeń. – pandoragami

+0

@lost_with_coding być może przykłady asio doładowania oczekują od ludzi znajomości pojęcia komunikacji cyfrowej i znaczenia powiązanych pojęć, takich jak protokoły, klienci, serwery, żądania itp. Użytych w przykładach. Sugeruję przeciwko inżynierii odwrotnej takiej wiedzy z kodu, istnieją łatwiejsze źródła, aby się tego wszystkiego nauczyć. –

+0

@lost_with_coding: The [examples] (http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/examples.html) nie wyjaśniają, co robi API, ponieważ jest to udokumentowane w [odniesienie ] (http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/reference.html) sekcja. Biblioteka Boost.Asio jest złożona, nie jest skomplikowana. W dokumentacji jest dużo informacji i warto poświęcić trochę czasu na zapoznanie się z różnymi częściami dokumentacji. –

Powiązane problemy