Reputation: 429
I am trying to send a map composed of an int and another map over TCP socket in linux.
the map is of the form
map<int, map<string, double>>
Following this SO link i tried to do
unsigned char* mybytemap = reinterpret_cast<unsigned char*>(&my_map);
then to send the buffer i used write() function as follows:
int size = sizeof(mybytemap);
char temp[10];
sprintf(temp, "%d", size);
write(sockfd, temp, strlen(temp)); //send the size for the client
write(sockfd, mybytemap, sizeof(mybytemap));
On the client side:
char temp[10];
n = read(sockfd, temp, 10);
size = stoi(temp); //Got Size Of buffer
unsigned char * buf;
if(size != 0)
{
buf = new unsigned char[size];
int current=0;
while(current<size)
{
n = read(sockfd,(unsigned char*)(buf)+current, min(1024,size-current));
if (n <= 0)
{
cout<<"ERROR reading from socket when receiving"<<endl;
break;
}
current+=n;
}
}
map<int, map<string, double>> *test = reinterpret_cast< map<int, map<string, double>>* > (buf);
vector<int> ks;
for(map<int, map<string, double>>::iterator it = test->begin(); it != test->end(); ++it)
{
ks.push_back(it->first);
cout<<"id: "<<it->first<<endl;
}
but the Map isn't received correctly and code crashes when trying to access the data. how to fix that?
Do i need to XML the map? and if so can someone guide me on how to do that?
Upvotes: 4
Views: 1089
Reputation: 746
answer in link in your question is not applicable to map (map is not pod)
general idea how you can to encode\decode map : encode size of map and then for each key/value encode size of key, then encode key, then encode size of value, then encode value. Following code assumes you encode size_t into sizeof(size_t) bytes
template<class T>
std::string encode(T value){
// data to bytes
}
template<class T>
T decode(std::string bytes){
// bytes to data
}
template<class K, class V>
std::string encode_map(std::map<K, V> data){
std::string result;
result.append(encode<size_t>(data.size()));
for(auto iter: data){
std::string first = encode<K>(iter.first);
result.append(encode<size_t>( first.size() ));
result.append(first);
std::string second = encode<V>(iter.second);
result.append(encode<size_t>( second.size() ));
result.append(encode<V>(iter.second));
}
return result;
}
template<class K, class V>
std::map<K, V> decode_map(std::string bytes){
size_t index = 0;
size_t size = decode<size_t>(std::string(bytes.begin()+index, bytes.begin()+index+sizeof(size_t) ) );
index += sizeof(size_t);
std::map<K, V> result;
for(size_t i = 0; i<size; i++){
size_t next_size = decode<size_t>(std::string(bytes.begin()+index, bytes.begin()+index+sizeof(size_t) ) );
index += sizeof(size_t);
K key = decode<K>(std::string(bytes.begin()+index, bytes.begin()+index+next_size ) );
index += next_size;
next_size = decode<size_t>(std::string(bytes.begin()+index, bytes.begin()+index+sizeof(size_t) ) );
index += sizeof(size_t);
V value = decode<V>(std::string(bytes.begin()+index, bytes.begin()+index+next_size ) );
index += next_size;
result[key] = value;
}
return result;
}
Upvotes: 3
Reputation: 23497
As recommended, you need to perform so-called serialization. You can employ Boost.Serialization as a serialization library. It can handle all STL types. An illustrative example:
std::map<int, std::map<std::string, double>> m1;
// ... (fill m1)
// serialize into a buffer (string):
std::string buffer;
boost::iostreams::back_insert_device<std::string> inserter(buffer);
boost::iostreams::stream<boost::iostreams::back_insert_device<std::string>> ostr(inserter);
boost::archive::binary_oarchive oa(ostr);
oa << m1;
ostr.flush();
// ... (here you can send the contents of buffer as plain bytes-chars via socket)
// deserialize into new map:
boost::iostreams::basic_array_source<char> device(buffer.data(), buffer.size());
boost::iostreams::stream<boost::iostreams::basic_array_source<char>> istr(device);
boost::archive::binary_iarchive ia(istr);
std::map<int, std::map<std::string, double>> m2;
ia >> m2;
Full live demo (with all headers): https://wandbox.org/permlink/NyZeVTrFI0p8RcmY
Upvotes: 2