通过套接字发送数据的过程到底是如何工作的?
How does the process of sending data through a socket really work?
我已经编写了一个 server/client 设置,可以来回发送字符串并且可以正常工作。现在我正尝试从一个不起作用的 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'
这样的哨兵字符,知道完整的输入行是不同的 "logical" 值得处理的消息
为下一条逻辑消息预留长度,可以是固定长度字段(更简单)或可变长度文本,后跟已知分隔符,例如 space 或换行符;这就是您的代码对 2 字节 quint16
size
值
所做的
将每个逻辑消息填充到固定长度
然后有必要保持 read()
ing 或 recv()
ing,直到读取了足够的字节供您处理下一条逻辑消息。
似乎您的 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
.
的长度保留了 space
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
但整个字符串还没有被缓冲,然后它 returns 并且这样做会丢弃 [=27= 的所有知识],它已经从 QDataStream
中删除了。相反,它应该记住 blockSize
某处(例如在 class 成员变量中)并且下次调用该函数时它应该从 if (tcpServerConnection->bytesAvailable() < blockSize)
.
继续
我已经编写了一个 server/client 设置,可以来回发送字符串并且可以正常工作。现在我正尝试从一个不起作用的 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'
这样的哨兵字符,知道完整的输入行是不同的 "logical" 值得处理的消息为下一条逻辑消息预留长度,可以是固定长度字段(更简单)或可变长度文本,后跟已知分隔符,例如 space 或换行符;这就是您的代码对 2 字节
quint16
size
值 所做的
将每个逻辑消息填充到固定长度
然后有必要保持 read()
ing 或 recv()
ing,直到读取了足够的字节供您处理下一条逻辑消息。
似乎您的 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
但整个字符串还没有被缓冲,然后它 returns 并且这样做会丢弃 [=27= 的所有知识],它已经从 QDataStream
中删除了。相反,它应该记住 blockSize
某处(例如在 class 成员变量中)并且下次调用该函数时它应该从 if (tcpServerConnection->bytesAvailable() < blockSize)
.