我有一个UDP服务器使用以下代码:
void initialize() { connect(&_udpSocket, SIGNAL(readyRead()), this, SLOT(onUdpDatagram())); _udpSocket.bind(QHostAddress::Any, 28283); } void onUdpDatagram() { qDebug() << "udp packet received!"; _udpSocket.write("Hello"); }
不幸的是,当收到UDP数据包时,我在日志中有以下错误:
QIODevice::write: device not open
如何使UDP套接字可写?我尝试为连接到发件人地址和端口的答案创建另一个套接字,但发送将不再使用28283端口...
任何的想法?
有关信息:我在MacOS 10.9上使用Qt 5.2.1
UDP不是基于连接的协议.您没有为每个对等体获得单独的套接字,而是在一个端口上有一个用于所有通信的套接字.
因此,需要额外的努力来回复传入的UDP数据包.您需要从收到的数据报中检索发件人地址,然后发回相同的地址.在套接字API中,这是通过使用recvfrom
和sendto
函数而不是recv
(或read
)和send
(或write
)来完成的 - 后者是为与TCP一起使用的连接套接字而设计的.
你没有显示你的_udpSocket
变量的声明(实际上,类型),所以我假设你使用的是QUdpSocket
.在这种情况下,看起来你会想要使用readDatagram
和writeDatagram
函数,它们recvfrom
和对象sendto
地址有一个额外的参数(实际上,它是一对,一个用于IP地址,一个用于端口).
以下是Qt文档中有关的内容:
使用此类的最常用方法是使用bind()绑定到地址和端口,然后调用writeDatagram()和readDatagram()来传输数据.如果要使用标准QIODevice函数read(),readLine(),write()等,必须首先通过调用connectToHost()将套接字直接连接到对等体.
巧合的是,这个警告是我在Qt上游引入的:
QIODevice :: write:设备未打开
它应该非常清楚,不像之前介绍的那样,即:你忘了用你的udp socket连接到主机.如果它甚至没有打开和/或连接,你不能指望它写和/或读.有关详细信息,请参阅文档
如果要使用标准QIODevice函数read(),readLine(),write()等,必须首先通过调用connectToHost()将套接字直接连接到对等体.
您必须在代码中的某处执行以下操作:
_udpSocket.connectToHost(myHostAddress, 28283, ReadWrite, AnyIPProtocol);
最后两个参数可以跳过,因为它们是默认值.正如您可以从文档中读到的,此方法调用也将为您打开套接字,这对于完成QIODevice
读写操作是必要的.
话虽这么说,你真的不应该忽视你的代码中的错误检查,因为它目前似乎是站立的.以这种方式找到问题将很困难.
此外,它是冰上蛋糕,但我鼓励你开始使用"新"信号槽语法,这不是那么新,但更现代和更方便:
void initialize() { connect(&_udpSocket, &QUdpSocket::connected, [&_udpSocket]() { connect(&_udpSocket, &QUdpSocket::readyRead, [&_udpSocket]() { qDebug() << "udp packet received!"; if (_udpSocket.write("Hello") != 6) qDebug() << "Failed to write:" << _udpSocket.errorString(); }); }); connect(&_udpSocket, &QUdpSocket::error, [&_udpSocket]() { qDebug() << "Error occured:" << _udpSocket.errorString(); }); _udpSocket.connectToHost(myHostAddress, 28283, ReadWrite, AnyIPProtocol); }