【问题标题】:toLocal8bit send over TCPtoLocal8bit 通过 TCP 发送
【发布时间】:2018-06-28 20:29:48
【问题描述】:

我正在 QT Creator 框架中创建 TCP 服务器/客户端应用程序。我想从 UI 输入字段中获取一些数据并通过 TCP 发送。

我在客户端应用程序中做这样的事情:

 void MainWindow::on_btn_login_clicked()
{
    QByteArray text = (ui->login_input->text()).toLocal8Bit();
    char* out = text.data();
    connection->ConnectAndSendData(out);
}

在 ConnectAndSendData 函数中:

void TcpConnect::ConnectAndSendData(const char* data)
{
    socket = new QTcpSocket(this);
    int port = 1234;
    socket->connectToHost("localhost", port);

    if(socket->waitForConnected(3000))
    {
        qDebug() << "connected to s. localhost at port " << port;
        socket->flush();
        socket->write(data, sizeof(data));
        qDebug() << data << "\n";

        socket->waitForReadyRead();
        char* serverresponse;
        socket->read(serverresponse, 128);

        if(serverresponse == MESSAGE_LOGINRQ)
            socket->write(data);
        socket->flush();
        socket->close();
    }
    else
    {
        /**/
    }
}

以及socket中的数据->write(data, sizeof(data));正确发送到服务器,但是当服务器回显它时,它看起来像“某物/x00/x00/x00/x00”或类似的东西。另外当我做这样的事情时:

#define MESSAGE_WANTLOGIN "wanlogin"
socket->write(MESSAGE_WANTLOGIN, sizeof(MESSAGE_WANTLOGIN));

消息被那些空符号弄乱了。

在服务器端接收数据看起来很简单:

void Thread::readyRead()
{
    socket->flush();
    QByteArray data = socket->readAll();
    qDebug() << "data received: " << data;
    if(data == MESSAGE_WANTLOGIN)
    {
        socket->write(MESSAGE_LOGINRQ);
    } else
    {
        qDebug() << "error not messageloginrq";
    }
}

就像你可以假设的那样,虽然我发送“wanlogin”消息,但服务器接收到“wanlogin/x00/x00”之类的东西,如果显然返回 false。

这个垃圾被应用在数据的末尾,这不可能检查发送了什么消息。另一件事是发送数据的最大大小是 8 个字符,而且对于这个长度的数据也应用了垃圾,所以它看起来像“wanlogin/x00/x00”;但是,当我输入更多字符(例如 10 个)时,发送数据只会被削减为 8 个符号,没有 /x00s。

所以我的问题是如何从这些 /x00s 中清除数据以及如何发送超过 1 个字节的信息(我需要它,例如发送用户的登录名和密码)。抱歉,如果有一些愚蠢的错误,这是我的第一个客户端/服务器应用程序,它也为每个客户端使用多线程。

【问题讨论】:

  • 可能与您的问题没有直接关系,但将toLocal8Bit/fromLocal8Bit 用于发送到其他机器的数据是个坏主意。简而言之,“本地 8 位”编码对应于 Linux 上的 utf-8,但对应于 Windows 上的 utf-16。请改用toUtf8/fromUtf8
  • 不幸的是,对于字符串“wanlogin”它给出“wanlogin/x00”,而对于“HAHAHAHAHHAHA”给出“HAHAHAHAHHAHA/x00”,当少于8个字符时它给出一个/x00,然后是/xCD所以“asd”将是“asd/x00/xCD/xCD/xCD/xCD”
  • @Dmitry 我很确定它不是 Windows 上的 UTF-16,因为 UTF-16 不是 8 位编码。但是您的观点仍然成立,因为使用本地定义的编码进行网络通信是不好的。
  • @KarolDrach 对于0xCD,请参阅我的答案。在 Windows 上,分配的内存使用0xCD 进行初始化。因此,您看到的是已分配但从未写入的内存。

标签: c++ multithreading qt sockets tcp


【解决方案1】:

sizeof(data)48,具体取决于您使用的是 32 位还是 64 位计算机。它不是数据的大小,而是指针的大小(以字节为单位)。

所以发生的情况是,您的实际 wanlogin 实际上是一个 6 个字符的字符串,而您最终又发送了 2 个字节。在这种情况下你很幸运:data() 返回的 char 数组是以 null 结尾的,所以你有一个额外的 0 可以访问,但访问第二个 0 是未定义的行为,即任何事情都可能发生。

解决方案是使用strlen() 而不是sizeof。或者,更好的是,通过将ConnectAndSendData(const char* data) 更改为ConnectAndSendData(const QByteArray &amp;data),直接使用QByteArray 调用write()

void MainWindow::on_btn_login_clicked()
{
    const QByteArray text = (ui->login_input->text()).toLocal8Bit();
    connection->ConnectAndSendData(text);
}

void TcpConnect::ConnectAndSendData(const QByteArray & data)
{
    socket = new QTcpSocket(this);
    quint16 port = 1234;
    socket->connectToHost("localhost", port);

    if(socket->waitForConnected(3000))
    {
        qDebug() << "connected to s. localhost at port " << port;
        socket->write(data);
        ...
    }
    ...
}

【讨论】:

  • 感谢您,使用保留 local8bit 但删除 sizeof() 的方法有效。我不敢相信解决方案如此简单:)
  • @KarolDrach 不过,您应该替换 toLocal8Bit()。如果服务器和客户端不共享相同的本地编码,或者如果用户输入本地编码不支持的字符,则可能会导致问题:If this string contains any characters that cannot be encoded in the locale, the returned byte array is undefined. Those characters may be suppressed or replaced by another. 如果要安全,最好使用 UTF-8。
猜你喜欢
  • 2014-01-16
  • 2016-02-20
  • 2016-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-05
  • 2016-02-17
相关资源
最近更新 更多