Modo corretto per inviare strutture dati personalizzate tramite socket

2

Mi chiedo quale sia il modo corretto per inviare strutture come array di caratteri tramite socket.

In questo momento ho qualcosa come sotto ma non è una buona soluzione perché causa un comportamento indefinito. È possibile inviare tipi come string o altri tipi definiti dall'utente?

O forse le strutture che funzionano come frame di protocollo dovrebbero avere solo tipi bult-in come int, char o char array con dimensione fissa?

Forse conosci qualche best practice su questo? Forse conosci qualche libreria di lavoro per farlo?

Non ho trovato alcun esempio funzionante che sarebbe diverso dal mio.

class FrameProtocol
{
public:
    std::array<char, 4096> buffer;
};

class FrameHeader
{
public:
    typedef enum { hello, priv} types;
    types type;
    const size_t size = sizeof(FrameHeader);
};

class PrivateMessage
{
public:
    int sender;
    int receiver;
    std::string value;
    const size_t size = sizeof(PrivateMessage);
};

class HelloMessage
{
public:
    std::string nickname;
    size_t size = sizeof(HelloMessage);
};


void sendTo(FrameProtocol& protocol)
{
    FrameHeader frame_header;
    memcpy(&frame_header, protocol.buffer.begin(), frame_header.size);

    std::cout << "Type: " << frame_header.type << std::endl;

    switch (frame_header.type)
    {
        case frame_header.priv:
        {
            std::cout << "###############################################" << std::endl;
            std::cout << "PRIV RECEIVED!" << std::endl;
            PrivateMessage priv;
            memcpy(&priv, protocol.buffer.begin() + frame_header.size, priv.size);
            std::cout << "PrivateMessage!, From: " << priv.sender << " To: " << priv.receiver << " val: " << priv.value << std::endl;
            std::cout << "################################################\n" << std::endl;
            break;
        }
        case frame_header.hello:
        {
            std::cout << "###############################################" << std::endl;
            std::cout << "HELLO RECEIVED!" << std::endl;
            HelloMessage hello {};
            memcpy(&hello, protocol.buffer.begin() + frame_header.size, sizeof(HelloMessage));
            std::cout << "HelloMessage!, Nickname: " << hello.nickname << std::endl;
            std::cout << "################################################\n" << std::endl;
        break;

            break;
        }

    }
}

int main()
{
    FrameProtocol frame;
    FrameHeader frame_header;
    frame_header.type = frame_header.priv;

    PrivateMessage pm;
    pm.sender = 10;
    pm.receiver = 20;
    pm.value = "Test";

    memcpy(frame.buffer.begin(), &frame_header, frame_header.size); // write header
    memcpy(frame.buffer.begin() + frame_header.size, &pm, pm.size); // write body

    FrameProtocol frame2;
    FrameHeader frame_header2;
    frame_header2.type = frame_header2.hello;

    HelloMessage hello;
    hello.nickname = "testas";
    hello.size = sizeof(hello);
    memcpy(frame2.buffer.begin(), &frame_header2, frame_header2.size); //write header
    memcpy(frame2.buffer.begin() + frame_header2.size, &hello, hello.size); // write body

    sendTo(frame2);
    sendTo(frame);
    
posta bielu000 15.06.2018 - 13:01
fonte

3 risposte

2

Se si desidera inviare dati tramite socket, è meglio convertire prima i dati in un formato testuale (come JSON o XML).

Un problema significativo con l'invio di dati binari su Internet è che presume che entrambi i lati del canale di comunicazione funzioneranno con architetture di computer simili (come endianness di dati o dimensioni di interi). Puoi anche risolvere questi problemi utilizzando formati di scambio di dati binari, come ASN.1, BSON, XDR, Thrift ecc.

Le librerie che puoi usare per fare cose come (ce ne sono molte) includono gSOAP ( link ) o Stroika ( link ). GSoap consente di definire strutture C ++, generare WSDL e semplici proxy / stub client / server per trasmettere e ricevere richieste con queste strutture dati. La struttura Stroika contiene un server web e un livello client Web incorporati simili per gestire le comunicazioni e strumenti facili da usare per mappare oggetti C ++ da / verso JSON (o XML o altri formati di testo), nonché legatura delle funzionalità del livello dei servizi Web tutto questo insieme.

    
risposta data 12.07.2018 - 21:45
fonte
0

Non preoccuparti di comportamenti non definiti dallo standard per processi come questo; gran parte del comportamento a basso livello di C ++ non è definito. Ciò che conta è che tu possa ottenere un comportamento coerente per la tua piattaforma . Decidi quindi su un protocollo e poi scrivi decodifica / codifica personalizzata che capisce esattamente quale ordine di byte inviare / ricevere. Tradizionalmente, ciò significava l'invio di dati in "Network Byte Order" (= Big Endian) e la trasformazione dell'ordine dei byte per le architetture Little Endian. I numeri in virgola mobile sono teoricamente più dolorosi dal momento che potrebbero utilizzare tutti i tipi di rappresentazioni, ma fortunatamente, in pratica, le architetture attuali si sono coalizzate attorno a IEEE 754 quindi non è tanto un problema.

Devi anche assicurarti che i tuoi dati per la trasmissione siano POD banali; e le tue classi attuali non lo sono perché contengono std::string . Dovrai ricodificare quelle stringhe in un formato trasmissibile.

L'alternativa è trasformare i dati in formato solo testo leggibile, come JSON o XML, ma questo è necessariamente più lento degli approcci binari.

    
risposta data 10.12.2018 - 10:42
fonte
0

Il più semplice di gran lunga è la conversione da / verso JSON. Questo è quello che fai se non è critico per le prestazioni, e funziona molto bene con strutture più complesse e supporta l'aggiornamento dei formati se usato in modo intelligente.

Avanti ci sono librerie di terze parti per la conversione in un formato binario, che è un po 'più complicato, ma più veloce. Di solito questo deve essere integrato nel processo di compilazione.

O il metodo manuale che non consiglierei: utilizzare una matrice di byte e riempirlo byte per byte.

    
risposta data 10.12.2018 - 10:52
fonte

Leggi altre domande sui tag