Advertisement

Sending data

Started by July 21, 2005 10:09 PM
4 comments, last by hplus0603 19 years, 6 months ago
i have a question. in vb when u send data over winsock, and say you are sending the x co-ordinate and y-coordinate of and object, the client would receive the data and split up the x and y coordinate with a delimeter. how would you approach that in c++?
In c++ if you want to send a delimiter you must add it to the end of the buffer to send. this character is ussually '\0' in c++.
Advertisement
why don t you create a buffer where you pack all the data you want to send into in a formated way

or are you doing text base transmission?
http://www.8ung.at/basiror/theironcross.html
Typically, you send binary data, and you send it as messages that you can parse out based on the data.

Either each message has a known size, and you know what to do from the message code, or the message has a length field prepended before the actual data.

A simple example might be:

enum MessageCode {  DoNothing,  SaySomething,  MoveToPoint,};struct MessageHeader {  short messageCode;  short messageSize;};struct MessageSaySomething {  char what[256];};struct MessageMoveToPoint {  float x;  float y;};struct ActualMessage {  MessageHeader header;  union {    MessageSaySomething saySomething;    MessageMoveToPoint moveToPoint;  };};int sendSaySomething( SOCKET s, std::string const & text ) {  ActualMessage msg;  if( text.size() >= sizeof( msg.saySomething.what ) ) {    throw BadDataException();  }  memcpy( msg.saySomething.what, text.c_str(), text.size() );  msg.header.messageCode = MessageSaySomething;  msg.header.messageSize = sizeof( MessageHeader ) + text.size();  return ::send( s, (char const *)&msg, msg.header.messageSize, 0 );}int sendMoveToPoint( SOCKET s, float x, float y ) {  ActualMessage msg;  msg.header.messageCode = MessageMoveToPoint;  msg.header.messageSize = sizeof( MessageHeader ) + sizeof( msg.moveToPoint );  msg.moveToPoint.x = x;  msg.moveToPoint.y = y;  return ::send( s, (char const *)&msg, msg.header.messageSize, 0 );}// Really, you'll be using asynchronous receives and do some // input buffering to avoid blocking the thread, but this is // for illustration only.int receiveMessage( SOCKET s, ActualMessage * outMessage ) {  int r = ::recv( s, (char *)outMessage, sizeof( outMessage->header ), 0 );  if( r != sizeof( outMessage->header ) ) {    throw ProtocolDesyncError();  }  if( outMessage->header.messageSize > sizeof( *outMessage ) - sizeof( outMessage->header ) ) {    throw BadNetworkDataError();  }  r = ::recv( s, (char *)&(&outMessage->header)[1], outMessage->header.messageSize, 0 );  return outMessage->header.messageCode;}


You only need one receiveMessage() function, but you need one sendMessage function per message kind you want to send. Typically, in a larger system, you'll use some data-driven description of the message layouts to avoid having to write error-prone custom marshalling code for each message kind. (Code generation is also sometimes used)
enum Bool { True, False, FileNotFound };
So you are merely casting a struct to an array of chars? Does this have any higher overheads than directly copying memory locations (that store ints, longs, etc...) to an array of chars and back again?

...Stip
Casting between pointer types is a zero-cost operation; it's only there for the compiler semantic analysis. It doesn't actually generate any extra code, because at the assembly level, all pointers are just (long) integers.
enum Bool { True, False, FileNotFound };

This topic is closed to new replies.

Advertisement