Ho riscontrato un piccolo problema con il trasferimento di dati su socket (TCP). Piccolo background su quello che sto facendo:ricezione di dimensioni variabili di dati tramite socket TCP
Sto inviando dati dal lato A al B. I dati inviati possono essere di lunghezza variabile, assumendo dimensioni massime di 1096 byte.
A) send(clientFd, buffer, size, NULL)
su B, dal momento che non so cosa dimensioni aspettarsi, cerco sempre di ricevere 1096 byte:
B) int receivedBytes = receive(fd, msgBuff, 1096, NULL)
Tuttavia, quando ho fatto questo: ho realizzato un stava mandando piccole porzioni di dati ..sono circa 80-90 byte. Dopo alcuni scoppi di invio, B li ha radunati per aver ricevuto un totale di 1096 byte. Questo ovviamente ha danneggiato i dati e l'inferno si è scatenato.
Per risolvere il problema, ho rotto i miei dati in due parti: intestazione e dati.
struct IpcMsg
{
long msgType;
int devId;
uint32_t senderId;
uint16_t size;
uint8_t value[IPC_VALUES_SIZE];
};
Su un lato:
A) send(clientFd, buffer, size, NULL)
su B, ho ricevuto l'intestazione e determinare la dimensione di payload per ricevere: e quindi ricevere il resto del payload.
B) int receivedBytes = receive(fd, msgBuff, sizeof(IpcMsg) - sizeof(((IpcMsg*)0)->value), 0);
int sizeToPoll = ((IpcMsg*)buffer)->size;
printf("Size to poll: %d\n", sizeToPoll);
if (sizeToPoll != 0)
{
bytesRead = recv(clientFd, buffer + receivedBytes, sizeToPoll, 0);
}
Quindi, per ogni invio, che ha un carico utile, finisco per chiamare riceve due volte. Questo ha funzionato per me, ma mi chiedevo se c'è un modo migliore per farlo?
TCP è un protocollo * streaming *, invia i dati come flusso, il che significa che quando si riceve, si può o meno ricevere quanto si richiede. Se si ricevono meno delle dimensioni previste del messaggio, è necessario memorizzare i dati ricevuti e effettuare più chiamate a 'recv' per ricevere tutti i dati. –
@JoachimPileborg: non ho capito il suggerimento sentinella. Per quanto riguarda l'altro suggerimento: stai suggerendo di fare due mandate per una richiesta di invio? (PS: Ho un sacco di mandate che vanno e ho bisogno di tenerle al minimo, dal momento che crea un ritardo/ritardo) – brainydexter
Per quanto riguarda come inviare/ricevere dati a lunghezza variabile, è possibile inviare i dati effettivi dimensione in "intestazione" a dimensione fissa seguita da ricezione dei dati effettivi; oppure potresti avere un "sentinella", un valore che non può essere nei dati, per contrassegnare la fine dei dati. Comunque, quale metodo utilizzi, devi effettuare più chiamate a 'recv', ma su un computer moderno la penalizzazione delle prestazioni per più chiamate' send'/'recv' è trascurabile (e TCP probabilmente metterà i dati da due consecutivi' inviare 'chiama in un unico pacchetto comunque). –