2015-09-08 39 views
0

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

插座是顺序I/O设备,并寻求它们是没有操作。不要在他们身上寻找! –

+1

...但您的代码中的第一个搜索是有效的。你正在寻找一个缓冲区,而不是套接字:) –

+0

@KubaOber aaah是的,我已经从下面的评论中得到:D谢谢! – CantThinkOfAnything

回答

2

TCP是一个字节流协议,这意味着数据以有序的字节流发送和接收,而不保留任何逻辑消息边界。在这方面,读取数据有点像读取终端设置为非缓冲模式时的std::cin:您可能会得到用户输入的下一个字符,或者10个字符,或者一个完整的行,一行半或下一个4k。关于唯一可以确定的是,您无法获得比写入流更多的内容。这是给你的工作了,当你有足够的数据有意义的过程:这可能是由...

  • 扫描像'\n'一个标记字符,知道输入的完整的生产线是不同的“逻辑“值得处理的消息

  • 预先将下一个逻辑消息的长度作为固定长度字段(更容易)或可变长度的文本,后面跟着已知的分隔符,如空格或换行符;这是你的代码与2字节quint16size

  • 填充每个逻辑消息做一个固定长度

它是那么必要保持read() ING或recv()操作直到足够的字节已经为您读取以处理下一个逻辑消息。

看来你的QDataStream正在让你更容易通过read() ing/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个字节来确定。

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

+0

谢谢你的明确解释。所以如果我是正确的,在服务器端,“in >> blocksize”只在变量内传送2位,因为变量是类型quint16,它是2位。前2位包含8字节的字符串长度,因此blocksize = 8(证实我在调试中看到的内容)。我也没有意识到,在客户端,seek(0)将流放在第一个位置,然后用REAL消息的大小覆盖前两个字节。 – CantThinkOfAnything

+1

@CantThinkOfAnything:正确的想法,虽然'quint16'是两个*字节*,而不是位。 'seek(0)'这个东西很愚蠢,因为字符串的大小必须可以直接写入文件而没有这种欺骗。 –

+0

啊的确如此,那是一个错字。并且用查找位,你说我可以首先附加消息的大小,然后附加字符串,而不是附加空白大小的单位,然后再附加字符串,然后再次实际大小。所以基本上2步而不是3。对不对? – CantThinkOfAnything

相关问题