Writing/Reading to a buffer
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
- Drew
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.
then when reading, you just do
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]
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.
And some examples on how you use it.
------------------------------------
Send data:
----------
//thats it.
then the recv part is almost the same.
recv part:
---------
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]
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.
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?
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
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
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement