簡體   English   中英

發送std :: vector <float> 通過TCP,從boost :: asio到QTcpSocket

[英]Send std::vector<float> over TCP, from boost::asio to QTcpSocket

服務器需要通過TCP套接字將std::vector<float>發送到Qt應用程序。 我正在使用Qt 5.7。

在服務器端,使用boost::asio

std::vector<float> message_ = {1.2, 8.5};
asio::async_write(socket_, asio::buffer<float>(message_),
    [this, self](std::error_code ec, std::size_t)

這行得通,我設法使用boost::asioread_some()將其恢復到客戶端。 由於Qtasio都有自己的事件管理器,因此我想避免在Qt應用程序中使用asio

所以在客戶端,我有(這不起作用):

client.h:

#define FLOATSIZE 4
QTcpSocket *m_socket;
QDataStream m_in;
QString *m_string;
QByteArray m_buff;

client.cpp(構造函數):

m_in.setDevice(m_socket);
m_in.setFloatingPointPrecision(QDataStream::SinglePrecision);
// m_in.setByteOrder(QDataStream::LittleEndian);

client.cpp(讀取功能,通過QObject::connect(m_socket, &QIODevice::readyRead, this, &mywidget::ask2read);QObject::connect(m_socket, &QIODevice::readyRead, this, &mywidget::ask2read);

uint availbytes = m_socket->bytesAvailable(); // which is 8, so that seems good
while (availbytes >= FLOATSIZE)
{
    nbytes = m_in.readRawData(m_buff.data(), FLOATSIZE);

    bool conv_ok = false;
    const float f = m_buff.toFloat(&conv_ok);

    availbytes = m_socket->bytesAvailable();

    m_buff.clear();
}

根據Qt文檔, m_buff.toFloat()調用返回0.0 ,這是失敗的。 我試圖更改浮點精度,小端或大端,但是我無法設法讓std::vector<float>恢復。 有什么提示嗎?

編輯:一切都在同一台PC /編譯器上運行。

編輯:請參閱我的答案以尋求解決方案,並提供有關正在發生的事情的更多詳細信息

我通過編輯Qt端(客戶端)讀取套接字來設法解決了這個問題:

uint availbytes = m_socket->bytesAvailable();
while (availbytes >= 4)
{
    char buffer[FLOATSIZE];
    nbytes = m_in.readRawData(buffer, FLOATSIZE);    
    float f = bytes2float(buffer);
    availbytes = m_socket->bytesAvailable();
}

我使用這兩個轉換函數, bytes2floatbytes2int

float bytes2float(char* buffer)
{
    union {
        float f;
        uchar b[4];
    } u;

    u.b[3] = buffer[3];
    u.b[2] = buffer[2];
    u.b[1] = buffer[1];
    u.b[0] = buffer[0];

    return u.f;
}

和:

int bytes2int(char* buffer)
{
    int a = int((unsigned char)(buffer[3]) << 24 |
        (unsigned char)(buffer[2]) << 16 |
        (unsigned char)(buffer[1]) << 8 |
        (unsigned char)(buffer[0]));
    return a;
}

我還發現該功能可以顯示字節,這對於查看幕后發生的事情很有用(來自https://stackoverflow.com/a/16063757/7272199 ):

template <typename T>
void print_bytes(const T& input, std::ostream& os = std::cout)
{
  const unsigned char* p = reinterpret_cast<const unsigned char*>(&input);
  os << std::hex << std::showbase;
  os << "[";
  for (unsigned int i=0; i<sizeof(T); ++i)
    os << static_cast<int>(*(p++)) << " ";
  os << "]" << std::endl;;
}

回覆。 您的回答 :這是哪一邊? 另外,您的平台是否不相同(OS /體系結構?)。 我從這個問題中假設兩個進程都在同一台PC和編譯器等上運行。

一方面,您可以看到ASIO並沒有執行與endianness相關的任何操作

#include <boost/asio.hpp>
#include <iostream>
#include <iomanip>
namespace asio = boost::asio;

#include <iostream>

void print_bytes(unsigned char const* b, unsigned char const* e)
{
    std::cout << std::hex << std::setfill('0') << "[ ";
    while (b!=e)
        std::cout << std::setw(2) << static_cast<int>(*b++) << " ";
    std::cout << "]\n";
}

template <typename T> void print_bytes(const T& input) {
    using namespace std;
    print_bytes(reinterpret_cast<unsigned char const*>(std::addressof(*begin(input))), 
                reinterpret_cast<unsigned char const*>(std::addressof(*end(input))));
}

int main() {
    float const fs[] { 1.2, 8.5 };
    std::cout << "fs:     "; print_bytes(fs);

    {
        std::vector<float> gs(2);
        asio::buffer_copy(asio::buffer(gs), asio::buffer(fs));

        for (auto g : gs) std::cout << g << " "; std::cout << "\n";
        std::cout << "gs:     "; print_bytes(gs);
    }
    {
        std::vector<char> binary(2*sizeof(float));
        asio::buffer_copy(asio::buffer(binary), asio::buffer(fs));
        std::cout << "binary: "; print_bytes(binary);

        std::vector<float> gs(2);
        asio::buffer_copy(asio::buffer(gs), asio::buffer(binary));

        for (auto g : gs) std::cout << g << " "; std::cout << "\n";
        std::cout << "gs:     "; print_bytes(gs);
    }
}

打印

fs:     [ 9a 99 99 3f 00 00 08 41 ]
1.2 8.5 
gs:     [ 9a 99 99 3f 00 00 08 41 ]
binary: [ 9a 99 99 3f 00 00 08 41 ]
1.2 8.5 
gs:     [ 9a 99 99 3f 00 00 08 41 ]

理論

我懷疑Qt一方會毀了事情。 由於功能readRawData的命名肯定意味着缺乏字節序意識,我猜您的系統的字節序會造成嚴重破壞( https://stackoverflow.com/a/2945192/85371 ,以及注釋)。

建議

在這種情況下,請考慮使用Boost Endian。

我認為使用高級發送方法服務器端(您嘗試發送c ++向量)和低級客戶端是個壞主意。

我很確定某個地方存在字節順序問題。

無論如何嘗試做這個客戶端:

char buffer[FLOATSIZE];
bytes = m_in.readRawData(buffer, FLOATSIZE);    

if (bytes != FLOATSIZE) 
     return ERROR;

const float f = (float)(ntohl(*((int32_t *)buffer)));

如果boost :: asio使用網絡字節順序作為浮點數(應如此),則將起作用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM