【问题标题】:QTcpSocket receiving transferQTcpSocket 接收传输
【发布时间】:2012-12-20 18:33:04
【问题描述】:

我在接收转帐时遇到问题。

QTcpSocket->readAll() 在我发送给它时没有读取足够的字节。当我发送 15k 字节时,它只读取其中的一部分,然后什么也不做。我做错了什么?

QByteArray array;

array = socket->readAll(); //just reads some part, not fully.

为什么会这样?

【问题讨论】:

  • 这段代码什么时候执行?在处理readyRead()waitForReadyRead() 之后的信号或其他什么时?
  • 它在 QTcpSocket 的 readyRead() 槽中。

标签: c++ qt qtcpsocket


【解决方案1】:

当您调用readAll() 时,很可能套接字还没有接收到所有数据。这是因为 TCP 通信发生在 小数据包 中(每个数据包大约有 1KB 的数据,取决于很多事情)。这些数据包构成一个流,通信线路的另一端将字节写入其中。您必须在接收端组装它们。如何组装它们必须在协议中定义。

要解决此问题,您必须等待所有预期数据才能组装。有时除非您阅读它(取决于协议),否则不知道需要多少数据。

假设你想实现一个协议,它说“直到换行符之前的一切都是我们称之为消息的东西”。现在您想收到这样的消息。这是通过连续读取并附加到目标缓冲区(如您的QByteArray)来完成的,直到出现换行符。但是,还有一件事:当您期望第二个 消息 时,它可以紧跟在 TCP 流中的第一个消息之后,因此您不仅要读取第一个消息的结尾,还要读取第一个消息的结尾。第二个开始。请记住这一点。

当不处理信号槽连接时,您可以为此类换行符分隔的消息编写一个同步接收器,如下所示:

QByteArray array;

while(!array.contains('\n')) {
    socket->waitForReadyRead();
    array += socket->readAll();
}

int bytes = array.indexOf('\n') + 1;     // Find the end of message
QByteArray message = array.left(bytes);  // Cut the message
array = array.mid(bytes);                // Keep the data read too early

processMessage(message);

处理QTcpSocket::readyRead()时,可以做类似的事情。

void MyClass::socketReadyRead() // connected to QTcpSocket::readyRead() signal
{
    array += socket->readAll();

    if(array.contains('\n')) {
        int bytes = array.indexOf('\n') + 1;     // Find the end of message
        QByteArray message = array.left(bytes);  // Cut the message
        array = array.mid(bytes);                // Keep the data read too early

        processMessage(message);

        socketReadyRead();                       // re-call myself to process more
    }
}

当您想读取通过一个 TCP 连接发送的所有内容(直到它被对等方关闭)时,您可以以阻塞方式等待此事件或处理连接到正确信号的插槽中的数据:@987654326 @。

阻塞:

socket->waitForDisconnected();
QByteArray array = socket->readAll();

非阻塞(使用槽处理信号):

void MyClass::socketReadyRead() // connected to QTcpSocket::readyRead() signal
{
    array += socket->readAll();
    // Do NOT process yet!
}

void MyClass::socketDisconnected() // connected to QTcpSocket::disconnected() signal
{
    processMessage(array);
}

替代的非阻塞解决方案(基本相同):

// You don't have to connect to QTcpSocket::readyRead() signal in this case

void MyClass::socketDisconnected()
{
    processMessage(socket->readAll());
}

【讨论】:

  • 嗨,我真的不知道它会持续多长时间或以什么结尾,我正在发送原始二进制格式。我知道如何使用 Winsock 或 POSIX 套接字但对 qt 来说是新手..
  • @OvérFlôwz 您必须知道长度,无论是提前还是在接收数据时检测结束。你们传输什么二进制格式?您将如何等待 POSIX 套接字中的整个消息?
  • 我正在逐块读取大小为 1024 的块,当它到达末尾时,返回 0 或 -1(老实说不记得了),然后将所有数据写入磁盘。我只是发送原始数据,它不是格式或其他任何东西,只是原始数据,我不知道它会是什么。
  • 什么的结尾? TCP连接何时关闭?我在问,因为 TCP 流没有“数据结束”之类的东西,但你可以关闭整个流(当然,你不能在同一个连接上接收更多数据)。
  • 在组装中做的,看看你是否喜欢。 recv_loop: 调用 recv,[hSock],buffer,1024,0 cmp eax,0 jle end_loop 调用 WriteFile,[file_handle],buffer,eax,wbytes,0 jmp recv_loop end_loop: ;在这里完成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多