如何使用套接字的阻塞状态作为条件?

How do I use blocking-status of socket as a condition?

我是 maintaining/developing 现有的代码库。我们有一个 Raspberry Pi 控制一堆硬件,其中一些是模块化的。该代码用 C(可能是 C++)编写,使用 IPv4 标准通过套接字(使用 socket.h)与 Windows 上的图形用户界面进行通信。我很确定我们没有在覆盆子代码中实现多线程,否则这会容易得多。

某些模块化硬件未与代码交互。没有额外的硬件,树莓派就坐在那里等待 GUI 发送一些东西。这就是我们希望它的行为方式。

问题是,当我们连接了这个额外的硬件时,树莓派还需要 运行 一些代码来响应它的一个 IO 引脚绑定到硬件上的一个按钮。
我尝试在 main() 中的循环中添加(各种)条件,这是我 认为 代码空闲的地方。我总是让硬件或 GUI 控制正常工作,但不能同时工作。

我最终发现在该循环快要结束时调用的 read() 正在阻塞。
现在我想弄清楚如何在 read() 阻塞时执行一段代码(用于硬件控制),而在它停止时执行另一段代码。

类似于:

(Pseudocode)
    read socket
    while(blocking)
    {
        check for hardware signal, if found, runTest();
    }
    {use result of read()}

main 中的循环:

while(true)
    {            
        initPort();

        while(listening)
        {
            openPort();

            if (netOpen)
            {
//puts("// Tester is connected /////////////////////////////////");
                loadCalFactors();
                loadCalResistors(); 
                loadExtConf(true);
                inOn(false);
                outOn(false);

                // Loop until client terminates connection.
                initPins();
                while(netOpen)
                {   
                    /*
                     * Moving the block to work().
                     */

//                    oldI = i;
//                    i = digitalRead(iTSW);
//                    
//                    if((i ^ oldI) == 0 && oldI == 1) // TSW has been held on
//                        testing = true;
//                    
//                    else if((i ^ oldI) == 1 && oldI == 0)
//                        testing = false;
//                    
//                    if(testLoaded && usingTermCtrl && i && !testing)
//                    {
//                        RunTp(false);                                
//                    }                  
//                    else  
                        work();
                }
            }
        }
    }

这是阻塞的代码:

   void work()
   {
        char bs[1];
        int n;
//socket Sockfd is blocking here, so we only briefly return to the 
//loop in main right after an action
        n = read(Sockfd, bs, 1); 
        if(n > 0)
            doAct(bs[0]);
        else
            checkForSOT();
   }

我已经尝试将所有硬件检查放入 checkForSOT()(之前是空的)中,但它并没有比 main 中的循环做得更好。

设置套接字的位置:

void initPort()
{
    struct sockaddr_in serv_addr;

printf("Initializing Port %d\n", HOST_PORT);
    listening = false;
    
    sockListen = socket(AF_INET, SOCK_STREAM, 0);
printf("sockListen=%d\n",sockListen);
    if(sockListen < 0)
    {
        puts("Error opening socket");
delay(1000);
    }
    else
    {
        bzero((char *)&serv_addr, sizeof(serv_addr));

        serv_addr.sin_family = AF_INET;
        serv_addr.sin_addr.s_addr = INADDR_ANY;
        serv_addr.sin_port = htons(HOST_PORT);

        if(bind(sockListen, (struct sockaddr *) &serv_addr,
                sizeof(serv_addr)) < 0)
        {
            puts("Error on binding");
delay(1000);
        }
        else
        {
            listen(sockListen, 1);
            listening = true;
        }
    }
}

void openPort()
{
    int clilen;
    int newsockfd;
    
    printf("\nTester waiting for connection on socket %d\n", sockListen);

    clilen = sizeof(cli_addr);

    // infinite wait on a connection 
    if((newsockfd = accept(sockListen, 
            (struct sockaddr *) &cli_addr, (socklen_t*) &clilen) ) < 0 )
        puts("Error on accept");

    else
    {
        if (DEBUG) debugMode = true;

        netOpen = true;
        Sockfd = newsockfd;
        sendVersion();
        netWrite("Connected\n");
        sendExtConfMessage();
        sendExtConf();      
    }
}

我在套接字阻塞上发现的大多数帖子都提到了 poll() 和 select()(连同它们的 p- 和 e- 升级(?)),但没有足够清楚详细说明它们如何为我工作,以确定它们是否是我需要的。 我也不确定在保持相同行为的同时将套接字更改为非阻塞需要什么。

注意:我仍在尝试通读 Beej 的网络编程指南并全神贯注,因此如果其中有特定部分对我有帮助,请具体说明。

此外,如果有人知道(或可以写出)通过 NetBeans 12(在 Windows 10 上)设置远程调试树莓派的好指南,那将是一个巨大的帮助!

投票不是很难。制作一个至少每 5 毫秒运行一次的循环。

while (running)

初始化,然后等待事情发生

    struct pollfd fds = {fd, POLLIN, 0};
    int rc = poll(&fds, 1, 5);  // wait for fds or 5 msec
    if (rc < 0) {
        perror("poll");
        exit(1);
    } else if (rc > 0) {
        if (fds.revents & POLLIN)
            recv(fd);  // fds is ready
    }
    // check button here
}

显然应该对错误条件进行更多检查和清理。