10 years, 7 months ago.

Why is Socket.receive blocking when I set non-blocking mode?

Why is my call to Socket.receive blocking? I am using EthernetInterface rev 33 and mbed_rtos rev 14 both from mbed_official.

In this sample, the first LED on the mbed 1768 indicates LINK. When the socket is not connected, the LINK led changes state when the Ethernet cable is removed/inserted. But when the socket is connected, the LINK led is not changing state when the Ethernet cable is removed/inserted, meaning that my while loop is stuck somewhere. Traced this using debugging statements (not shown) that the receive is blocking.

Also weird is that the code has different behavior if in main() rather than in a Thread. It only allows connections to be re-established if running in a Thread, but doesn't allow re-connections if the code is moved into main and the thread is removed.

Am I doing something wrong here, or did I find bug(s)?

#include "mbed.h"
#include "EthernetInterface.h"
#include "Socket.h"
#include "TCPSocketServer.h"
#include "TCPSocketConnection.h"

DigitalOut myled(LED1);
Serial tty_pc(USBTX, USBRX);

void eth_main(const void *context)
{
    puts("Starting " __FILE__ " " __DATE__ " " __TIME__);
        
    Ethernet eth;
    eth.set_link(eth.AutoNegotiate);

    EthernetInterface ethif;
    ethif.init();
    ethif.connect();

    printf("IP %s\n", ethif.getIPAddress());

    TCPSocketServer server;
    TCPSocketConnection sock;
    bool active = false;
    unsigned short port = 8000;

    server.bind(port);
    server.listen();

    server.set_blocking(false, 500); // SET NON-BLOCKING

    printf("listening at %s:%hu\n", ethif.getIPAddress(), port);

    while(true)
    {
        myled = eth.link();

        if (active)
        {
            char c;
            if (sock.receive(&c, 1) <= 0) // NON-BLOCKING (!?) RECEIVE TO CHECK IF SOCKET ACTIVE
                Thread::wait(500);
                
            if (!sock.is_connected())
            {
                puts("connection closed");
                sock.close(true);
                active = false;
                server.bind(port);
                server.listen();
                printf("listening at %s:%hd\n", ethif.getIPAddress(), port);
            }
        }
        else
        {
            if (server.accept(sock) == 0)
            {
                active = true;
                server.close();
                puts("connection established");
            }
        }
    }
}

int main()
{
    Thread eth_thread(eth_main, 0);
    
    while (1)
    {
        // forever
    }
}

2 Answers

10 years, 7 months ago.

I have since realized there are two sockets, and the socket being received on is not set to non-blocking. Doesn't answer why the behavior is different in main() though.

Accepted Answer
10 years, 7 months ago.

char c; if (sock.receive(&c, 1) <= 0) NON-BLOCKING (!?) RECEIVE TO CHECK IF SOCKET ACTIVE Thread::wait(500);

Not clear why you have this code at all. If you become ACTIVE (there is a connection), and there is either no data or the connection is dropped, this will loop forever.

Your Is_connected() check is all you need.

I tried removing this code, and the LED now blinks as you might expect.

No idea about your thread related question.

Thanks for the response.

The receive is always necessary to detect remote socket closure. If you're not receiving, you don't notice the remote has gone away. Try it!

As mentioned in my previous follow up I fixed the non-blocking problem by setting the second socket to non-blocking. I added the statement right after the accept.

posted by Dave Van Wagner 26 Sep 2013