c++ - Qt C++ 控制台服务器,等待套接字连接并同时接受输入?

标签 c++ qt sockets input

我正在编写一个服务器作为 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();

如何才能使套接字可以同时等待连接和等待用户输入的命令?

最佳答案

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

由于我使用的是 Windows,我建议您这样做(应该适用于所有平台):

  1. 打开从stdin读取数据的线程
  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()));
}

关于c++ - Qt C++ 控制台服务器,等待套接字连接并同时接受输入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14697168/

相关文章:

c++ - 重写 Qt 的 mousePressEvent 会破坏 moveEvent 参数

c# - C#(ASP.NET)通过套接字与Android通信

c# - 使用 recieveFrom 获取多播数据包的源 IP

c++ - 如何使用 boost::property_tree 解析带根数组的 JSON

c++ - 我不能在 C++ 函数中使用 new 来构建

c++ - QGraphicsView 是否拥有其关联图形场景的所有权?

关闭/清理 "mixed"文件描述符/套接字

c++ - 如何将模板函数作为模板函数的参数传递?

c++ - 复制 const char*

c++ - 通过加入现有 QHash 来初始化 const QHash