Qt: Python TCP客户端通过套接字发送数据。如何用Qt读取这些字节?
情况:
我有一个用Python写的TCP客户端和一个用Qt写的TCP服务器。我尝试用我的客户端发送字节,但Qt服务器就是无法读取这些字节。
如果我用Python写的客户端和服务器,所有东西都运行得很好。而且,我也能让我的Python客户端和C#服务器顺利工作。
这是Python客户端的代码:
import socket
import sys
HOST = 'localhost'
PORT = 50505
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error as msg:
sys.stderr.write("[ERROR] %s\n" % msg)
sys.exit(1)
try:
sock.connect((HOST, PORT))
except socket.error as msg:
sys.stderr.write("[ERROR] %s\n" % msg)
sys.exit(2)
sock.send(b'Hello World!\r\n')
我试过一些示例代码,比如fortuneserver/fortuneclient,但都没用。bytesavailable()总是返回0。
所以我的问题是,如何在我的Qt应用中读取“Hello World!”这一行呢?我只需要一个函数,当服务器发出newConnection()信号时能启动这个函数。
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(startRead()));
更新:
这是Qt服务器的一部分代码:
void Server::startRead()
{
QDataStream in(tcpSocket);
in.setVersion(QDataStream::Qt_4_0);
QString ipAddress;
if (blockSize == 0) {
if (tcpSocket->bytesAvailable() < (int)sizeof(quint16))
return;
in >> blockSize;
}
if (tcpSocket->bytesAvailable() < blockSize)
return;
QString nextFortune;
in >> nextFortune;
statusLabel->setText(nextFortune);
ABOVE IS FROM FORTUNE CLIENT EXAMPLE.
BELOW IS FROM ANOTHER EXAMPLE.
/*
char buffer[128] = {0};
QTcpSocket *client = tcpServer->nextPendingConnection();
qDebug() << client->bytesAvailable();
for (int i=0; i<100; i++)
{
client->read(buffer, client->bytesAvailable());
qDebug() << buffer;
std::string sString(buffer);
QString qString(sString.c_str());
statusLabel->setText(qString);
}
*/
}
最后那部分代码写得很糟糕。我试着做点什么,但我对Qt完全没有头绪 :)
2 个回答
你附上的服务器代码是这样工作的:每个“数据包”(逻辑上的一个)由一个 size
字段和接下来与这个 size
相等的数据组成。
基本流程是这样的:
- 先读取一个
quint16
,如果没有足够的字节可读,就等着。 - 读取到
quint16
后,等到至少有这个quint16
指定的字节数可以读取。 - 一旦有足够的数据,就可以读取这些数据了。
理解了这些后,即使你按照服务器的要求写了数据包的长度,你的操作仍然不会成功。这是因为服务器从套接字读取 QString
的方式。客户端写的是原始的 Python 字符串,我猜它只是把普通的 ASCII 字符写入了套接字。服务器则是使用 QDataStream
从套接字读取数据(这是 Qt 中序列化的标准方式)。如果你查看 QString
的操作符<< 的实现,在这里,你会发现它做的事情比读取一个 ASCII 字符串要复杂得多。
如果你不能更改服务器,那就改改你的客户端吧。你可以在 PyQt 附带的示例中看到 fortune 客户端的实现。
你需要让你的代码在有数据可用的时候去读取。根据你的描述,startRead()
运行时还没有数据可用。
我猜你在startRead()
里调用了QTcpServer::nextPendingConnection
来获取你的tcpSocket
?如果没有,你需要这样做。
只需将你的tcpSocket
或client
的readyRead
信号连接到一个doRead()
槽函数,然后在这个槽函数里检查bytesAvailable()
并读取数据。
每当有新数据到达时,这个槽函数就会被调用。
你可能还会对你的TCP套接字的disconnected()
信号感兴趣,这样你就能知道什么时候数据发送完毕。