Qt: Python TCP客户端通过套接字发送数据。如何用Qt读取这些字节?

1 投票
2 回答
3950 浏览
提问于 2025-04-15 18:25

情况:

我有一个用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 个回答

0

你附上的服务器代码是这样工作的:每个“数据包”(逻辑上的一个)由一个 size 字段和接下来与这个 size 相等的数据组成。

基本流程是这样的:

  1. 先读取一个 quint16,如果没有足够的字节可读,就等着。
  2. 读取到 quint16 后,等到至少有这个 quint16 指定的字节数可以读取。
  3. 一旦有足够的数据,就可以读取这些数据了。

理解了这些后,即使你按照服务器的要求写了数据包的长度,你的操作仍然不会成功。这是因为服务器从套接字读取 QString 的方式。客户端写的是原始的 Python 字符串,我猜它只是把普通的 ASCII 字符写入了套接字。服务器则是使用 QDataStream 从套接字读取数据(这是 Qt 中序列化的标准方式)。如果你查看 QString 的操作符<< 的实现,在这里,你会发现它做的事情比读取一个 ASCII 字符串要复杂得多。

如果你不能更改服务器,那就改改你的客户端吧。你可以在 PyQt 附带的示例中看到 fortune 客户端的实现。

1

你需要让你的代码在有数据可用的时候去读取。根据你的描述,startRead()运行时还没有数据可用。

我猜你在startRead()里调用了QTcpServer::nextPendingConnection来获取你的tcpSocket?如果没有,你需要这样做。

只需将你的tcpSocketclientreadyRead信号连接到一个doRead()槽函数,然后在这个槽函数里检查bytesAvailable()并读取数据。

每当有新数据到达时,这个槽函数就会被调用。

你可能还会对你的TCP套接字的disconnected()信号感兴趣,这样你就能知道什么时候数据发送完毕。

撰写回答