Reputation: 49
msg->msgType = JOINREPLY;
memcpy((char *)(msg+1), &memberNode->addr.addr, sizeof(memberNode->addr.addr));
memcpy((char *)(msg+1) + 1 + sizeof(memberNode->addr.addr), &memberNode->memberList, sizeof(memberNode->memberList));
This is my msg which I want to send from one function by calling another function, which is send((char *)msg, msgsize);
The data structure for msg is
enum MsgTypes{
JOINREQ,
JOINREPLY,
DUMMYLASTMSGTYPE,
HEARTBEAT
};
typedef struct MessageHdr {
enum MsgTypes msgType;
}MessageHdr;
vector<MemberListEntry> memberList;
is the definition of memberList, as you can see memberList is a vector of type MemberListEntry, MemberListEntry has its own data.
int id;
short port;
long heartbeat;
long timestamp;
Since I am converting the complete memberList into (char *) is it possible to convert (char *) to memberList or MemberListEntry type again and iterate over it??
MemberListEntry *ml;
ml=(MemberListEntry *)malloc(sizeof(MemberListEntry));
for(char *j=finalData; i < (int)string(finalData).length(); j = (char *)(j+ sizeof(MemberListEntry))){
ml= (MemberListEntry *)j;
i+=sizeof(MemberListEntry);
idR=ml->getid();
portR=ml->getport();
heartbeatR=ml->getheartbeat();
//Do some stuff
}
The "finalData" is the data which I get after chopping off the msgType and the address which I was storing, pointing my pointer to the location where I store my memberList in the char format.
Upvotes: 0
Views: 109
Reputation: 161
You'll need to include an field in your message header indicating the whole size of a message pack.
possibly like this:
typedef struct MessageHdr {
enum MsgTypes msgType;
unsigned int msgLength;
} MessageHdr;
The actual value stored in the msgLength field depends on the convention, e.g. it can vary from the whole message pack size or minus the size of the header, or simply the count of MemberListEntry
s. use whatever you prefer.
You use send((char *)msg, msgsize);
to send over a tcp socket. However, your peer cannot figure out the important msgsize
value in order to rebuild the message data, unless you explicitly send it as part of your message header.
Then it should be trivial to rebuild them.
Firstly you should figure out how many entry exists in your message pack. Then you alloc a new vector of that size. finally you memcpy
all data into the new vector, and everything should be ok.
Principle #1: You cannot get information from nowhere.
The sizeof
works because the compiler knows the sizes. They are predefined, by the specification, by the platform, or by the header files you #include
d. They are fixed. And they never change.
The .length()
works because the std::vector
keep the length information for you under the scene. You can check their corresponding header files yourself.
In short, none of them comes from some fancy magics that automatically figure out what is contained in an arbitary memory area.
In your case, the information - "the actual element count" - is critical. And it must be accessible to the peer in order to reconstruct the data structure.
Priciple #2: Data structures that contain pointers in it cannot be send directly over network.
A pointer is only valid in current process. You cannot blindly send pointer over network. So sending your clever std::vector
does not work, either. Though the std::vector
itself has fixed size and you can apply sizeof
to it, it uses pointer internally to hold the actual data that can change dynamically.
Well, what you actually need is some kind of data marshalling / object serializing. You need to convert the data to some representation suitable for network transferring, and convert them back later. In the C++ realm, you have to do it yourself. There is no magic.
If you feel really boring implementing such a thing, consider using some high level language that handles object serializing for you. For example, Javascript has native support of the famous JSON format which is excellent in data exchanging. Or you can use C# which has a fast and efficient binary serializer with strong type.
Upvotes: 1
Reputation: 6190
If you need to transfer data using char*, you can simply recast the data, given that you know its size, back to its original form, assuming there's been no data deformation or transformation, which TCP prevents.
char*
is actually a sort of array in disguise, as arrays are actually just blocks of data stored adjacently in memory. In C:
array[1] and 1[array]
are the same as they both access the data at the address of array incremented by 1.
So your data has just been "unformatted" into a raw data block. If you use a cast back to your original form to give it type, everything should be fine.
If your data contains pointers, you're screwed. Now you don't have the original memory address system to refer to, so how can you locate data? Unless you copy the memory addresses as well, you can't access pointers once they go across systems.
Upvotes: 0