2016-10-29 2 views
0

Ich versuche, eine 24-Bit-Nachricht zwischen einem TCP-Server und einem Client zu senden.Wie sende ich einen TCP-Puffer mit verschiedenen Elementgrößen?

So habe ich

uint8_t id = 5; 
unint16_t num = 4000; 

Also, was ein Weg wäre, sie in einem TCP-Puffer senden? Ich weiß, dass ich das uint16_t in Netzwerkbyte-Reihenfolge umwandeln muss, und ich würde das für das uint8_t nicht tun müssen.

Die Botschaft, die ich hat sende der Lage sein, mit einem dieser Anrufe werden nichtstimulierten als auch

uint32_t htonl(uint32_t hostlong); 
uint16_t htons(uint16_t hostshort); 
uint32_t ntohl(uint32_t netlong); 
uint16_t ntohs(uint16_t netshort); 

Der Kunde eine Nachricht erwartet, die von einem 16-Bit-Zahl, gefolgt von einem 8-Bit-Zeichen besteht . Ich kann das nicht ändern, also muss ich es irgendwie umgehen. Der Client wird die obigen Funktionen auch zum Konvertieren der Nachricht verwenden.

Soweit ich weiß, kann dies nicht mit einem Puffer gemacht werden. Habe ich etwas übergesehen?

Antwort

4

Sie können Ihre Daten zusammenstellen, indem Sie sie in einen einzelnen flachen Bytepuffer wie folgt kopieren:

uint8_t id = 5; 
uint16_t num = 4000; 
uint16_t beVal16 = htons(num); 
unsigned char flatbuf[sizeof(id)+sizeof(beVal16)]; 
memcpy(&flatbuf[0], &id, sizeof(id)); 
memcpy(&flatbuf[sizeof(id)], &beVal16, sizeof(beVal16)); 
int numBytesSent = send(theSocketFD, flatbuf, sizeof(flatbuf), 0); 

... und dann tun das Gegenteil auf der Empfangsseite:

uint8_8 id; 
uint16_t beVal16; 
unsigned char flatbuf[sizeof(id)+sizeof(beVal16)]; 
int numBytesReceived = recv(theSocketFD, flatbuf, sizeof(flatbuf), 0); 
if (numBytesReceived == sizeof(flatbuf)) 
{ 
    memcpy(&id, &flatbuf[0], sizeof(id)); 
    memcpy(&beVal16, &flatbuf[sizeof(id)], sizeof(beVal16)); 
    uint16_t num = ntohs(beVal16); 

    printf("received num=%u id=%u\n", num, id); 
} 
else {/* handle error or partial-buffer-receive, omitted here */} 
+0

Ich denke, das Konzept ist das gleiche, aber der Kunde ist in C++ und der Server ist in Python. Ich habe die Frage nicht richtig markiert. Es sieht so aus, als ob es sich um das Senden wirklich gut kümmert. – user3577756

+1

Um die Empfangslogik in Python zu machen, sehen Sie sich die python-Methode anlit.unpack() an, die für solche Dinge sehr nützlich ist. –

+0

Err, das wäre struct.unpack() (verflucht Autokorrektur!) –

1

Sie können die Daten in einem einzigen Puffer wie folgt platzieren:

uint8_t id = 5; 
unint16_t num = 4000 

... 
uint8_t buf[3]; 
buf[0] = id; 
//pack num in network byte order: 
buf[1] = (num & 0xff00) >> 8; 
buf[2] = num & 0xff; 

int rc = write(tcpsock, buf, sizeof buf); 
//check rc 

Oder man könnte es auch mit dies erreichen, etwas weniger effizient , da sie zwei Anrufe Schreib ausführt:

int rc = write(tcpsock, &id, sizeof id); 
int num_net = htons(num); 
rc = write(tcpsock, &num_net sizeof num_net); 
0

Sie können dies tun, mit writev(), den Aufruf ‚Sammeln write‘.

+0

Das scheint bequemer. So wird es automatisch in zwei separate Puffer schreiben, weil sie dann unterschiedliche Größen haben? – user3577756

+0

Es schreibt automatisch * aus * einem, zwei oder mehr Puffern der gleichen oder unterschiedlicher Größe, was immer Sie wollen. Kein Kopieren von Daten erforderlich. – EJP

+0

Beachten Sie, dass 'writev()' keine portable Funktion ist, aber auf Plattformen, auf denen es nicht vorhanden ist, leicht eine äquivalente Funktion implementieren würde. –

1

Der Client erwartet eine Nachricht, die aus einem 8-Bit-Zeichen gefolgt von einer 16-Bit-Zahl besteht.

TCP ist ein Streaming-Transport, es hat kein Konzept von Nachrichten. Sie können die beiden Werte einfach einzeln senden:

uint8_t id = 5; 
send(sckt, &id, sizeof(id), 0); 

uint16_t num = htons(4000); 
send(sckt, &num, sizeof(num), 0); 

Der Peer erhält 3 Bytes in der richtigen Reihenfolge. Das ist garantiert durch TCP. Der Empfänger könnte 1 Byte gefolgt von 2 Bytes lesen oder 3 Bytes gleichzeitig lesen oder sogar 1 Byte dreimal lesen. TCP ist es egal.

Soweit ich weiß kann dies nicht mit einem Puffer gemacht werden.

Natürlich kann es.

Für den Anfang, wenn Send Coalescing über die Nagle algorithm aktiviert ist (was es standardmäßig ist), puffert der Socket kleine sendet und überträgt sie in effizienteren Paketen. Daher werden die beiden obigen send Anrufe sehr wahrscheinlich zusammen übertragen werden.

Aber, wenn Sie wollen, auf dass nicht verlassen, könnten Sie einfach eine struct definieren die Werte zu halten, und dann, dass senden:

#pragma pack(push, 1) // or equivalent 
struct pktmsg 
{ 
    uint8_t id; 
    uint16_t num; 
}; 
#pragma pack(pop) 

pktmsg msg; 
msg.id = 5; 
msg.num = htons(4000); 
send(sckt, &msg, sizeof(msg), 0);