Strange behavior to TCPSocketServer class [new mbed Ethernet Interface official library]

23 Jul 2013

I found a strange behavior in TCPSocketServer class from mbed new EthernetInterface library.

This is the code:

#include "mbed.h"
#include "EthernetInterface.h"

int main() {
    EthernetInterface eth;
    eth.init(); //Use DHCP
    eth.connect();
    printf("IP Address is %s\n", eth.getIPAddress());
    
    TCPSocketServer m_Svr;
    m_Svr.bind (80);
    m_Svr.listen(1);
    m_Svr.set_blocking (false, 900);

    while (1) {
        TCPSocketConnection Clnt;
        if (m_Svr.accept(Clnt) < 0) {
            printf("no connection\n");
        } else {
            printf("Client (IP=%s) is connected !\n", Clnt.get_address());
        }
    }
}

If I run this code, at the beginning everything works fine, and "no connection" message appears every 900 milliseconds.

Then I open a browser in my PC (both mbed and PC are connected to the same network), I write "http: [mbed IP address]" in navigation bar and I press "Enter". Mbed message switch to "Client IP: xxxx is connected!", and then it returns to "no connection" again.

So far, everything works as expected.

But: after re-connecting a few times (with "F5" key, in browser), suddenly mbed stop responding to connections (it remains displaying "no connection" forever) or, sometimes, it begins to behave like in blocking mode (i.e., don't display "no connection" anymore, but still display "Client IP: is connected" whenever I press "F5"), wich is even more strange...

23 Jul 2013

Hallo pablo, i have the same behavior with my application. May be you have to set down your speed.

set_link(FullDuplex10)

but this does not work with EthernetInterface.h

set link is not a member .......

has anybody an idea?

24 Jul 2013

Yes, it behaves funky but....lets look at the options: Is there any specific reason to run the server socket in nonblocking with a timeout of 900ms? were you planning to do something else in the periodic 900ms time where the accept times out?

A solution could be to move the server to its own thread and keep the main loop for your other tasks unless you have a specific reason to keep the server in the main loop

#include "mbed.h"
#include "EthernetInterface.h"

void http_thread(void const* arg)
{  
  TCPSocketServer m_Svr;
  m_Svr.set_blocking (true);
  m_Svr.bind (80);    
  m_Svr.listen(1);
    
    //osThreadSetPriority( Thread::gettid() ,  osPriorityBelowNormal );
 
    while (1) {
        TCPSocketConnection Clnt;
        printf("Accept\n");
        int ret = m_Svr.accept(Clnt);
        if ( ret < 0) {
            printf("no connection\n");            
        } else {
            printf("Client (IP=%s) is connected\n", Clnt.get_address());
            char buff[512];            
            int result = Clnt.receive(buff, 511);
            if(result < 0 )
                printf("The horror\n ");
            else {
               if(result >= 511)
                 buff[511] = 0;
               else
                 buff[result + 1] = 0;
                 
               printf("%s\n",buff);
            }
            const char * msg = "Hello World\n\r\n\r";
            sprintf(buff,"HTTP/1.1 200 OK\n\rContent-Length: %d\n\rContent-Type: text/html\n\rConnection: Close\n\r\n\r", strlen(msg));
            Clnt.send(buff,strlen(buff));
            Clnt.send( const_cast<char*>(msg), strlen(msg));
        }        
    }
}
  
  
DigitalOut led(LED1);
EthernetInterface eth;

int main() {    
    Serial pc(USBTX, USBRX);
    pc.baud(921600);
    
    eth.init(); //Use DHCP
    eth.connect();    
    printf("IP Address is %s\n", eth.getIPAddress());    
    Thread httpsvr( &http_thread );
    
    while(true){
      osDelay(900);
      led = !led;
      //DO SOME STUFF
    }   
}

Salu2

24 Jul 2013

Hi H Soto, thanks for your answer.

It seems to work a lot better this way, though I don't know exactly why.

Keeping the server in its own thread, if I return setting to set_blocking (false, 900) [although there is no reason for it, just to test] then the behavior is again the same as before, it stops responding to the 3rd or 4th reload (press "F5" in client browser).

However, if I change to set_blocking (true), as you suggested, then it works way better, but it still can do hang, bombarding it with reloads (holding down the F5 key in browser).

Thank you very much.

25 Jul 2013

Hola Pablo, la verdad es la siguiente:

Although the change to blocking mode only masks the problem, it is probably a more elegant way to deal with it. Changing the blocking mode to non/900 will trigger the same condition as when the server ran in the main thread but blocking in http task will give you the freedom to do what you need in the main task. I tested the code yesterday and it didnt crash on me, but I noticed something interesting in the process: doing printf at low speeds(9600 baud wth?) introduces a lot of wait states, many of them intlocked so it is better to keep printf'ing in the time critical parts to a minimum, that's the reason I ran the serial port at almost 100 times higher baud rate.

You could test how stable it behaves when you remove all printf logging to the serial pc terminal, and if you really need to log, just post the log message pointers from the http context to the main context using a message queue/mailbox and lower the prio of the main so the outputing doesnt interfere with your critical task.

Salu2, H.

26 Jul 2013

Hi H soto.

Thanks to your advice I was able to run an HTTP server. I did my own simplified version of Henry Leinen server:

Import programHTTP_server

HTTP Server upon new mbed Ethernet Interface. Based on original code by Henry Leinen.

The funny thing is that it works perfectly (albeit rather slowly) if I leave the "#define debug" line (in HTTPServer.cpp), that insert lots of messages to serial terminal at 9600 baud. If I remove all those messages, the server does not work anymore (and on top, I can't know what is going on).

28 Jul 2013

Fixed!

It works now.

05 Aug 2013

Hi Hector.

I've found that, while this server works and is very stable, it is very slow compared to my previous HTTP Server implemented upon the old NetServices library.

Receiving and parsing the request is not an issue, but the problem arises when trying to send the reply. Every time I call tcpSocketConnection.send or send_all method, it return -1 except if I raise the timeout to 500, meaning that every time I call send, takes exactly half a second to be ready to send. Unfortunately, when reading a file from the localFileSystem (which is also quite slow), I break it into chunks of 128 bytes, and each time I send one of these chunks, I have a waiting time of at least 500 ms.

On the other hand, serving the same file with the old netServices library, without any RTOS, is way faster.

In what can I be wrong?