【问题标题】:How to terminate a listening TCP Server with keyboard input in C++如何在 C++ 中使用键盘输入终止侦听 TCP 服务器
【发布时间】:2018-09-02 21:24:09
【问题描述】:

我正在尝试找到一种在服务器侦听传入客户端连接时安全关闭服务器的方法,而无需在 linux 中使用经典的 ctrl+C 。我想终止程序,例如通过键盘输入 Q-quit 等... 在按下 enter 后立即这样做,而不是在接受之后,例如客户端连接。我应该如何实现这个? 这是我的示例代码。

    int startSocketConnection() {
        socketFD = socket(AF_INET, SOCK_STREAM, 0);

        //TODO exceptions
        if (socketFD < 0) {
            std::cout << "\nError establishing socket...\nexiting..." << std::endl;
            return (-1);
        }
        std::cout << "\nSocket server has been created..." << std::endl;
        server_addr.sin_family      = AF_INET;
        server_addr.sin_addr.s_addr = htons(INADDR_ANY);
        server_addr.sin_port        = htons(portNum);

        //TODO exceptions
        if ( (bind(socketFD, (struct sockaddr*) &server_addr, sizeof(server_addr))) < 0 ) {
            std::cout << "Error binding connection, Socket has already been established" << std::endl;
            return (-1);
        }

        std::cout << "Listening for incoming client connection..." << std::endl;
        listen(socketFD, 1);

        size = sizeof(client_addr);
        while (sessionActive) {
            newSocketFD = accept(socketFD, (struct sockaddr *) &client_addr, &size);
            if (newSocketFD < 0) error("ERROR on accept");
            //fork() returns child pid to parent, 0 to the child process.
            pid = fork();
            if (pid < 0) error("ERROR on fork");
            //if child process...
            if (pid == 0)  {
                close(socketFD);

                //process client query...
                sessionActive = dostuff(newSocketFD);

                signal(SIGCHLD, SIG_IGN);
                std::cout << "Child process terminated!" << std::endl;
                exit(0);
            }
            else {
                close(newSocketFD);
            }
        }
        close(socketFD);
        return 0;
    }

【问题讨论】:

  • 如果你读过几本书或教程,我想你应该见过 non-blocking 套接字和 select 调用的使用吗?两者都是帮助您解决问题的有用工具。还要记住,在 POSIX(如 Linux)环境中,套接字和文件都是相同的,都是 描述符。还要记住,标准输入是一个可以像任何其他文件一样读取的文件(例如从STDIN_FILENO 描述符)。
  • @Someprogrammerdude 不幸的是,我对编写网络服务器一无所知。甚至我写的那一篇也几乎是复制粘贴的。不过感谢您提供的信息。

标签: c++ linux server serversocket


【解决方案1】:

您需要添加另一个从标准输入读取并在看到这些命令时毫不客气地退出您的应用程序的线程,或者更改您的代码以使用类似selectpoll 的命令来查看哪些描述符具有可用输入:添加stdin 的描述符(出于您的目的,您可以相信它为 0)与侦听套接字的描述符一起,当其中一个或两者都有输入事件时,您的 selectpoll 将返回并且 - 如果它告诉你的标准输入有数据——你可以不阻塞地读取它:如果你看到你的终止命令,退出。

对于select/poll,您应该将调用accept 的套接字设置为非阻塞,因为可能会在您转到@987654331 时收到传入连接尝试的通知@ 该连接可能已经失败 - 您不希望 accept 也为您阻止和停止您的 selectpoll 呼叫监控 stdin

在这两个中,额外的线程是最简单的——这是一个最小的程序,说明如何启动它并让它在你的主线程做自己的事情时监控标准输入。在 Linux 上,使用 -lpthread 链接。

#include <thread>
#include <iostream>
#include <string>
#include <unistd.h> // for sleep

int main()
{
    std::thread t{
        [] {
            std::string s;
            while (std::cin >> s)
                if (s == "exit")
                {
                    std::cout << "exit command given on stdin\n";
                    exit(0);
                }
        }
    };
    t.detach();

    while (true)
    {
        sleep(2);
        std::cout << "beat\n";
    }
}

(如果你想“有序”关闭它确实会变得更复杂一些,主线程中的对象的析构函数保证运行......)

【讨论】:

  • 感谢您的回复。这确实比我预期的要复杂。只需添加一个简单的额外功能!
  • 线程方法非常简单 - 请参阅我在答案中附加的示例代码。
猜你喜欢
  • 1970-01-01
  • 2021-11-15
  • 1970-01-01
  • 2018-05-11
  • 1970-01-01
  • 2016-12-30
  • 1970-01-01
  • 2019-09-10
  • 2019-10-20
相关资源
最近更新 更多