send() and objects
Can anyone tell me how to send a object through a socket?
Example:
struct Player
{
char Name[10];
int XPos;
int YPos;
}
send(socket,char buffer,sizeof(buffer),0)
send takes a (char) datatype for the buffer, how can I use a player defined object type from above instead?
I understand the same Player structure definition would need to be on the server side as well but how do I get it through the socket.
If the simple answer is you cant send anything but a char datatype can you explain a different way of accomplishing this. Im very new to network coding and am struggling with this area. Thanks in advance.
November 25, 2003 02:30 PM
what you can do is instantiate the structure you created, get a pointer to the structure, and then cast that pointer to a char*. Then when it reads the buffer it''ll take it byte by byte over. (use sizeof(structure) to get the number of bytes...).
-Matt
matt@cubewarfare.com
-Matt
matt@cubewarfare.com
Thanks for the reply Mike
Im still not 100% confident with my pointers.
Is the proper way of what you described like this?
struct Player
{
char Name[10];
int XPos;
int YPos;
}
Player *ptr;
send(socket,(char*)&ptr,sizeof(ptr),0)
Also can I get a little bit of an explanation on how it takes it byte by byte and knows how to reconstruct it back into structure format on the server side?
Thanks in advance.
Im still not 100% confident with my pointers.
Is the proper way of what you described like this?
struct Player
{
char Name[10];
int XPos;
int YPos;
}
Player *ptr;
send(socket,(char*)&ptr,sizeof(ptr),0)
Also can I get a little bit of an explanation on how it takes it byte by byte and knows how to reconstruct it back into structure format on the server side?
Thanks in advance.
You''d prolly wanna do this
send(socket,(char*)&ptr,sizeof(Player),0)
since sizeof(ptr) would return 4 and not the size of the struct.
-=[ Megahertz ]=-
send(socket,(char*)&ptr,sizeof(Player),0)
since sizeof(ptr) would return 4 and not the size of the struct.
-=[ Megahertz ]=-
-=[Megahertz]=-
Pip,
Think about it in the same way as you would write to a file. To write a structure to a file, you would either write the structure as a block of data or write each element of the structure out individually, right?
Well, it''s exactly the same for sending through a socket. I personally would send each item individually to save on traffic although in your case it wouldn''t be a catastrophic waste of bandwidth.
Just remember that the data has to be reconstructed at the other end so remember to send the length of a string etc. so that the receiving end knows how many bytes to put in the string at the other end.
The reason I say this is because if you have large, mostly unused buffers it is a waste of bandwidth to transfer the whole buffer when it isn''t used. For example, if you have a 1000 byte buffer that isn''t currently used in your structure; it is better to send a single int (value zero) than send 1000 unused bytes.
Think about it in the same way as you would write to a file. To write a structure to a file, you would either write the structure as a block of data or write each element of the structure out individually, right?
Well, it''s exactly the same for sending through a socket. I personally would send each item individually to save on traffic although in your case it wouldn''t be a catastrophic waste of bandwidth.
Just remember that the data has to be reconstructed at the other end so remember to send the length of a string etc. so that the receiving end knows how many bytes to put in the string at the other end.
The reason I say this is because if you have large, mostly unused buffers it is a waste of bandwidth to transfer the whole buffer when it isn''t used. For example, if you have a 1000 byte buffer that isn''t currently used in your structure; it is better to send a single int (value zero) than send 1000 unused bytes.
"Absorb what is useful, reject what is useless, and add what is specifically your own." - Lee Jun Fan
"Absorb what is useful, reject what is useless, and add what is specifically your own." - Lee Jun Fan
quote:
Original post by Pip
Can anyone tell me how to send a object through a socket?
You need to define a serialisation strategy for how to turn objects into sequences of bytes, and how to turn sequences of bytes into objects (deserialisation). One design you might follow would be to have a serialise() member function for each class requiring serialisation, and you would have a free-standing deserialise() function which effectively acts like a "virtual constructor". Serialisation would need to do something like the following:
i) Output a unique tag identifying the type;
ii) For composites, recursively call the serialise() function (see i);
iii) For primitives, create an external representation.
iv) Optionally write a trailer tag, which might contain a checksum or end marker.
As an example, imagine you have these two classes:
class Serialisable{public: virtual std::string<char> serialise() const =0 virtual ~Serialisable() {}};class A : public Serialisable{ const int tag = 0x01;private: int x; int y;};class B : public Serialisable{ const int tag = 0x02;private: int z; A a;};Implementation of the serialise() function is left as an exercise to the reader.The other half of the equation is to write a deserialisation function. The way this might work is to have a free-standing deserialise() function in each class which delegates to a deserialising ctor of the class it is trying to create. That would mean deserialise could read the tag that was created in step i) of serialisation to decide what object it is trying to create and then call the constructor for that class. Something like this: Serialisable* deserialise(std::istream& is){ int tag; is >> tag; if(tag == A::tag) return new A(is); else if(tag == B::tag) return new B(is); else // error unknown type!}
[see also Virtual Constructors]
The big problem you can run into here is with C++'s static typing. If A and B are fundamentally different types, then you're going to have to start performing downcasts to get at the correct type before you can use it. For this reason, its best to restrict the actual types you need to serialise to the minimum, or even to find a different strategy altogether. Note that serialisation is independent of what happens with the serialised form of the objects. You might find it easier to develop a serialisation strategy by writing to files instead of sockets to begin with.
To learn more, Google for something like "C++ serialisation".
[Disclaimer: all code is untested and deliberately incomplete.]
[edited by - SabreMan on November 26, 2003 1:04:51 PM]
After some experimentation this is my progress on my problem. I have tried using
send(socket,(void*)ptr, sizeof(Player),0);
This is the error it gave me:
error C2664: ''send'' : cannot convert parameter 2 from ''void *'' to ''const char *''
So this is what I tried:
//Client Side
struct Player
{
char Name[7];
char msg[20];
};
//skip code to send()
int Bytes;
Player TestObj;
strcpy(TestObj.Name,"Ericka\0");
strcpy(TestObj.msg,"I hope this works!\0");
Player *ptr;
ptr = &TestObj
Bytes = send(ClientSocket,(char*)ptr,sizeof(Player),0);
//Server Side
struct Player
{
char Name[7];
char msg[20];
};
//skip to recv()
int Bytes;
Player TestObj;
Player *ptr;
Bytes = recv(ClientSocket,(char*)ptr,sizeof(Player),0);
ptr = &TestObj
printf("%s: %s,TestObj.Name,TestObj.msg);
All this compiles and the server runs fine, when I connect with the client and try to send the object through I get WSAEFAULT as a error. It says one of the reasons this error is thrown is because "This error occurs if an application passes an invalid pointer value, or if the length of the buffer is too small."
This is the output I get when it tries to print it out on the servers console screen.
Shattered Server 1.0
Running...
Client on 1964 connected.
ERROR: WSAEFAULT has been thrown...
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ¼ : ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ¼
Client on 1964 disconnected
I tried moving the ptr above the recv() like this.
ptr = &TestObj
Bytes = recv(ClientSocket,(char*)ptr,sizeof(Player),0);
That got rid of the ERROR but it still prints out the same garbage instead of the string:
Ericka: I hope this works!
If anyone can help me with this I would be very grateful.
Thanks in advance!
send(socket,(void*)ptr, sizeof(Player),0);
This is the error it gave me:
error C2664: ''send'' : cannot convert parameter 2 from ''void *'' to ''const char *''
So this is what I tried:
//Client Side
struct Player
{
char Name[7];
char msg[20];
};
//skip code to send()
int Bytes;
Player TestObj;
strcpy(TestObj.Name,"Ericka\0");
strcpy(TestObj.msg,"I hope this works!\0");
Player *ptr;
ptr = &TestObj
Bytes = send(ClientSocket,(char*)ptr,sizeof(Player),0);
//Server Side
struct Player
{
char Name[7];
char msg[20];
};
//skip to recv()
int Bytes;
Player TestObj;
Player *ptr;
Bytes = recv(ClientSocket,(char*)ptr,sizeof(Player),0);
ptr = &TestObj
printf("%s: %s,TestObj.Name,TestObj.msg);
All this compiles and the server runs fine, when I connect with the client and try to send the object through I get WSAEFAULT as a error. It says one of the reasons this error is thrown is because "This error occurs if an application passes an invalid pointer value, or if the length of the buffer is too small."
This is the output I get when it tries to print it out on the servers console screen.
Shattered Server 1.0
Running...
Client on 1964 connected.
ERROR: WSAEFAULT has been thrown...
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ¼ : ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ¼
Client on 1964 disconnected
I tried moving the ptr above the recv() like this.
ptr = &TestObj
Bytes = recv(ClientSocket,(char*)ptr,sizeof(Player),0);
That got rid of the ERROR but it still prints out the same garbage instead of the string:
Ericka: I hope this works!
If anyone can help me with this I would be very grateful.
Thanks in advance!
A char array is actually a pointer to a chunk of memory so I wouldn''t be surprised if when you send the structure it is simply sending the addresses of those arrays. Try something like this instead:
//skip code to send()
int Bytes;
Player TestObj;
strcpy(TestObj.Name,"Ericka\0");
strcpy(TestObj.msg,"I hope this works!\0");
Player *ptr;
ptr = &TestObj
// use htonl to ensure network byte order
long l = htonl(TestObj.XPos);
Bytes = send(ClientSocket,(char*)&l, sizeof(long), 0);
l = htonl(TestObj.YPos);
Bytes = send(ClientSocket,(char*)&l, sizeof(long), 0);
l = strlen(TestObj.Name);
l = htonl(l);
Bytes = send(ClientSocket,(char*)&l, sizeof(long), 0);
Bytes = send(ClientSocket,(char*)TestObj.Name, strlen(TestObj.Name), 0);
l = strlen(TestObj.Msg);
l = htonl(l);
Bytes = send(ClientSocket,(char*)&l, sizeof(long), 0);
Bytes = send(ClientSocket,(char*)TestObj.Msg, strlen(TestObj.Msg), 0);
// sending the length of the string is optional, but if you don''t then add one to the strlen() result to ensure that the terminating null is sent. this will allow you to reconstruct the object at the other end
// recv the data in the same order then print out the contents of the structure, all should be ok
//skip code to send()
int Bytes;
Player TestObj;
strcpy(TestObj.Name,"Ericka\0");
strcpy(TestObj.msg,"I hope this works!\0");
Player *ptr;
ptr = &TestObj
// use htonl to ensure network byte order
long l = htonl(TestObj.XPos);
Bytes = send(ClientSocket,(char*)&l, sizeof(long), 0);
l = htonl(TestObj.YPos);
Bytes = send(ClientSocket,(char*)&l, sizeof(long), 0);
l = strlen(TestObj.Name);
l = htonl(l);
Bytes = send(ClientSocket,(char*)&l, sizeof(long), 0);
Bytes = send(ClientSocket,(char*)TestObj.Name, strlen(TestObj.Name), 0);
l = strlen(TestObj.Msg);
l = htonl(l);
Bytes = send(ClientSocket,(char*)&l, sizeof(long), 0);
Bytes = send(ClientSocket,(char*)TestObj.Msg, strlen(TestObj.Msg), 0);
// sending the length of the string is optional, but if you don''t then add one to the strlen() result to ensure that the terminating null is sent. this will allow you to reconstruct the object at the other end
// recv the data in the same order then print out the contents of the structure, all should be ok
"Absorb what is useful, reject what is useless, and add what is specifically your own." - Lee Jun Fan
"Absorb what is useful, reject what is useless, and add what is specifically your own." - Lee Jun Fan
quote:
Original post by Pip
After some experimentation this is my progress on my problem. I have tried using
send(socket,(void*)ptr, sizeof(Player),0);
This approach is insufficient, since all you are doing is sending the physical representation of the object as a stream of bytes, and presumably forcing the runtime at the opposite end of the link to recognise that stream of bytes as the correct type of object. Firstly, you are undermining the type system by dealing directly with the memory representation of objects. If you make a mistake, all bets are off - the language can''t help you because you''ve already decided you know better. Secondly, you are assuming that the other end of the link deals with identical physical representations for the types in question. This is generally a very weak assumption. In your case, I suspect you are dealing with both ends of the socket so have full control over the situation. However, many real-world scenarios requiring serialisation do not allow you to make these assumptions. What if the other end of the socket is a Java program, or a C++ program written on a different compiler? In the latter case, you might end up with subtle bugs manifesting themselves in an unrelated area of your program.
Although this probably seems like a lot of hard work for something you perceive as simple, you shouldn''t let that put you off. The approach you are attempting is fraught with problems that could bite you in future, and the "correct" approach is not as hard as it seems.
Thanks JY
I tried your advice, I am probally still messing something up.
//Client Side
int Bytes;
Player TestObj;
strcmp(TestObj.Name,"Ericka\0");
strcmp(TestObj.Msg,"I hope this works!\0");
Player *ptr;
ptr = &TestObj
long MsgLength;
MsgLength = strlen(TestObj.Name);
MsgLength = htonl(MsgLength);
Bytes = send(ClientSocket,(char*)&MsgLength,sizeof(MsgLength),0);
Bytes = send(ClientSocket,(char*)TestObj.Name,strlen(TestObj.Name),0);
MsgLength = strlen(TestObj.Msg);
MsgLength = htonl(MsgLength);
Bytes = send(ClientSocket,(char*)&MsgLength,sizeof(MsgLength),0);
Bytes = send(ClientSocket,(char*)TestObj.Msg, strlen(TestObj.Msg),0);
//Server Side
int Bytes;
Player TestObj;
Player *ptr;
ptr = &TestObj
long MsgLength;
Bytes = recv(ClientSocket,(char*)&MsgLength, sizeof(MsgLength), 0);
MsgLength = ntohl(MsgLength);
Bytes = recv(ClientSocket,(char*)&TestObj.Name,sizeof(MsgLength),0);
Bytes = recv(ClientSocket,(char*)&MsgLength, sizeof(MsgLength), 0);
MsgLength = ntohl(MsgLength);
Bytes = recv(ClientSocket,(char*)&TestObj.Msg,sizeof(MsgLength),0);
printf("%s: %s\n",TestObj.Name, TestObj.Msg);
Do I have it right on the recv end? Everything runs fine and the client sends the message but it still comes out as garbage instead of the sent object values.
I have also put my actual code on the web found here. It should compile and run if anyone wants to see what its doing. I condensed it from my Network Class into one main for the client and one for the server.
(ClientSide)
http://www.angelfire.com/rebellion2/sisterhood/Network.html
(ServerSide)
http://www.angelfire.com/rebellion2/sisterhood/server.html
[edited by - Pip on November 27, 2003 8:18:08 PM]
I tried your advice, I am probally still messing something up.
//Client Side
int Bytes;
Player TestObj;
strcmp(TestObj.Name,"Ericka\0");
strcmp(TestObj.Msg,"I hope this works!\0");
Player *ptr;
ptr = &TestObj
long MsgLength;
MsgLength = strlen(TestObj.Name);
MsgLength = htonl(MsgLength);
Bytes = send(ClientSocket,(char*)&MsgLength,sizeof(MsgLength),0);
Bytes = send(ClientSocket,(char*)TestObj.Name,strlen(TestObj.Name),0);
MsgLength = strlen(TestObj.Msg);
MsgLength = htonl(MsgLength);
Bytes = send(ClientSocket,(char*)&MsgLength,sizeof(MsgLength),0);
Bytes = send(ClientSocket,(char*)TestObj.Msg, strlen(TestObj.Msg),0);
//Server Side
int Bytes;
Player TestObj;
Player *ptr;
ptr = &TestObj
long MsgLength;
Bytes = recv(ClientSocket,(char*)&MsgLength, sizeof(MsgLength), 0);
MsgLength = ntohl(MsgLength);
Bytes = recv(ClientSocket,(char*)&TestObj.Name,sizeof(MsgLength),0);
Bytes = recv(ClientSocket,(char*)&MsgLength, sizeof(MsgLength), 0);
MsgLength = ntohl(MsgLength);
Bytes = recv(ClientSocket,(char*)&TestObj.Msg,sizeof(MsgLength),0);
printf("%s: %s\n",TestObj.Name, TestObj.Msg);
Do I have it right on the recv end? Everything runs fine and the client sends the message but it still comes out as garbage instead of the sent object values.
I have also put my actual code on the web found here. It should compile and run if anyone wants to see what its doing. I condensed it from my Network Class into one main for the client and one for the server.
(ClientSide)
http://www.angelfire.com/rebellion2/sisterhood/Network.html
(ServerSide)
http://www.angelfire.com/rebellion2/sisterhood/server.html
[edited by - Pip on November 27, 2003 8:18:08 PM]
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement