2013-05-14 74 views
8

假設我有一個結構,其成員值我想通過網絡發送到另一個使用winsock 2的系統。我使用的是C++語言。 我如何將它轉換爲char *請記住結構必須在發送之前序列化,以及如何將char *反序列化到另一端的struct中?我發現boost序列化是對類似問題的建議,但任何人都可以用序列化和反序列化的小代碼片段來說明嗎?序列化結構

這個問題可能看起來很基本,但對相關帖子的其他答案沒有多大幫助。

+0

什麼[系列化示例](http://www.boost.org/doc/libs/1_53_0/libs/serialization/example/demo.cpp)? – nogard 2013-05-14 12:59:03

回答

0

如果你的結構是POD你可以使用memcpy

::memcpy(data, &your_struct, sizeof(YourStruct)));

,反之亦然接待處:

::memcpy(&your_struct, data, sizeof(YourStruct)));

datachar*。不要忘記你必須分配它,確保它足夠大並在最後刪除它。

+1

在發送端:struct example { \t int a; \t float b; \t double c; }; \t示例ex; \t ex.a = 1; \t ex.b = 1.02; \t ex.c = 1.040; :: memcpy(Buffer,&ex,sizeof(example)); \t \t \t \t retval = send(conn_socket,Buffer,sizeof(Buffer),0);在接收端:例如ex; retval = recvfrom(msgsock,Buffer,sizeof(Buffer),0,(struct sockaddr *)&from,&fromlen); \t \t \t :: memcpy(&ex,Buffer,sizeof(example)); \t \t \t printf(「%f」,ex.c);輸出:-627743856220419250000000000000000000000000000。爲什麼是這樣? – Vigo 2013-05-14 13:19:34

+2

因爲不同的體系結構和不同的編譯器會以不同的方式應用填充和字節順序,所以在只需複製結構時需要非常小心。 – Nick 2013-05-14 13:27:22

+0

我在兩個系統上都使用Visual Studio 2005和XP。但爲什麼這種差異? – Vigo 2013-05-14 13:38:27

1

好吧我會從助推網站採取example,因爲我不明白你無法理解它。
我添加了一些評論和更改它,你可以通過網絡傳輸。網絡代碼本身不在這裏。爲此,你可以看看boost::asio

int main() { 
    // create and open a character archive for output 
    // we simply use std::strinstream here 
    std::stringstream ofs; 

    // create class instance 
    const gps_position g(35, 59, 24.567f); 

    // save data to archive 
    { 
     boost::archive::text_oarchive oa(ofs); 
     // write class instance to archive 
     oa << g; 
     // archive and stream closed when destructors are called 
    } 

    // now we have const char* ofs.str().c_str() 
    // transfer those bytes via network 
    // read them on the other machine 

    gps_position newg; 
    { 
     // create and open an archive for input 
     std::stringstream ifs(the_string_we_read_from_the_network); 
     boost::archive::text_iarchive ia(ifs); 
     // read class state from archive 
     ia >> newg; 
     // archive and stream closed when destructors are called 
    } 
    return 0; 
} 
2

你可以做

struct MyStruct { 

    int data; 
    char* someNullTerminatedName; // Assuming not larger than 1023 chars 

    std::ostream& serialize(std::ostream& os) const { 
     char null = '\0'; 
     os.write((char*)&data, sizeof(data)); 
     os.write(someNullTerminatedName, strlen(someNullTerminatedName)); 
     os.write(&null, 1); 
     return os; 
    } 
    std::istream& deserialize(std::istream& is) { 
     char buffer[1024]; 
     int i = 0; 
     is.read((char*)&data, sizeof(data)); 
     do { buffer[i] = is.get(); ++i; } while(buffer[i] != '\0'); 
     if (someNullTerminatedName != NULL) free(someNullTerminatedName); 
     someNullTerminatedName = (char*)malloc(i); 
     for (i = 0; buffer[i] != '\0'; ++i) { 
      someNullTerminatedName[i] = buffer[i]; 
     } 
     return is; 
    } 
}; 

它是由你來照顧字節序和差異在int S和諸如此類的東西的尺寸。

例子:

MyStruct foo, bar; 
std::stringstream stream; 
foo.serialize(stream); 
// ... Now stream.str().c_str() contains a char* buffer representation of foo. 
// For example it might contain [ 1f 3a 4d 10 h e l l o w o r l d \0 ] 
bar.deserialize(stream); 
// ... Now bar is a copy, via a serial stream of data, of foo. 

如果你有一個套接字庫,通過C++輸入輸出流暴露其接口,那麼你甚至都不需要stringstream的。

3

您也可以查看Google的Protocol Buffers,這是一個用於在主機之間發送數據的平臺/語言獨立庫。

但是,範例轉向了先編寫協議,然後將數據結構納入其中。這樣做的好處是它可以強制你的軟件架構適應簡單的數據類型。

14

以下示例顯示了將struct序列化爲char數組並將其反序列化的最簡單方法。

#include <iostream> 
#include <cstring> 

#define BUFSIZE 512 
#define PACKETSIZE sizeof(MSG) 

using namespace std; 

typedef struct MSG 
{ 
    int type; 
    int priority; 
    int sender; 
    char message[BUFSIZE]; 
}MSG; 

void serialize(MSG* msgPacket, char *data); 
void deserialize(char *data, MSG* msgPacket); 
void printMsg(MSG* msgPacket); 

int main() 
{ 
    MSG* newMsg = new MSG; 
    newMsg->type = 1; 
    newMsg->priority = 9; 
    newMsg->sender = 2; 
    strcpy(newMsg->message, "hello from server\0"); 
    printMsg(newMsg); 

    char data[PACKETSIZE]; 

    serialize(newMsg, data); 

    MSG* temp = new MSG; 
    deserialize(data, temp); 
    printMsg(temp); 

    return 0; 
} 

void serialize(MSG* msgPacket, char *data) 
{ 
    int *q = (int*)data;  
    *q = msgPacket->type;  q++;  
    *q = msgPacket->priority; q++;  
    *q = msgPacket->sender;  q++; 

    char *p = (char*)q; 
    int i = 0; 
    while (i < BUFSIZE) 
    { 
     *p = msgPacket->message[i]; 
     p++; 
     i++; 
    } 
} 

void deserialize(char *data, MSG* msgPacket) 
{ 
    int *q = (int*)data;  
    msgPacket->type = *q;  q++;  
    msgPacket->priority = *q; q++;  
    msgPacket->sender = *q;  q++; 

    char *p = (char*)q; 
    int i = 0; 
    while (i < BUFSIZE) 
    { 
     msgPacket->message[i] = *p; 
     p++; 
     i++; 
    } 
} 

void printMsg(MSG* msgPacket) 
{ 
    cout << msgPacket->type << endl; 
    cout << msgPacket->priority << endl; 
    cout << msgPacket->sender << endl; 
    cout << msgPacket->message << endl; 
} 
在加速的網站
+0

簡單序列化的好例子 – PhillyNJ 2015-07-12 00:15:19

+0

你的代碼有兩個內存泄漏。實際上根本不需要使用'new'。下面是進一步的可能的改進:1.使MSG成爲反序列化函數的返回類型而不是輸出參數2.而不是'typedef struct MSG {...} MSG;'使用'struct MSG {...};' ,它在C++中是一樣的3.使用'std :: string'或'std :: vector '來保存序列化的數據(並且完全處理這個'#define PACKETSIZE')並將其用作' serialize'函數而不是輸出參數(或者如果你堅持把參數改成'char(&data)[PACKETSIZE]')。 – 2016-02-02 17:46:27

+0

他的代碼中沒有內存泄漏。所有內存在主方法結束時被釋放。 – jackmott 2016-05-17 20:26:05