通过套接字发送数据的过程是如何工作的?

时间:2015-09-08 01:04:01

标签: php c++ qt sockets stream

我已经编写了一个服务器/客户端设置,可以来回发送字符串并且可以正常工作。现在我试图从一个无效的PHP脚本发送数据,所以我试图解开为什么它无法正常工作。

这是从客户端发送数据的代码,我发送给服务器的字符串=" aa"

(请注意代码中的评论)

void Client::sendNewMessage(){
    qDebug() << "sendNewMessage()";

    QString string(messageLineEdit->text()); 

    QByteArray block;
    QDataStream out(&block, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_0);
    out << quint16(0) << string; // why is the quint16 appended before the string?
    out.device()->seek(0); // set current position to 0, why exactly?
    out << (quint16)(block.size() - sizeof(quint16)); // substract 16bit unsigned int from the total data size? 
                                                      //Probably something to do with the appending of the quint16 at the beginning.

    tcpSocket->write(block);
}

这是服务器的读取功能:

void TcpServer::readIncomingData(){
    QDataStream in(tcpServerConnection);
    in.setVersion(QDataStream::Qt_4_0);

    int size = (int) sizeof(quint16); // get packetsize? size = 2 because quint16 is 2 bytes?
    qDebug() << "size = " << size;

    // ** OPTIONAL CODE, WORKS WITHOUT ASWELL ** // I got this somewhere from the internet.
    if (tcpServerConnection->bytesAvailable() < (int)sizeof(quint16))
        return; // if size of packet is less than 2, return. 
                // Because there is not enough bytes to correctly read the data?

    quint16 blockSize = 0;
    in >> blockSize; // i noticed that after this line executes
                     // tcpServerConnection->bytesAvailable is substracted by 2
                     // and blockSize = 8 instead of 10, because 
                     // tcpServerConnection->bytesAvailable starts with 10.
                     // it seems that the socket recognizes that a quint16 was appended
                     // before the actual data, hence the 8 bytes. Is this correct?

    if (tcpServerConnection->bytesAvailable() < blockSize)
        return;

    QString data;
    in >> data;
    qDebug() << "data = " << data;

因此,这些问题的主要目的是能够将数据从PHP脚本发送到服务器,因此我需要(并希望)了解整个过程的工作原理。如果有人能对这个黑洞发光,我会很高兴的:D

注意服务器和客户端是使用QTcpSocket和QTcpServer编写的。

1 个答案:

答案 0 :(得分:2)

TCP是字节流协议,这意味着数据以有序的字节流发送和接收,而不保留任何逻辑消息边界。在这方面,当您的终端设置为无缓冲模式时,读取数据有点像读取std::cin:您可能会获得用户键入的下一个字符,或10个字符,或完整的行,一行或一半或接下来的4k。关于你可以确定的唯一一件事就是你不能获得比写入流更多的东西。当你有足够的数据来处理有意义的事情时,你需要解决这个问题:那可能是......

  • 扫描像'\n'这样的标记字符,知道完整的输入行是值得处理的“逻辑”消息

  • 在下一个逻辑消息的前面加上一个长度,可以是固定长度字段(更简单),也可以是可变长度文本,后跟已知的分隔符,如空格或换行符;这是您的代码使用2字节quint16 size值进行的操作

  • 将每条逻辑消息填充到固定长度

然后有必要保留read()recv(),直到读取了足够的字节来处理下一条逻辑消息。

似乎您的QDataStream通过read() / {{}}尽可能让您更轻松 - 可能是在后台线程中,或者当您的应用处于空闲状态时。它显然提供recv()作为已经从TCP流接收并且在其缓冲区中的字节数。

在客户端:

bytesAvailable()

这将写入一个2字节的“0”值,后跟QString string(messageLineEdit->text()); QByteArray block; QDataStream out(&block, QIODevice::WriteOnly); out.setVersion(QDataStream::Qt_4_0); out << quint16(0) << string; // why is the quint16 appended before the string? 的文本。前者有效地为string的长度保留空间。

string

这会在字符串之前跳回到上面写入2字节“0”值的地方......

out.device()->seek(0); // set current position to 0, why exactly?

这将覆盖上面写的“0”值和字符串的实际大小,它通过从out << (quint16)(block.size() - sizeof(quint16)); // substract 16bit unsigned int from the total data size? 大小中减去2个字节来确定。

在服务器端,看起来每次收到更多数据时都会调用该函数,并检查是否有足够的数据作为下一条消息进行解析。它看起来很麻烦,好像有足够的数据来解析block但整个字符串还没有被缓冲,然后它返回并且这样做会丢弃size的所有知识,这将是已经从blockSize中删除。相反,它应该记住QDataStream某处(例如在类成员变量中),并且下次调用它的函数应该从blockSize继续。