我有一个socketDescriptor。
我需要两个插座。其中一个仅用于 ReadOnly,另一个用于 WriteOnly。
这是不可能的吗?如果是这样,怎么做?
Qt 的套接字不支持每个本地套接字具有多个套接字对象,但您可以通过创建适当的单向接口来近似这一点。
在下面的示例中,接口不执行任何缓冲,因此它们强制每个套接字的每种接口只有一次。一旦你使用了接口,你不应该直接使用套接字。
// https://github.com/KubaO/stackoverflown/tree/master/questions/socket-split-43409221
#include <QtNetwork>
class SocketBase : public QIODevice {
Q_OBJECT
public:
explicit SocketBase(QAbstractSocket * parent) : QIODevice{parent} {
connect(parent, &QAbstractSocket::connected, this, &SocketBase::connected);
connect(parent, &QAbstractSocket::disconnected, this, &SocketBase::disconnected);
connect(parent, &QAbstractSocket::stateChanged, this, [this](QAbstractSocket::SocketState state){
emit stateChanged(state);
setOpenMode(m_dev->openMode());
});
connect(parent,
static_cast<void(QAbstractSocket::*)(QAbstractSocket::SocketError)>(&QAbstractSocket::error),
this, [this](QAbstractSocket::SocketError error){
setErrorString(m_dev->errorString());
emit this->error(error);
});
setOpenMode(m_dev->openMode());
}
QAbstractSocket::SocketError error() const {
return m_dev->error();
}
QAbstractSocket::SocketState state() const {
return m_dev->state();
}
Q_SIGNAL void connected();
Q_SIGNAL void disconnected();
Q_SIGNAL void error(QAbstractSocket::SocketError);
Q_SIGNAL void stateChanged(QAbstractSocket::SocketState);
bool isSequential() const override { return true; }
protected:
QAbstractSocket * const m_dev = static_cast<QAbstractSocket*>(parent());
};
class ReadSocket : public SocketBase {
Q_OBJECT
public:
explicit ReadSocket(QAbstractSocket * parent) : SocketBase(parent) {
for (auto proxy : parent->findChildren<ReadSocket*>())
Q_ASSERT(proxy == this);
connect(m_dev, &QIODevice::readyRead, this, &QIODevice::readyRead);
}
bool atEnd() const override {
return QIODevice::atEnd() && m_dev->atEnd();
}
qint64 bytesAvailable() const override {
return m_dev->bytesAvailable();
}
bool canReadLine() const override {
return m_dev->canReadLine();
}
protected:
qint64 readData(char * data, qint64 maxLength) override {
return m_dev->read(data, maxLength);
}
qint64 readLineData(char *data, qint64 maxLength) override {
return m_dev->readLine(data, maxLength);
}
qint64 writeData(const char *, qint64) override {
return -1;
}
};
class WriteSocket : public SocketBase {
Q_OBJECT
public:
explicit WriteSocket(QAbstractSocket * parent) : SocketBase(parent) {
for (auto proxy : parent->findChildren<WriteSocket*>())
Q_ASSERT(proxy == this);
connect(m_dev, &QIODevice::bytesWritten, this, &QIODevice::bytesWritten);
}
qint64 bytesToWrite() const override {
return m_dev->bytesToWrite();
}
bool flush() {
return m_dev->flush();
}
protected:
qint64 readData(char *, qint64) override {
return -1;
}
qint64 writeData(const char * data, qint64 length) override {
return m_dev->write(data, length);
}
};
int main(int argc, char *argv[])
{
QCoreApplication app{argc, argv};
QHostAddress addr{"127.0.0.1"};
quint16 port{9341};
QTcpServer server;
if (! server.listen(addr, port)) qFatal("can't listen");
QObject::connect(&server, &QTcpServer::newConnection, &server, [&]{
auto s = server.nextPendingConnection();
QObject::connect(s, &QTcpSocket::readyRead, s, [s]{
s->write(s->readAll());
});
QObject::connect(s, &QTcpSocket::disconnected, s, &QObject::deleteLater);
});
const char data_[] = "dhfalksjdfhaklsdhfklasdfs";
auto const data = QByteArray::fromRawData(data_, sizeof(data_));
QTcpSocket client;
WriteSocket writer(&client);
ReadSocket reader(&client);
QObject::connect(&writer, &WriteSocket::connected, [&]{
writer.write(data);
});
QObject::connect(&reader, &ReadSocket::readyRead, [&]{
if (reader.bytesAvailable() >= data.size()) {
auto const read = reader.read(data.size());
Q_ASSERT(read == data);
qApp->quit();
}
});
client.connectToHost(addr, port);
return app.exec();
}
#include "main.moc"