简体   繁体   中英

C++ How to exit out of a while loop recvfrom()

I'm trying to create a UDP broadcast program to check for local game servers, but I'm having some trouble with the receiving end. Since the amount of servers alive is unknown at all times, you must have a loop that only exits when you stop it. So in this bit of code here:

while(1) // start a while loop
       {
     if(recvfrom(sd,buff,BUFFSZ,0,(struct sockaddr *)&peer,&psz) < 0) // recvfrom() function call
        {
            cout << red << "Fatal: Failed to receive data" << white << endl;
            return;
        }
     else
     {
            cout << green << "Found Server :: " << white;
            cout << yellow << inet_ntoa(peer.sin_addr), htons(peer.sin_port);
            cout << endl;
   }
       }

I wish to run this recvfrom() function until I press Ctrl + C. I've tried setting up handlers and such (from related questions), but they're all either too complicated for me, or it's a simple function that just exits the program as a demonstration. Here's my problem: The program hangs on recvfrom until it receives a connection (my guess), so, there's never a chance for it to specifically wait for input. How can I set up an event that will work into this nicely?

Thanks!

In the CTRL-C handler, set a flag, and use that flag as condition in the while loop.

Oh, and if you're not on a POSIX systems where system-calls can be interrupted by signals, you might want to make the socket non-blocking and use eg select (with a small timeout) to poll for data.


Windows have a couple of problems with a scheme like this. The major problem is that functions calls can not be interrupted by the CTRL-C handler. Instead you have to poll if there is anything to receive in the loop, while also checking the "exit loop" flag.

It could be done something like this:

bool ExitRecvLoop = false;

BOOL CtrlHandler(DWORD type)
{
    if (type == CTRL_C_EVENT)
    {
        ExitRecvLoop = true;
        return TRUE;
    }

    return FALSE;  // Call next handler
}

// ...

SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE);

while (!ExitRecvLoop)
{
    fd_set rs;
    FD_ZERO(&rs);
    FD_SET(sd, &rs);

    timeval timeout = { 0, 1000 };  // One millisecond

    if (select(sd + 1, &rs, NULL, NULL, &timeout) < 0)
    {
        // Handle error
    }
    else
    {
        if (FD_ISSET(sd, &rs))
        {
            // Data to receive, call `recvfrom`
        }
    }
}

You might have to make the socket non-blocking for this to work (see the ioctlsocket function for how to).

Thread off your recvFrom() loop so that your main thread can wait for user input. When user requests stop, close the fd from the main thread and the recvFrom() will return immediately with an error, so allowing your recvFrom() thread to exit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM