Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
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); }