2014-11-21 30 views
0

我正在與其他使用sendto(..)和recvfrom()的UDP套接字運行相同程序的其他服務器(相同或相似系統)交換結構struct update_packet將struct結構化爲char *並通過UDP發送

基於從stackoverflow.com/questions/27055729/答案,我寫了一個函數來序列struct update_packet

struct update_packet { 
    uint16_t num_update_fields; 
    uint16_t port; 
    uint32_t IP; 

    vector<struct node> nodes; 

    const char * serialize() const { 
     ostringstream oss; 
     put_u16_as_big(oss, num_update_fields); 
     put_u16_as_big(oss, port); 
     put_u32_as_big(oss, IP); 

     for(size_t i = 0; i < num_update_fields; ++i) { 
      put_u32_as_big(oss, nodes[i].IP); 
      put_u16_as_big(oss, nodes[i].port); 
      put_u16_as_big(oss, nodes[i].nil); 
      put_u16_as_big(oss, nodes[i].server_id); 
      put_u16_as_big(oss, nodes[i].cost); 
     } 
     string str = oss.str(); 

     cout << str << "\t" << str.size() << endl; 
     cout << str.data() << "\t" << sizeof(str.data()) << endl; 
     return str.data(); 
    } 
         ... 
}; 

put_u16_as_big是一個輔助函數,它把一個uint16_t大端爲參考ostringstream

void put_u16_as_big(ostringstream& oss, uint16_t data) { 
    if (is_big_endian()) { 
     oss.write((const char *)&data, sizeof(data)); 
    } 
    else { 
     const char * ptr = (const char *)&data; 
     unsigned int s = sizeof(data); 
     for(unsigned int i=0; i < s; ++i) { 
      oss.put(ptr[s-1-i]); 
     } 
    } 
} 

然後它被實例化像

struct update_packet up; 
const char * up_to_send = up.serialize(); 

和發送。

我把一些coutserialize()進行測試。

隨着

cout << str << "\t" << str.size() << endl; 

它打印怪異字符(數字在一個盒子),大小爲44

然而,str.data()返回const char *

cout << str.data() << "\t" << sizeof(str.data()) << endl; 

我得到

8 

空字符串爲str.data()和8大小

此外,當我接收通過UDP套接字的數據,並從recvfrom打印的返回值,其是接收到的字節,它打印0,並且所接收的消息是相同種類的就像那個怪異的角色,但只有一個角色。

問題是什麼,如何解決這個問題,以便我可以在接收端接收和檢索數據?

回答

1

in put_u16_as_big(),您正在將原始二進制數據寫入ostringstream(字符串),但實際上並未將其轉換爲字符串。如果你想寫入原始的二進制數據,你需要寫入一個基本的ostream

此外,由於您實際上並未將其轉換爲字符串,因此您無法將其打印出來,就好像它是字符串一樣。

如果你堅持要用ostringstream然後,而不是使用oss.put()oss.write()這將插入原始的二進制,你應該使用operator<<這將插入格式化輸出。當然,如果你真的使用字符串,那麼字節順序並不重要。

+0

項目規格要求大的字節順序。如何在Big Endian中寫入'ostringstream'並在接收端讀取它,如果它使用小端? – user2418202 2014-11-22 01:34:19

+0

@ user2418202如果您將其轉換爲數字的字符串表示形式,那麼您將「排除」字節序。字節順序是數字在內存中的二進制表示所固有的。如果你想發送原始的二進制數據,那麼你應該發送它是「網絡字節順序」這是大端。這是一堆C庫函數,它將數字從主機字節順序轉換爲網絡字節順序,並返回:'htonl()','ntohl()'用於'long',還有一些用於'short' 。原始二進制和字符串表示都有優點和缺點... – rafeek 2014-11-25 16:11:41