2010-08-10 3 views
4

J'utilise des sockets synchronisés avec une fenêtre win32, et en utilisant la fonction send() et recv() pour envoyer des données via Internet TCP; Qu'est-ce que je me demande, comment pourrais-je envoyer des entiers ou même ma propre classe/structure sur le socket TCP? parce que la fonction send() me permet seulement d'envoyer des caractères.Sockets C++ - Puis-je envoyer uniquement des caractères?

Aurais-je juste à envoyer des caractères, puis peut-être les convertir en entier avec atoi()? ou si je voulais envoyer une structure de classe, j'enverrais beaucoup de chaînes et les mettrais dans les variables ... une par une.

+0

Les caractères sont des octets. Ce niveau de conversion demande beaucoup de travail. –

+0

duplication possible de [Envoyer structure via Socket en utilisant JAVA et C++] (http://stackoverflow.com/questions/2202250/sending-struct-via-socket-using-java-and-c) –

Répondre

5

Il n'envoie pas de caractères dans le sens textuel - il envoie des tableaux contigus d'octets, auxquels il fait référence en utilisant un char *. Vous pouvez indiquer les octets de tout type de valeur de cette façon, donc si vous voulez envoyer un int,

int A = 5; 
const char* pBytesOfA = (const char*)&A; 
int lengthOfBytes = sizeof(A); 

send(socket, pBytesOfA, lengthOfBytes, flags); 
+1

Je pense que vous devriez utiliser htonl() avant la transmission. –

2

Cela dépend de ce que vous voulez faire. Une possibilité simple est:

Supposons qu'un int possède 32 bits significatifs et que les valeurs négatives soient codées en complément à deux. Ensuite, vous pouvez envoyer un int comme quatre chars:

bool send_int(int fd, int i) 
{ 
    unsigned char buf[4]; 
    buf[0] = (i >> 24) & 0xff; 
    buf[1] = (i >> 16) & 0xff; 
    buf[2] = (i >> 8) & 0xff; 
    buf[3] = (i >> 0) & 0xff; 
    return ((unsigned) send(fd, buf, sizeof buf, 0) == sizeof buf); 
} 

Du côté de la réception, vous devez lire quatre octets puis combiner leurs valeurs de façon à former un nouveau int.

Il existe de nombreuses autres possibilités pour coder int s et d'autres types de données en tant que flux d'octets. Ce qui précède est juste un exemple simple.

+1

Ne fais pas ça. Je veux dire ne pas comparer à la taille du tampon. Toujours garder une trace du nombre d'octets que vous avez envoyés. 'write (2)' et 'send (2)' peuvent légalement retourner moins alors vous demandez d'envoyer. –

+0

Merci pour la note. Le correctif approprié serait d'écrire une fonction 'sendbytes' qui essaie à plusieurs reprises d'envoyer le tampon donné (ou le reste) jusqu'à ce que tous les octets aient été envoyés ou qu'une erreur irrécupérable se soit produite. –

0

Vous pouvez certainement envoyer un tampon binaire via send(). Transformez-le simplement en (const char *) dans l'appel d'envoi.

+1

Cela deviendra rapidement source d'erreurs si vous avez un matériel différent sur le côté envoi et côté réception. Pensez à l'ordre des octets, à la taille de 'int', etc. –

+0

Je suppose que le tampon binaire a été composé correctement. Peut-être aurais-je dû être plus explicite. – carlsborg

2

Ne faites pas cela vous-même, utilisez les bibliothèques qui le font pour vous, comme Boost.Asio et Boost.Serialization.

Boost Asio est une bibliothèque qui remplace les sockets et fournit même un interface like C++ iostreams et traitera les types d'envoi/réception intégrés comme int pour vous. Boost La sérialisation vous permet de sérialiser facilement vos classes afin de pouvoir les envoyer sur le réseau.

SI vous ne pouvez pas utiliser des bibliothèques supplémentaires, vous devrez envoyer les données manuellement sur des sockets simples - assurez-vous que vous n'oubliez d'utiliser htons, ntohs, htonl and ntohl functions, or your code will break when the two communicating computers use different endianess (byte order).

petit extrait:

// sender: 
unsigned long to_send = 123; 
unsigned long to_send_n = htonl(to_send); // convert to network byte order 
send(send_socket, (const char*)(&to_send_n), sizeof(unsigned long), flags); 

// reciever: 
char recv_buf[sizeof(unsigned long)]; 
recv(recv_socket, recv_buf, sizeof(unsigned long)); //recieve number 
unsigned long recieved = ntohl(*((unsigned long*)recv_buf), flags); // convert back to host byte order 

Étant donné que ces fonctions existent seulement Pour les types non signés, vous serez limité aux types non signés.

0

AC (++) charn'est pas la même chose qu'un caractère. Un char est simplement un type entier avec au moins (et habituellement exactement) 8 bits. Un char souvent représente un caractère ASCII (ou de nos jours, une unité de code UTF-8), mais il peut également représenter des données binaires arbitraires, ce qui est le cas avec send() et recv().

Maintenant, il y a des protocoles (par exemple, SMTP) qui faire partent du principe que les données texte et peut mutiler des données binaires qui arrive à contenir octets comme 0x0A (saut de ligne) ou 0x00 (fin de chaîne C). Dans ce cas, vous devez utiliser un encodage binaire-texte comme Base64. Mais cela ne devrait pas être un problème si vous travaillez directement avec TCP.