8 years, 1 month ago.

EthernetInterface - Reconnecting a failed socket

My problem is on a FRDM k64f. The example I have here is basically an attempt to learn EthernetInterface and ring buffers. This is an echo client that connects to a server and returns any data the server sends it. That all seems to work great. But, if the connection is lost I can't get it to attempt a new connection. I'm using socket.is_connected() to test whether a valid connection exists. Here is the main code and the ring buffer header and cpp file.

FRDM_Ethernet

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

// ############################################################################
// ############################################################################
// ##  Basically a tcp echo client using a ring buffer
// ############################################################################
// ############################################################################
 
const char* ECHO_SERVER_ADDRESS = "192.168.100.101";
const int ECHO_SERVER_PORT = 23;
/*
struct _rb{
    char* buffer;
    int head;
    int tail; 
    int maxLen;
}rbFromCodec, rbToUser, rbFromUser, rbToCodec;
*/
_rb rbFromCodec;
_rb rbToUser, rbFromUser, rbToCodec;

char strToCodec[1024], strToUser[1024], strToPC[1024], strFromCodec[8192], strFromUser[1024], strFromPC[1024];

// Ringbuffer article:
//   http://embedjournal.com/implementing-circular-buffer-embedded-c/

int main() {
    EthernetInterface eth;
    eth.init(); //Use DHCP
    eth.connect();
    printf("\nClient IP Address is %s\n", eth.getIPAddress());
    
    rbFromCodec.buffer = strFromCodec;
    rbFromCodec.head = 0;
    rbFromCodec.tail = 0;
    rbFromCodec.maxLen = 8192;
    
    // Create our socket
    TCPSocketConnection socket;
    
    while(true){
        while(socket.is_connected()){
            //rxHandler();
            char d[8192];
            char w[128];
            int ss; // returns socket.send
            d[0] = 0;
            int sr = socket.receive(d, 8192);
            if(sr > 0){ // if anything received   
                for(int i = 0; i<sr; i++){ // go through all of the received chars
                    int q = circBufPush(rbFromCodec, d[i]); // and push them into our ring buffer
                }
            }
            //txHandler()
            static char txbuf;
            static char tb[1024];
            int n; // circBufPop returns -1 on error
            if(txbuf > 0){ // if we've already popped a char to send
                ss = socket.send_all(w, strlen(w));
                if(socket.send(&txbuf, 1) > 0){ // then this char was sent successfully
                    txbuf = 0;
                    ss = socket.send_all(w, strlen(w));
                    n = circBufPop(rbFromCodec, &txbuf);
                    if(n>0){
                        ss = socket.send_all(w, strlen(w));
                    }
                }
            }else{ // txbuf is empty
                int ndx = 0;
                n = 0;
                while((ndx < 1024) && (n == 0)){
                    n = circBufPop(rbFromCodec, &tb[ndx]);
                    if(n == 0){ ndx++; }
                }
                if(ndx > 0){ socket.send_all(tb, ndx); }
                ndx = 0;
            }
        }
        // connection hasn't started or has failed...
        //socket.close();
        //socket.set_blocking(false, 1500);
        while (socket.connect(ECHO_SERVER_ADDRESS, ECHO_SERVER_PORT) < 0) {
            printf("Unable to connect to (%s) on port (%d)\n", ECHO_SERVER_ADDRESS, ECHO_SERVER_PORT);
            wait(1);
        }
        printf("Connected to Server at %s\n",ECHO_SERVER_ADDRESS);
    }
    // Clean up - Yes, I know,  The code never reaches this point!
    socket.close();
    eth.disconnect();
    
}

Ring Buffer header file:

rlmRingBuffers.h

// This is start of the header guard.  ADD_H can be any unique name.  By convention, we use the name of the header file.
#ifndef rlmRingBuffers
#define rlmRingBuffers
 
// This is the content of the .h file, which is where the declarations go
int add(int x, int y); // function prototype for add.h -- don't forget the semicolon!

struct _rb{
    char* buffer;
    int head;
    int tail; 
    int maxLen;
};
 
// Ringbuffer article:
//   http://embedjournal.com/implementing-circular-buffer-embedded-c/

int circBufPush(_rb &c, char data);
/*
{
    int next = c.head + 1;
    if (next >= c.maxLen)
        next = 0;
 
    // Circular buffer is full
    if (next == c.tail)
        return -1;  // quit with an error
 
    c.buffer[c.head] = data;
    c.head = next;
    return 0;
}
*/
int circBufPop(_rb &c, char *data);
/*
{
    // if the head isn't ahead of the tail, we don't have any characters
    if (c.head == c.tail)
        return -1;  // quit with an error
 
    *data = c.buffer[c.tail];
    c.buffer[c.tail] = 0;  // clear the data (optional)
 
    int next = c.tail + 1;
    if(next >= c.maxLen)
        next = 0;
 
    c.tail = next;
 
    return 0;
}
*/
 
// This is the end of the header guard
#endif

Ring Buffer cpp file:

rlmRingBuffers.cpp

// Ringbuffer article:
//   http://embedjournal.com/implementing-circular-buffer-embedded-c/

struct _rb{
    char* buffer;
    int head;
    int tail; 
    int maxLen;
};
 
int circBufPush(_rb &c, char data)
{
    int next = c.head + 1;
    if (next >= c.maxLen)
        next = 0;
 
    // Circular buffer is full
    if (next == c.tail)
        return -1;  // quit with an error
 
    c.buffer[c.head] = data;
    c.head = next;
    return 0;
}
int circBufPop(_rb &c, char *data)
{
    // if the head isn't ahead of the tail, we don't have any characters
    if (c.head == c.tail)
        return -1;  // quit with an error
 
    *data = c.buffer[c.tail];
    c.buffer[c.tail] = 0;  // clear the data (optional)
 
    int next = c.tail + 1;
    if(next >= c.maxLen)
        next = 0;
 
    c.tail = next;
 
    return 0;
}

Question relating to:

1 Answer

8 years, 1 month ago.

It looks like there is still state that needs to be cleaned up with the close method if the connection fails. Unfortunately the TCPSocketConnection doesn't have a method to test for that. The "correct" fix would probably be to restructure the code so that close is called when the socket changes from connected to disconnected. Alternatively you can just close the socket anytime the connect fails.

while (socket.connect(ECHO_SERVER_ADDRESS, ECHO_SERVER_PORT) < 0) {
    printf("Unable to connect to (%s) on port (%d)\n", ECHO_SERVER_ADDRESS, ECHO_SERVER_PORT);
    socket.close();
    wait(1);
}

Thanks Chris, I'll give that a try.

posted by Rick McNeely 21 Mar 2016