2015-11-08 62 views
0

我想通過它有以下格式的插座發送數據包:發送數據的多個領域超過插座用C

struct Packet{ 
    uint32_t seqnum; 
    uint16_t check; 
    char data[1024] 
}; 

分組包含每個數據包都有一個序列號,校驗和數據。我怎麼能把這3個字段放入一個緩衝區以便通過套接字發送,然後當收到時,字段可以被提取?例如,是否有可能使緩衝區的前4個字節爲seqnum,接下來的4個字節爲檢查,然後剩餘的數據爲1024個字節?因此,接收器預計會收到總共1032個字節,然後應該能夠提取前4個數據,然後將這個數據序列,接下來的4個數據作爲校驗和,並將最後的1024個數據作爲數據?我通過UDP來做這件事,所以我不能單獨發送這些字段。

+0

你可以做到這一點,但是當你的數據是,說這是不是最佳的,如果你的實際數據可能比1024小得多,100個字節或更少,你會浪費帶寬。 –

+0

此外,您將增加您的數據包無法到達目的地的機會。使用UDP時,數據包太大並不常見。但是,先讓它工作,然後再嘗試優化它。 –

+0

不要使用結構作爲網絡協議。使用網絡協議作爲網絡協議。 – EJP

回答

-1

您必須確保您的結構已正確設置,以使字段在正確的字節邊界處正確對齊。

所以這是好的:

struct Packet{ 
    uint32_t seqnum; 
    uint32_t check; 
    char data[1024]; 
}; 

但是,這並不:

struct Packet{ 
    uint16_t other; 
    // 2 bytes of padding exist here so seqnum sits on a 4-byte boundary 
    uint32_t seqnum; 
    uint32_t check; 
    char data[1024]; 
}; 

任何整型字段大於8位應轉換之前發送到網絡字節順序,並返回到主機字節順序接收以後。對於32位值使用htonlntohl,對於16位值使用htonsntohs

一旦你做到了這一點,你可以直接發送結構:

struct Packet packet; 
// populate packet 
int sock = socket(AF_INET, SOCK_DGRAM, 0); 
// perform error checking, call bind, etc. 
int sendLen = sendto(socket, &packet, sizeof(packet), 0, &my_sockaddr, sizeof(my_sockaddr)); 

而且同樣接受它:

struct Packet packet; 
int sock = socket(AF_INET, SOCK_DGRAM, 0); 
// perform error checking, call bind, etc. 
int recvLen = recvfrom(socket, &packet, sizeof(packet), 0, &my_sockaddr, &my_sockaddr_len); 
// read packet 
+0

@DavidSchwartz我提到了字節順序和「htonl/s」和「ntohl/s」的使用。雖然我承認我不知道有任何架構將一種尺寸的值與較大尺寸的偏移值對齊。 – dbush

+0

您正在使用的語言爲您提供了編寫能夠保證工作的代碼所需的全部工具。爲什麼要進行對齊的假設? –

0

編輯 - OP沒有要求C++,但是如果有幫助,底層實現在C中完成。

我從Boost示例網站修改了一個類,以滿足您的需求,它是緩衝區和結構的便捷包裝。這應該適合您的需要,但它不考慮大或小的永久性。

當你的郵件總是固定的大小時,它會讓你更容易,但是在你的郵件頭中添加另一個4字節的整數可以爲你節省很多帶寬,這很容易實現。

message myMessage; 

myMessage.setSequence(nextSequenceNumber); 
myMessage.setCheckSum(mycheckSum); 

//assuming the message you have is a std::string 
memcpy(myMessage.body(), message.c_str(), myMessage.body_length()); 
myMessage.encode_header(); 
sendto(socket, myMessage.data(), myMessage.length(), 0, &my_sockaddrsizeof(my_sockaddr)); 

myMessage.reset(); 
recvfrom(socket, myMessage.data(), myMessage.length(), 0, &my_sockaddr, &my_sockaddr_len); 

if(!myMessage.decodeHeader()){ 
// handle bad header/corrupt message 
} 

int32_t sequence = myMessage.getSequence(); 
int32_t checkSum = myMessage.getSheckSum(); 

class message 
{ 
public: 
    enum { check_length = 4 }; 
    enum { seq_length = 4 }; 
    enum { body_length = 1024 }; 
    message() : _checkSum(0), _sequence(0), _body_length(1024), _header_length(8) {} // constructor + init list 

    const char* data() const { return data_; } 
    char* data()    { return data_; } 
    const char* body() const { return data_ + check_length + seq_length; } 
    char* body()    { return data_ + check_length + seq_length; } 
    std::size_t length() { return _body_length + _header_length; } 
    std::size_t body_length() { return _body_length; } 
    int32_t const& getCheckSum() const { return _checkSum; } 
    int32_t const& getSequence() const { return _sequence; } 
    void setCheckSum(const int32_t& s) { _checkSum = s; } 
    void setSequence(const int32_t& s) { _sequence = s; } 

    bool decode_header() 
    { 
     char check_sum[check_length + seq_length + 1] = ""; 
     char sequence[check_length + seq_length + 1] = ""; 
     strncat_s(check_sum, data_, seq_length); 
     strncat_s(sequence, data_ + check_length, check_length); 
     _checkSum = std::atoi(check_sum); 
     _sequence = std::atoi(sequence); 

     if (_checkSum == 0 || _sequence == 0) 
     { 
      std::cout << "Header malfunction" << std::endl; 
      return false; 
     } 
     return true; 
    } 

    void encode_header() 
    { 
     char header[check_length + seq_length + 1] = ""; 
     std::memcpy(header, &_sequence, sizeof(int32_t)); 
     std::memcpy(header + seq_length, &_checkSum, sizeof(int32_t)); 
     std::memcpy(data_, header, check_length + seq_length); 
    } 

    void reset() 
    { 
     memset(&data_[0], 0, sizeof(data_)); 
     int32_t _checkSum = 0; 
     int32_t _sequence = 0; 
    } 

private: 
    char data_[check_length + seq_length + body_length]; 
    int32_t _body_length, _header_length; 
    int32_t _checkSum; 
    int32_t _sequence; 
}; 
+0

這個問題被標記爲C,而不是C++。 – dbush