QLocalSocket真的用于命名管道吗?

Is QLocalSocket really used for namedpipes

本文关键字:管道 真的 用于 QLocalSocket      更新时间:2023-10-16

根据Qt文档,如果我们想在Windows上使用命名管道,我们可以使用QLocalSocket。我正在使用Qt编写服务器和客户端程序。如果我尝试使用 WIN32 API 在管道线中写入一些消息,Qt 客户端不会显示它。此外,如果客户端再次使用 WIN32 API 写入,Qt 服务器不会回显发送的消息。QLocalSocket 真的推荐用于命名管道吗?

这是 Win32 服务器代码

     wcout << "Creating an instance of a named pipe..." << endl;
    // Create a pipe to send data
    HANDLE pipe = CreateNamedPipeW(
        L"\\.\pipe\ServicePipe", // name of the pipe
        PIPE_ACCESS_OUTBOUND, // 1-way pipe -- send only
        PIPE_TYPE_BYTE, // send data as a byte stream
        100, // only allow 1 instance of this pipe
        0, // no outbound buffer
        0, // no inbound buffer
        0, // use default wait time
        NULL // use default security attributes
        );
    if (pipe == NULL || pipe == INVALID_HANDLE_VALUE) {
        wcout << "Failed to create outbound pipe instance.";
        // look up error code here using GetLastError()
        system("pause");
        return 1;
    }
    wcout << "Waiting for a client to connect to the pipe..." << endl;
    // This call blocks until a client process connects to the pipe
    BOOL result = ConnectNamedPipe(pipe, NULL);
    if (!result) {
        wcout << "Failed to make connection on named pipe." << endl;
        // look up error code here using GetLastError()
        CloseHandle(pipe); // close the pipe
        system("pause");
        return 1;
    }
    wcout << "Sending data to pipe..." << endl;
    // This call blocks until a client process reads all the data
    wcout <<endl<<"Input your message: ";
    wstring data=L"";
    getline(wcin,data);
    DWORD numBytesWritten = 0;
    result = WriteFile(
        pipe, // handle to our outbound pipe
        data.c_str(), // data to send
        wcslen(data.c_str()) * sizeof(wchar_t), // length of data to send (bytes)
        &numBytesWritten, // will store actual amount of data sent
        NULL // not using overlapped IO
        );

    if (result) {
        wcout << "Number of bytes sent: " << numBytesWritten << endl;
    } else {
        wcout << "Failed to send data." << endl;
        // look up error code here using GetLastError()
    }
    // Close the pipe (automatically disconnects client too)
    CloseHandle(pipe);
    wcout << "Done." << endl;

这是 Win32 客户端:

    wcout << "Connecting to pipe..." << endl;
    // Open the named pipe
    // Most of these parameters aren't very relevant for pipes.
    HANDLE pipe = CreateFileW(
        L"\\.\pipe\ServicePipe",
        GENERIC_READ, // only need read access
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
        );
    if (pipe == INVALID_HANDLE_VALUE) {
        wcout << "Failed to connect to pipe." << endl;
        // look up error code here using GetLastError()
        system("pause");
        return 1;
    }
    wcout << "Reading data from pipe..." << endl;
    // The read operation will block until there is data to read
    wchar_t buffer[128];
    DWORD numBytesRead = 0;
    BOOL result = ReadFile(
        pipe,
        buffer, // the data from the pipe will be put here
        127 * sizeof(wchar_t), // number of bytes allocated
        &numBytesRead, // this will store number of bytes actually read
        NULL // not using overlapped IO
        );
    if (result) {
        buffer[numBytesRead / sizeof(wchar_t)] = '?'; // null terminate the string
        wcout << "Number of bytes read: " << numBytesRead << endl;
        wcout << "Message: " << buffer << endl;
    } else {
        wcout << "Failed to read data from the pipe." << endl;
    }
    // Close our pipe handle
    CloseHandle(pipe);
    wcout << "Done." << endl;

这是Qt服务器端

   LocalSocketIpcServer::LocalSocketIpcServer(QString servername, QObject *parent)
:QObject(parent) {
m_server = new QLocalServer(this);
if (!m_server->listen(servername)) {
    showMessage("Not able to start the Server");
}
connect(m_server, SIGNAL(newConnection()), this, SLOT(socket_new_connection()));
}
LocalSocketIpcServer::~LocalSocketIpcServer() {
}

void LocalSocketIpcServer::socket_new_connection() {
QLocalSocket *clientConnection = m_server->nextPendingConnection();
while (clientConnection->bytesAvailable() < (int)sizeof(quint32))
    clientConnection->waitForReadyRead();

//connect(clientConnection,SIGNAL(readyRead()),clientConnection,SLOT(rea));
connect(clientConnection, SIGNAL(disconnected()),clientConnection, SLOT(deleteLater()));
QDataStream in(clientConnection);
in.setVersion(QDataStream::Qt_5_1);
if (clientConnection->bytesAvailable() < (int)sizeof(quint16)) {
    return;
}
QString message;
in >> message;
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
QString msg=+"Message recieved with content "+message+"n";
out.setVersion(QDataStream::Qt_5_1);
out <<msg;
out.device()->seek(0);
clientConnection->write(block);
clientConnection->flush();
clientConnection->disconnectFromServer();
emit messageReceived(message);
}

void LocalSocketIpcServer::showMessage(QString msg)
{
QMessageBox m;
m.setText(msg);
m.exec();
}
LocalSocketIpcServer::FrmMain(QWidget *parent) :QMainWindow(parent),ui(new Ui::FrmMain)
{
ui->setupUi(this);
m_server = new LocalSocketIpcServer("\\.\pipeServicePipe", this);
connect(m_server, SIGNAL(messageReceived(QString)), this, SLOT(messageReceived(QString)));
}
LocalSocketIpcServer::~FrmMain()
{
delete ui;
}
void LocalSocketIpcServer::messageReceived(QString message)
{
   ui->textBrowser->append(message+"n");
}

这是Qt客户端

LocalSocketIpcClient::LocalSocketIpcClient(QString remoteServername, QObject *parent) :
    QObject(parent) {
m_socket = new QLocalSocket(this);
m_serverName = remoteServername;
connect(m_socket, SIGNAL(connected()), this, SLOT(socket_connected()));
connect(m_socket, SIGNAL(disconnected()), this, SLOT(socket_disconnected()));
connect(m_socket, SIGNAL(readyRead()), this, SLOT(socket_readReady()));
connect(m_socket, SIGNAL(error(QLocalSocket::LocalSocketError)),
        this, SLOT(socket_error(QLocalSocket::LocalSocketError)));
}
LocalSocketIpcClient::~LocalSocketIpcClient() {
m_socket->abort();
delete m_socket;
m_socket = NULL;
}
QString LocalSocketIpcClient::Read()
{
QDataStream in(this->m_socket);
in.setVersion(QDataStream::Qt_5_1);
if (m_socket->bytesAvailable() < (int)sizeof(quint16)) {
    return "No data available";
}
QString message;
in >> message;
return message;
}
void LocalSocketIpcClient::send_MessageToServer(QString message) {
m_socket->abort();
m_message = message;
m_socket->connectToServer(m_serverName,QIODevice::ReadWrite);
}

void LocalSocketIpcClient::socket_connected(){
QByteArray block;
QDataStream out(&block, QIODevice::ReadWrite);
out.setVersion(QDataStream::Qt_5_1);
out << m_message;
out.device()->seek(0);
m_socket->write(block);
m_socket->flush();
}
 void LocalSocketIpcClient::socket_disconnected() {
 //showMessage("Client socket_disconnected");
}

void LocalSocketIpcClient::socket_readReady() {
//showMessage("Client socket read Ready");
QDataStream in(this->m_socket);
in.setVersion(QDataStream::Qt_5_1);
if (m_socket->bytesAvailable() < (int)sizeof(quint16)) {
    return;
}
QString message;
in >> message;
emit RecievedDataFromServer(message);
}
void LocalSocketIpcClient::socket_error(QLocalSocket::LocalSocketError e) {
/*
QString errorMessage="Client socket_error:";
switch (e) {
case QLocalSocket::ConnectionRefusedError:
    errorMessage+="The connection was refused by the peer (or timed out).";
    break;
case QLocalSocket::PeerClosedError:
    errorMessage+="The remote socket closed the connection. Note that the client socket (i.e., this socket) will be closed after the remote close notification has been sent.";
    break;
case QLocalSocket::ServerNotFoundError:
    errorMessage+="The local socket name was not found.";
    break;
case QLocalSocket::SocketAccessError:
    errorMessage+="The socket operation failed because the application lacked the required privileges.";
    break;
case QLocalSocket::SocketResourceError:
    errorMessage+="The local system ran out of resources (e.g., too many sockets).";
    break;
case QLocalSocket::SocketTimeoutError:
    errorMessage+="The socket operation timed out.";
    break;
case QLocalSocket::DatagramTooLargeError:
    errorMessage+="The datagram was larger than the operating system's limit (which can be as low as 8192 bytes).";
    break;
case QLocalSocket::ConnectionError:
    errorMessage+="An error occurred with the connection.";
    break;
case QLocalSocket::UnsupportedSocketOperationError:
    errorMessage+="The requested socket operation is not supported by the local operating      system.";
    break;
case QLocalSocket::UnknownSocketError:
    errorMessage+="An unidentified error occurred.";
    break;
default:
    break;
}
showMessage(errorMessage);
*/
}
void LocalSocketIpcClient::showMessage(QString msg)
{
QMessageBox m;
m.setText(msg);
m.exec();
}
LocalSocketIpcClient::SingleMessageSend(QWidget *parent) :
QDialog(parent),
ui(new Ui::SingleMessageSend)
{
ui->setupUi(this);
client  = new LocalSocketIpcClient("\\.\pipeServicePipe", this);
connect(this->client,SIGNAL(RecievedDataFromServer(QString)),this,SLOT(UpdateGUI(QString)));
}
LocalSocketIpcClient::~SingleMessageSend()
{
delete ui;
}
void SingleMessageSend::on_pushButton_clicked()
{
QString msg=this->ui->lineEdit->text().trimmed();
client->send_MessageToServer(msg);
}
void SingleMessageSend::UpdateGUI(QString message)
{
 ui->textEdit->insertPlainText(message+"n");
}
void SingleMessageSend::on_pushButton_2_clicked()
{
ui->textEdit->insertPlainText(client->Read()+QString("n"));
}

无需浏览您的所有代码,我可以肯定地回答这个问题。 以下是来自工作应用程序的一些代码,该代码从Qt应用程序写入另一个Qt应用程序中的命名管道(它恢复了另一个最小化的应用程序):

QLocalSocket ls;
ls.connectToServer("Restore Server", QIODevice::WriteOnly);
if (!ls.waitForConnected(5000))
{
        qDebug(ls.errorString().toUtf8());
        return false;
}
ls.write("raise");
if (!ls.waitForBytesWritten(5000))
{
        qDebug(ls.errorString().toUtf8());
        return false;
}
ls.disconnectFromServer();

要还原的应用程序设置如下:

localServer = new QLocalServer(this);
connect(localServer, SIGNAL(newConnection()), this,
    SLOT(messageFromOtherInstance()));
localServer->listen("Restore Server");

当需要阅读消息时,我是这样做的:

QLocalSocket *localSocket = localServer->nextPendingConnection();
if (!localSocket->waitForReadyRead(5000))
{
        qDebug(localSocket->errorString().toLatin1());
        return;
}
QByteArray byteArray = localSocket->readAll();
QString message = QString::fromUtf8(byteArray.constData());
if (message == "raise")
    bringToTop(this);

很可能是Qt命名管道和M$命名管道在某种程度上不兼容。 我建议编写一个 M$ 框架应用程序来写入 M$ 框架客户端,并编写一个 M$ 框架应用程序来读取,以确保它们都正常工作。 然后,替换Qt应用程序以从Qt服务器读取。 如果这不起作用,那就是某种框架不兼容(尽管我希望它们都与操作系统正确交互)。 在这种情况下要确定的一件事是确保进程不会阻塞。 这就是为什么例如,我在阅读之前确保阅读准备就绪。 在 M$ 侧写入后,您可能还必须冲洗管道,尽管我没有使用 Qt。

(请注意,我后来发现,如果打开了"打印"、"打印预览"、"页面设置"或"浏览文件"对话框,它将停止Qt消息循环,并且应用程序将无法响应此类消息。 "选择字体"对话框 OTOH 不会阻止父应用。 去图。