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

Time:10-13

Sorry if this is a duplicate. I am somewhat new to network programming, and I haven't found any posts on my own that have helped me understand this.

So, a little background on the issue:

I am maintaining/developing an existing code-base. We have a Raspberry Pi controlling a bunch of hardware, some of which is modular. The code, written in C (might be C ), communicates using IPv4 standards over a socket (using socket.h) with a gui on Windows. I'm pretty sure we don't have multithreading implemented in the raspberry code, or this would be much easier!

My problem has to do with how some of the modular hardware is interacting (or rather, is not) with the code. Without the extra hardware, the raspberry sits there waiting until the gui sends something over. That's how we want it behaving.

Problem is, when we have this extra hardware connected, the raspberry needs to also be able to run some code in response to one of its IO pins tied to a button on the hardware.

I tried adding (various) conditions to a loop in main(), which is where I thought the code was idling, to no avail. I always got either the hardware OR gui control working, but not both. I eventually figured out that read(), which is called near the end of that loop, is blocking.

So now what I'm trying to figure out is how to execute one chunk of code (for the hardware control) if read() is blocking, and another when it stops. Something like:

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

The loop in 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();
                }
            }
        }
    }

Here's the code where it's blocking:

   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();
   }

PS: I tried putting all my hardware checks in checkForSOT() (which was previously empty) already, but it didn't do any better than the loop in main.

And where the socket is being setup:

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();      
    }
}

Most of the posts I've found on sockets blocking mention poll() and select() (along with their p- and e- upgrades(?)), but don't go into clear-enough detail on how they work for me to figure out if they are what I'm needing. I'm also not sure what it would take to change the socket to non-blocking while maintaining the same behavior.

Note: I am still trying to read through and wrap my head around Beej's guide to network programming, so if there's a specific section of that that'll help me, please be specific.

Also, if anyone knows of (or could write) a good guide to setting up remote debugging the raspberry through Netbeans 12 (on Windows 10), that would be a HUGE help!

CodePudding user response:

Poll isn't very hard. Make a loop that runs at least every 5 msec.

while (running)

Initialize, then wait for something to happen

    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
}

Obviously there should be more checking and cleanup on error conditions.

  • Related