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

How does the process of sending data through a socket really work?

本文关键字:何工作 工作 过程 套接字 数据      更新时间:2023-10-16

我已经写了一个服务器/客户端设置,可以来回发送字符串,它的工作。现在我正试图从一个不工作的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编写。

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

  • 扫描像'n'这样的前哨字符,知道完整的输入行是值得处理的不同的"逻辑"消息

  • 为下一个逻辑消息添加长度,可以是固定长度字段(更容易),也可以是后跟已知分隔符(如空格或换行符)的可变长度文本;这就是你的代码对2字节quint16 size值所做的

  • 将每个逻辑消息填充为固定长度

有必要保持read() ing或recv() ing,直到有足够的字节被读取,以便您处理下一个逻辑消息。

似乎你的QDataStream是使这更容易为你read()/recv() ing只要它可以-也许在后台线程或当你的应用程序是空闲的。显然,它提供了bytesAvailable()作为它已经从TCP流接收到的字节数,并在它的缓冲区中。

客户端:

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?

写入一个2字节的"0"值,后面跟着string的文本。前者有效地为string的长度保留了空间。

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

这将跳转到字符串之前的2字节"0"值上面写的地方…

out << (quint16)(block.size() - sizeof(quint16)); // substract 16bit unsigned int from the total data size? 

这将用字符串的实际大小覆盖上面写的"0"值,它通过从block大小中减去2个字节来确定。

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