2

我正在编写一个服务器作为 Qt 控制台应用程序。我将服务器设置为等待套接字连接,但我还需要允许用户将命令输入服务器以进行管理。两者都是独立工作的。但是,我遇到的问题是,当我在接受和处理输入命令的 while 循环中时,服务器不接受连接。

我有一个 Socket 类,在它的构造函数中,我有:

connect(server,SIGNAL(newConnection()),this, SLOT(newConnection()));

在构造函数的正下方,我调用了一个具有更深入版本的函数,用于从用户那里获取命令:

QTextStream qin(stdin, QIODevice::ReadOnly);
QString usrCmd;

while(usrCmd != "exit" && usrCmd != "EXIT") {   
    //Get command input and process here
}

在 newConnection() 中,我只接受下一个连接,然后使用套接字。

QTcpSocket *serverSocket = server->nextPendingConnection();

我怎样才能使套接字可以等待连接并同时等待用户输入的命令?

4

1 回答 1

2

您的代码有问题是因为您使用 while 循环阻塞了事件循环。因此,您的问题的解决方案是异步读取标准输入。在 Linux 上(我猜在 Mac 上),您可以QSocketNotifier根据各种 Internet 资源来通知数据何时到达标准输入,并手动读取它)。

当我使用 Windows 时,我建议您以这种方式进行(应该适用于所有平台):

  1. 打开从标准输入读取数据的线程
  2. 一旦你得到一些数据(也许是行?),你可以使用 Qt 信号槽机制将数据传递给主线程进行处理,而不会阻塞事件循环。

所以,这是伪代码。MainAppClass 应该是您现有的服务器类,只需编辑构造函数以创建新线程,并添加用于处理数据的新插槽。

class Reader: public QThread
{
    Q_OBJECT
 public:
    Reader(QObject * parent = 0 ): QThread(parent){}

    void run(void)
    {
         forever{
             std::string data;
             std::getline (std::cin, data);

             if(data == "exit")
             {
                 emit exitServer();
                 return;
             }


             emit dataReady(QString::fromStdString(data));
         }
     }

signals:
    void dataReady(QString data);
    void exitServer();

};



class MainAppClass: public QObject
{
    Q_OBJECT
public:
    MainAppClass()
    {
        Reader * tr = new Reader(this);
        connect(tr, SIGNAL(dataReady(QString)), this, SLOT(processData(QString)));
        connect(tr, SIGNAL(exitServer()), this, SLOT(exitServer()));
        tr->start();
    }

public slots:
    void processData(QString data)
    {

        std::cout << "Command: " << data.toStdString() << std::endl;
    }

    void exitServer()
    {
       std::cout << "Exiting..." << std::endl;
    }
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainAppClass myapp; //your server

    app.exec();
    return 0;
}

由于我编写了如何使用 QTcpSocket 的简单指南,所以这里是简短的

当您获得客户端QTcpSocket时,将信号连接到某个插槽,并从对象中readyRead()读取数据。sender()您不需要在构造函数中阅读任何内容。

对于阅读,您可以使用标准QIODevice功能。

注意:这是伪代码,您可能需要更改一些内容(检查读取流的状态、在某个列表中保存指向套接字的指针、订阅disconnected()信号、调用listen()构造函数、检查是否QTcpServer正在侦听等)。

所以,你需要onReadyRead()在你的类中有一个插槽,它将具有以下代码:

void Server::readyReadSlot()
{
    QTcpSocket *client = (QTcpSocket*)sender(); // get socket which emited the signal
    while(client->canReadLine()) // read all lines! 
                                 // If there is not any lines received (you may not always receive 
                                 // whole line as TCP is stream based protocol),
                                 // you will not leave data in the buffer for later processing.
    {
        QString line = client->readLine(); 
        processLine(line); // or emit new signal if you like
    }
}

在内部newConnection(),您需要将readyRead()信号与插槽连接。

void Server::newConnection()
{
    QTcpSocket *clientSocket = server->nextPendingConnection(); 
    connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
}
于 2013-02-04T23:04:52.430 回答