通过TCP发送std :: vector <float>,从boost :: asio发送到QTcpSocket

时间:2017-01-18 15:28:15

标签: c++ qt sockets networking boost-asio

服务器需要通过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::asio的{​​{1}}将其恢复到我的客户端。由于read_some()Qt都有自己的事件管理器,因此我希望避免在asio应用中使用asio

所以在客户端我有(这不起作用):

client.h:

Qt

client.cpp(构造函数):

#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); 连接):

QObject::connect(m_socket, &QIODevice::readyRead, this, &mywidget::ask2read);

根据Qt doc,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(); } 调用返回m_buff.toFloat(),这是一个失败。我试图改变浮点精度,小或大端,但我无法让我的0.0回来。任何提示?

编辑:一切都在同一台PC /编译器上运行。

编辑:请参阅我的答案以获取解决方案,并了解有关正在进行的更多详细信息

3 个答案:

答案 0 :(得分:1)

我设法通过编辑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;;
}

答案 1 :(得分:1)

重新。 your answer:这是哪一方?此外,您的平台是不一样的(操作系统/架构?)。我从问题中假设两个进程都在同一台PC和编译器等上运行。

首先,您可以看到ASIO does not do anything related to 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。

答案 2 :(得分:0)

我认为使用高级发送方法服务器端(您尝试发送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使用浮点数的网络字节顺序(应该这样),这将有效。