【发布时间】:2015-12-04 14:38:57
【问题描述】:
我很难读取通过套接字连接发送到 Qt 服务器应用程序的字符输入。数据由 PHP 发送。
我了解读取流数据的原理,因为我已经在堆栈上问过这个问题。我还使用 Qt 编写的服务器和客户端使其工作。
我使用的方法是将要发送的数据的字节大小附加在实际数据之前。然后当数据进来时,我首先读取长度部分,这样我就知道我必须读取多少字节才能正确形成数据。
看起来像这样:
发送函数:
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);
out << string;
out.device()->seek(0);
out << (quint16)(block.size() - sizeof(quint16));
tcpSocket->write(block);
}
接收函数:
QDataStream in(tcpServerConnection);
in.setVersion(QDataStream::Qt_4_0);
qDebug() << "bytes available = " << tcpServerConnection->bytesAvailable();
if (blockSize == 0) {
int size = (int) sizeof(quint16);
qDebug() << "size = " << size;
if (tcpServerConnection->bytesAvailable() < (int)sizeof(quint16)){
qDebug() << "less bytes than size...";
return;
}
qDebug() << "bytes available=" << tcpServerConnection->bytesAvailable();
in >> blockSize;
}
if (tcpServerConnection->bytesAvailable() < blockSize){
qDebug() << "less bytes available than blocksize, bytes="
<< tcpServerConnection->bytesAvailable();
return;
}
QString data;
in >> data;
qDebug() << "data = " << data;
好的,这一切都有效,所以我尝试用 PHP 做,但失败了
这是我的尝试之一:
<?php
$addr = gethostbyname("127.0.0.1");
$client = stream_socket_client("tcp://$addr:*****", $errno, $errorMessage);
if ($client === false) {
throw new UnexpectedValueException("Failed to connect: $errorMessage");
}
$data = 'a';
$datatopost = serialize($data);
fwrite($client, strlen($data));
fwrite($client, base64_encode($data));
echo stream_get_contents($client);
fclose($client);
在 Qt 中,我尝试了 quint8、16、32、64、sizeof(char)、sizeof(int) 的各种组合。
在 PHP 中,我尝试过对数据进行序列化、编码,并在没有这些东西的情况下发送它。但我无法让它工作。我必须非常接近,因为数据实际上是发送的,因为有可用的字节,但我不知道如何正确编码/解码以使其工作。
在问了关于这个话题的各种问题后,我确实觉得我的理解有了很大的提高,但我仍然缺少关于如何实际做事的重要信息。
所以我的问题是:这里出了什么问题,需要采取哪些步骤才能将数据从 PHP 读取到 Qt/C++?
非常感谢细节,因为我真的很想知道事情是如何从内到外的。
side-note 从 PHP 脚本发送数据后,服务器将数据发送回原样,这样就可以了。这样连接就成功了
更新 这是实际也收到回复的工作 php 脚本:
<?php
if(!($sock = socket_create(AF_INET, SOCK_STREAM, 0)))
{
perror("Could not create socket");
}
echo "Socket created n";
//Connect socket to remote server
if(!socket_connect($sock , '127.0.0.1' , *****))
{
perror("Could not connect");
}
echo "Connection established n";
$message = "aa";
//Send the message to the server
if( ! socket_send ( $sock , $message , strlen($message) , 0))
{
perror("Could not send data");
}
echo "Message send successfully n";
//Now receive reply from server
if(socket_recv ( $sock , $buf , 500 , MSG_WAITALL ) === FALSE)
{
perror("Could not receive data");
}
echo $buf;
///Function to print socket error message
function perror($msg)
{
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("$msg: [$errorcode] $errormsg n");
}
从浏览器 url 执行时的脚本回复:
Socket created nConnection established nMessage send successfully n hello
【问题讨论】:
-
QDataStream 需要对数据进行特殊编码。您确定您的 PHP 代码正在以 QDataStream 4.0 格式读取/写入数据吗?否则两端都会看到垃圾......
-
@tux3 好吧,我肯定没有在 PHP 中指定任何 QDataStream 格式。尽管 php 脚本确实回显了服务器发回的数据。我在上面发布的代码再次被编辑了一点,所以现在 php 脚本没有收到任何数据。但我相信一个小的编辑会解决这个问题。服务器确实收到了字节,我不知道这是否足够。我有点迷失在我尝试过的所有各种事情中,我忘记记录 100% 有效的事情
-
没关系。我错了。我不确定您是否应该使用
QDataStream阅读。相反 - 创建您自己的协议,例如 - 前 8 个字节 = 数据包大小,然后发送原始数据。并直接读入,使用QIODevice::read方法(在QTcpSocket中重新实现)。 -
因为
QDataStream实现了它自己的序列化协议。如果您想使用QDataStream,请查看readRawData和writeRawData方法。 -
我不懂PHP,所以帮不上忙。请注意类型大小和字节顺序(大/小端)的错误。