我想使用QTCPSocket发送和接收结构。
系统确实有一个中央套接字服务器和许多Qt客户端应用程序。 每个客户端都发送一个结构,由中央套接字服务器向其余部分广播。
Connector
延伸QTcpSocket
这是我的连接方法
void Connector::Open(QString address, int port) // It works!
{
connectToHost(address, port);
this->onWaiting();
connect(this, SIGNAL(connected()), this, SLOT(connected()));
connect(this, SIGNAL(disconnected()), this, SLOT(disconnected()));
connect(this, SIGNAL(readyRead()), this, SLOT(readyRead()));
connect(this, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWritten(qint64)));
}
这是我发送数据的方法
void Connector::SendData(const void* data,qint64 len) // It works!
{
writeData((char*)data,len);
waitForBytesWritten();
}
这是为了接收
void Connector::readyRead() // Don't work
{
Information n; //My struct
memcpy(&n, data.data(), data.size());
onInformationReceived(n);
}
但收到的信息总是无效的。那是对的吗?
答案 0 :(得分:1)
存在一些问题:
可以使用任意数量的可用于读取的字节调用readyRead()
槽。你唯一的保证是它超过零字节,尽管在实践中没有理由依赖它。你必须检查bytesAvailable
。它可以是一个字节。它可以是兆字节。
参见例如this answer和that answer用于叙述,that one用于代码。
至少,你需要:
void Connector::readyRead() {
if (bytesAvailable() < sizeof(Information)) return;
Information info;
auto const data = read(sizeof(Information));
memcpy(&info, data.constData(), data.size());
onInformationReceived(info);
}
通过网络发送struct
作为不透明二进制文件将无效。无法保证接收端将以相同的方式布置结构。除非您参考编译器ABI文档,否则您甚至无法知道数据的二进制格式是什么。
参见例如this answer了解如何正确完成。
至少,您需要为QDataStream
实施Information
流媒体运营商,然后在连接的两端使用它:
QDataStream & operator<<(QDataStream &, const Information &);
QDataStream & operator>>(QDataStream &, Information &);
void Connector::send(const Information & info) {
auto dev = this; // We're a QIODevice :(
QDataStream stream{dev};
stream << info;
dev.waitForBytesWritten(); // this is superbly bad!
}
void Connector::readyRead() {
auto dev = this; // We're a QIODevice :(
QDataStream stream{dev};
stream.startTransaction();
Information info;
dev >> info;
if (! stream.commitTransaction()) return;
onInformationReceived(info);
}
您不应该延长QTcpSocket
。您的课程应为QObject
,其值为QTcpSocket
。
你永远不应该阻止。
因此,固定的Connector
类可能如下所示。同样,this answer介绍了如何正确使用QDataStream
来说明与代码的未来更新的兼容性。但另请参阅this answer了解如何利用Qt 5.7&#39; QDataStream
中的读取交易。
class Connector : public QObject {
Q_OBJECT
QTcpDevice m_dev;
QDataStream m_str{&m_dev};
void onReadyRead() {
m_str.startTransaction();
Information info;
m_str >> info;
if (! stream.commitTransaction()) return;
onInformationReceived(info);
}
void onBytesWritten() {
if (m_dev.bytesToWrite() == 0)
emit allDataSent();
}
void onInformationReceived(const Information &);
public:
Connector(const QString & address, int port, QObject * parent = nullptr) :
QObject{parent}
{
connect(&m_dev, &QAbstractSocket::connected, this, &Connector::connected);
connect(&m_dev, &QAbstractSocket::disconnected, this, &Connector::disconnected);
connect(&m_dev, &QIODevice::readyRead, this, onReadyRead);
connect(&m_dev, &QIODevice::bytesWritten, this, onBytesWritten);
m_dev.connect(address, port);
}
void send(const Information & info) {
m_str << info;
}
Q_SIGNAL void connected();
Q_SIGNAL void disconnected();
Q_SIGNAL void allDataSent();
}