Advertisement

Writing/Reading to a buffer

Started by February 21, 2005 11:13 AM
6 comments, last by X5-Programmer 19 years, 11 months ago
Ok im new to network programming so im playing around with it, im designing a little class which creates a stream of bytes so i can send it over the network. I dont have a problem putting data into bytes, its just getting it from the stream back into usable data, heres my current structure: CBuffer buffer; int a,b = 0; float i = 0; char * str = "My String"; buffer.Write(a); buffer.Write(b); buffer.Write(i); buffer.Write(str, strlen(str)); //now the idea is you can read from it in the same way, int a; float b; a = buffer.Read(integer); b = buffer.Read(float); etc etc But i cant think of the best way to get char *, or std::vector str; back into variables. Cheers. Ash.
If you have a char* array (string) and want to make it into an integer you can use: int val = atoi(str); If you have a float, the same goes with atof. Is this what you are asking about?

- Drew
Advertisement
I don't have any experience with the CBuffer class, so I don't know if there's an easier way to do this, but with a typical buffer (char buf[BUF_SIZE]), a variable length string can be extracted by reading in single characters until the null-termination is reached. Of course, in order for this to work, you need to make sure that you write the null-terminator into the buffer with the string.
if you want to serialize a string into a byte array, simply first write the length of the string and then write that many characters. e.g.

std::string  hi = "hello";buffer.write((unsigned char)hi.size(),hi.c_str());


then when reading, you just do

//doing = "" will zero out the entire buffer, however this is compiler//specific. use memcpy instead.. i had only forgot the order of the memcpy parameters right nowchar hi[256]= "";unsigned char ln;buffer.read(ln);//your read function should take a char pointer and an int or possibly //unsigned char specifying how many bytes to readbuffer.read(hi, ln);


NOTE: the method i used used a single byte to write the length. this means your limited to 256 characters with this method. im sure you can figure out how to fix that though

[Edited by - graveyard filla on February 21, 2005 12:10:08 PM]
FTA, my 2D futuristic action MMORPG
This is how I do it, I have been use it for my apps. I is an easy write/read class.

here is the class.
#ifndef _CPACKET_H_#define _CPACKET_H_#define WPAssert( assertion ) { if( !(assertion) ) { fprintf( stderr, "\n%s:%i ASSERTION FAILED:\n  %s\n", __FILE__, __LINE__, #assertion ); assert( #assertion &&0 ); } }#define PACKET_SIZE 512struct sbtsWData{	short length, pointer;	short opcode;	char  data[ PACKET_SIZE ];	sbtsWData( ):length( 0 ), opcode( 0 ), pointer( 0 ) { }	~sbtsWData( ) {		clear( );	}	void Initialise( unsigned short newLength, unsigned short newOpcode ) {				setLength( newLength );		opcode = newOpcode;	}		void clear( ) {    if( data )		strcpy(data, "");		opcode = 0;	}	void setLength( unsigned short newlength )	{	    if( (newlength > length) | (data==0) ) {		clear( );		data[newlength];		}else 		{					pointer = 0; opcode = 0;		}		length=newlength;	}	template < class type > inline sbtsWData & operator<<( const type &newData  ) {    writeData( newData );    return *this;	}	  template < class type > inline sbtsWData & operator>>( type &newData ) {		readData( newData );		return *this;	}  	inline sbtsWData & operator<<( const char * newData ) {		writeData( newData );		return *this;	}	inline sbtsWData & operator>>( char * newData ) {		readData( newData );		return *this;	}  	inline short & writeData( const void * newData, const short datalength ) {		return pointer = writeDataAt( pointer, newData, datalength );	}	inline short & readData( void * newData, const short datalength ) {		return pointer = readDataAt( pointer, newData, datalength );	}	template < class type > inline short & writeData( const type &newData ) {		return pointer = writeDataAt( pointer, newData );	}	template < class type > inline short & readData( type &newData ) {		return pointer = readDataAt( pointer, newData );	}	inline short & writeData( const char * newData ) {		return pointer = writeDataAt( pointer, newData );	}	inline short & readData( char * newData ) {		return pointer = readDataAt( pointer, newData );	}	inline short writeDataAt( const short offset, const char * newData ) {		short dlen = strlen( newData ) + 1;		WPAssert( offset + dlen <= length );		memcpy( data + offset, newData, dlen );		return offset + dlen;	}	inline short readDataAt( const short offset, char * newData ) {		short dlen = strlen( (char *)data + offset ) + 1; 		WPAssert( offset + dlen <= length );		memcpy( newData, data + offset, dlen );		return offset + dlen;	}	template < class type > inline short writeDataAt( const short offset, const type &newData ) {		WPAssert( offset + sizeof( type ) <= length );		memcpy( data + offset, &newData, sizeof( type ) );		return offset + sizeof( type );	}	template < class type > inline short readDataAt( const short offset, type &newData ) const {		WPAssert( offset + sizeof( type ) <= length );		memcpy( &newData, data + offset, sizeof( type ) );		return offset + sizeof( type );	}	inline short writeDataAt( const short offset, const std::string &newData ) {		short dlen = newData.length( ) + 1;		WPAssert( offset + dlen <= length );		memcpy( data + offset, newData.c_str( ), dlen );		return offset + dlen;	}	inline short readDataAt( const short offset, std::string &newData ) {		newData = (char *) data + offset;		short dlen = newData.length( ) + 1;		WPAssert( offset + dlen <= length );		return offset + dlen;	}  	inline short writeDataAt( const short offset, const void * newData, const short datalength ) {		WPAssert( offset + datalength <= length );		memcpy( data + offset, newData, datalength );		return offset + datalength;	}	inline short readDataAt( const short offset, void * newData, const short datalength ) const {		WPAssert( offset + datalength <= length );		memcpy( newData, data + offset, datalength );		return offset + datalength;	}};#endif



And some examples on how you use it.
------------------------------------

Send data:
----------

sbtsWData send_data;char strName[ 10 ] = "user";char strPass[ 10 ] = "password";short ID = 5;int nameLen = sizeof( char ) + strlen( strName ) + 1;int passLen = sizeof( char ) + strlen( strPass ) + 1;//Build the packet, first size of name + size of pass + size of shortint packetLen = ( nameLen + passLen );//First the packet size then opCode.send_data.Initialise( packetLen , CMSG_LOGIN ); send_data.writeData( ID );send_data.writeData( strName );send_data.writeData( strPass );send(SOCK, (char*)&send_data, sizeof( sbtsWData ), 0 );send_data.clear();


//thats it.

then the recv part is almost the same.

recv part:
---------

sbtsWData *recv_data;if( recv_data->opCode == CMSG_LOGIN ){   short ID;   char strName[ 10 ];   char strPass[ 10 ];   recv_data->Initialise( recv_data->lenght, NULL );   recv_data->readData( ID );   recv_data->readData( strName );   recv_data->readData( strPass );   printf("ID: %i", ID);   printf("name: %i", strName);   printf("name: %i", strPass);   recv_data->clear();}


hope this helps, it maybe are something wrong I only wrote it dident check so much.

[Edited by - X5-Programmer on February 26, 2005 12:24:07 PM]
-[ thx ]-
Hey,

This is the basic run down of how I make a 'stream' class to send over winsock. Keep in mind I am not that great at c++ at all. I made this class based off the open source of Rak Net and some tricky data conversion I figured out off the Eternal Lands open source client.

#ifndef STREAM_H#define STREAM_H	namespace dsmmorpg	{		// Stream Class		class Stream		{			public:				// Function Headers				Stream()				{					// Set the position of the buffer					m_Position = 2;					// Set the size of the buffer					m_Buffer[0] = 0;				}				Stream ( const char * p_Buffer )				{					// Declare the size of the incoming stream					uint32 p_Size = ( uint32 ) p_Buffer[0];					// Copy over the existing buffer					for ( int i = 0; i < p_Size; i++ )						m_Buffer = p_Buffer;					// Append the string delimiter to the end of the packet					m_Buffer[p_Size] = '\0';					// Set the position of the buffer					m_Position = 2;				}				uint32 GetSize()				{					// Return the current size of the buffer					return ( ( uint32 ) m_Buffer[0] );				}				char * GetData()				{					// Format the current buffer					m_Buffer[GetSize()] = '\0';					// Return the buffer					return ( m_Buffer );				}				void ResetPosition()				{					// Reset the position of the buffer					m_Position = 2;				}				void SetType ( uint32 p_Type )				{					// Set the stream type					m_Buffer[1] = ( uint8 ) p_Type;				}				void SetUint8 ( uint32 p_Data )				{					// Append an unsigned character to the stream					m_Buffer[m_Position++] = ( uint8 ) p_Data;					// Update the size of the stream					m_Buffer[0] = ( uint8 ) m_Position;				}				void SetUint32 ( uint32 p_Data )				{					// Append an unsigned integer to the stream					*( ( uint32 * )( m_Buffer + m_Position ) ) = p_Data;					// Update the position of the stream					m_Position += sizeof ( uint32 );					// Update the size of the stream					m_Buffer[0] = ( uint8 ) m_Position;				}				void SetSint8 ( sint32 p_Data )				{					// Append a signed character to the stream					m_Buffer[m_Position++] = ( sint8 ) p_Data;					// Update the size of the stream					m_Buffer[0] = ( uint8 ) m_Position;				}				void SetSint32 ( sint32 p_Data )				{					// Append a signed integer to the stream					*( ( sint32 * )( m_Buffer + m_Position ) ) = p_Data;					// Update the position of the stream					m_Position += sizeof ( sint32 );					// Update the size of the stream					m_Buffer[0] = ( uint8 ) m_Position;				}				void SetFloat32 ( float p_Data )				{					// Append a float to the stream					*( ( float * )( m_Buffer + m_Position ) ) = p_Data;					// Update the position of the stream					m_Position += sizeof ( float );					// Update the size of the stream					m_Buffer[0] = ( uint8 ) m_Position;				}				void SetFloat64 ( double p_Data )				{					// Append a double to the stream					*( ( double * )( m_Buffer + m_Position ) ) = p_Data;					// Update the position of the stream					m_Position += sizeof ( double );					// Update the size of the stream					m_Buffer[0] = ( uint8 ) m_Position;				}				void SetString8 ( const char * p_Data )				{					// Declare the size of the string to append					m_Buffer[m_Position++] = ( uint8 ) strlen ( p_Data );					// Append a character array to the stream					for ( int i = 0; i < strlen ( p_Data ); i++ )						m_Buffer[m_Position++] = p_Data;					// Update the size of the stream					m_Buffer[0] = ( uint8 ) m_Position;				}				void SetString8 ( const std::string& p_Data )				{					// Declare the size of the string to append					m_Buffer[m_Position++] = ( uint8 ) p_Data.size();					// Append a character array to the stream					for ( int i = 0; i < p_Data.size(); i++ )						m_Buffer[m_Position++] = p_Data;					// Update the size of the stream					m_Buffer[0] = ( uint8 ) m_Position;				}				uint32 GetType()				{					// Return the size of the stream					return ( ( uint32 ) m_Buffer[1] );				}				uint32 GetUint8()				{					// Return an unsigned character from the stream					return ( ( uint32 ) m_Buffer[m_Position++] );				}				uint32 GetUint32()				{					// Update the position of the buffer					m_Position += sizeof ( uint32 );					// Return an unsigned integer from the stream					return ( * ( ( uint32 * )( m_Buffer + m_Position - sizeof ( uint32 ) ) ) );				}				sint32 GetSint8()				{					// Return a signed character from the stream					return ( ( sint32 ) m_Buffer[m_Position++] );				}				sint32 GetSint32()				{					// Update the position of the buffer					m_Position += sizeof ( sint32 );					// Return a signed integer from the stream					return ( * ( ( sint32 * )( m_Buffer + m_Position - sizeof ( sint32 ) ) ) );				}				float GetFloat32()				{					// Update the position of the stream					m_Position += sizeof ( float );					// Return a float from the stream					return ( * ( ( float * )( m_Buffer + m_Position - sizeof ( float ) ) ) );				}				double GetFloat64()				{					// Update the position of the stream					m_Position += sizeof ( double );					// Return a double from the stream					return ( * ( ( double * )( m_Buffer + m_Position - sizeof ( double ) ) ) );				}				char * GetString8()				{					// Declare the size of this string					int p_Size = ( uint32 ) m_Buffer[m_Position++];					// Format the current string					m_String[p_Size] = '\0';					// Copy over the string from the stream					for ( int i = 0; i < p_Size; i++ )						m_String = m_Buffer[m_Position++];					// Return the string from the stream					return ( m_String );				}			protected:				char m_Buffer[1024];				char m_String[256];				int m_Position;		};	}#endif


So m_Buffer[0] is the entire size of the buffer stream, and m_Buffer[1] is the 'type' of stream it is ( ie. like movement packet, display text packet, etc... ).

How you use it?

#define UPDATE_MOVEMENT 1#define DISPLAY_TEXT 2Stream m_OutGoingStream;m_OutGoingStream.SetType ( UPDATE_MOVEMENT );m_OutGoingStream.Sint32 ( player.x );m_OutGoingStream.Sint32 ( player.y );m_OutGoingStream.Sint32 ( player.z );m_OutGoingStream.SetFloat32 ( server.ping );orm_OutGoigStream.SetString8 ( "Display this text on screen!" );......Stream m_IncomingStream;int Type = m_IncomingStream.GetType();if ( Type == UPDATE_MOVEMENT ){	sint32 X = m_IncomingStream.GetSint32();	sint32 Y = m_IncomingStream.GetSint32();	sint32 Z = m_IncomingStream.GetSint32();	float ping = m_IncomingStream.GetFloat32();}else if ( Type = DISPLAY_TEXT ){	cout << m_IncomingPacket.GetString8();}


Basically as you extract a piece of data from the stream, the stream moves to the next piece of data automatically ( so save every piece of data because next time you call it it will change ).

Tell me what you guys think :-D

Thanks,
Aaron Andersen
Advertisement
like it ;)
-[ thx ]-

This topic is closed to new replies.

Advertisement