[C/C++, Linux]

0

Hej wszystkim :)

Bardzo dziekuje @spartanPAGE za poswiecony czas i uwage.
Wroce ze zobrazowanym przykladem w nowym poscie jak zasugerowales :)

6

Wykonujac recv na sockecie tcp brak jest gwarancji ze otrzymam cala.kompletna paczke danych

??
https://pl.wikipedia.org/wiki/Transmission_Control_Protocol

W przeciwieństwie do UDP, TCP gwarantuje wyższym warstwom komunikacyjnym dostarczenie wszystkich pakietów w całości, z zachowaniem kolejności i bez duplikatów. Zapewnia to wiarygodne połączenie kosztem większego narzutu w postaci nagłówka i większej liczby przesyłanych pakietów. Chociaż protokół definiuje pakiet TCP, to z punktu widzenia wyższej warstwy oprogramowania, dane płynące połączeniem TCP należy traktować jako ciąg oktetów. W szczególności – jednemu wywołaniu funkcji API (np. send()) nie musi odpowiadać wysłanie jednego pakietu. Dane z jednego wywołania mogą zostać podzielone na kilka pakietów lub odwrotnie – dane z kilku wywołań mogą zostać połączone i wysłane jako jeden pakiet (dzięki użyciu algorytmu Nagle'a). Również funkcje odbierające dane (recv()) w praktyce odbierają nie konkretne pakiety, ale zawartość bufora stosu TCP/IP, wypełnianego sukcesywnie danymi z przychodzących pakietów.

@cod3ralmi9hty odpowiadając na komentarz:
Ile odczytasz, tyle będziesz miał.

Możesz wczytać dane do bufora, wziąć z nich to co potrzebujesz i resztę odłożyć na później -
w ten sposób w kilku liniach kodu możesz np. sformuować sobie wczytywanie danej ilości słów z socketu lub coś podobnego.

Daj mi trochę czasu - jeśli nie upiekę się od gorąca, to zrobię Ci drobny przykład z mockami

Na początek przerażenie: przyda się cały zestaw nagłówków;

#include <sstream>
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
#include <limits>

Następnie idzie nasz mock socketa:

namespace mock {
    class socket {
    public:
        using data_type = std::string;
        using send_calls_type = std::vector<data_type>;
        
        socket(send_calls_type &&scalls) {
            send_calls.reserve(scalls.size());
            std::transform(
                std::rbegin(scalls), std::rend(scalls), std::back_inserter(send_calls),
                [](auto &&data){ return data + " "; });
        }
        
        data_type fetch_next() {
            return send_calls.size()?
                pop() : data_type{};
        }
    private:
        data_type pop() {
            auto result = send_calls.back();
            send_calls.pop_back();
            return result;
        }
        send_calls_type send_calls;
    };
}

template<typename Socket>
auto fetch_next(Socket &sock) {
    return sock.fetch_next();
}

Czyli do konstruktora trafiają twoje "wywołania" i po kawałku można wyciągać data_type, czyli w tym wypadku std::string (wyciąga po jednym słowie).

Następnie trzeba się zająć wyciąganiem pewnej ilości danych z socketa:

template<typename T>
auto read_n(std::stringstream &ss, size_t n) {
    std::vector<T> result;
    while(ss && n --> 0) {
        T temp;
        ss >> temp;
        result.push_back(temp);
    }
    return result;
}

template<typename T>
auto read_all(std::stringstream &ss) {
    return read_n<T>(ss, std::numeric_limits<size_t>::max());
}

Mając to wszystko możemy pozwolić sobie na pomocniczą funkcję wypisującą zawartość kontenera:

template<typename Cont>
void print_container(
    Cont const &cont, 
    std::ostream & out = std::cout, 
    std::string sep = " "
) {
    for(auto const &item: cont) {
        out << item << sep;
    }
    out << "\n";
}

Z tym wszystkim nasz main wygląda tak:

int main() {
    std::stringstream data;
    mock::socket socket {{
        "asia ma wszy",
        "a pootin jest ciulem"
    }};

    
    data << fetch_next(socket);

    //first two
    print_container(read_n<std::string>(data, 2));
    
    data << fetch_next(socket);
    
    //the rest
    print_container(read_all<std::string>(data));
    
    return 0;
}

Output:

asia ma 
wszy a pootin jest ciulem 

Link: http://melpon.org/wandbox/permlink/GqVYYYPoXZKOv5Eh

1 użytkowników online, w tym zalogowanych: 0, gości: 1