I have had a lot of problems with using TCPSocket
. It doesn’t seem to be too user friendly when it comes to handling errors and special cases. One interesting comment about it that I could is:
https://os.mbed.com/forum/bugs-suggestions/topic/36246/
The issues there were mostly disregarded.
Anyway, I used the TCPSocket
over a year ago to receive data, but if the socket received too much data it somehow froze and never worked again. Could not get it to behave, so we moved all comms to UDP and built own “reliability” on top of that, Now I need TCP for MQTT but TCPSocket
again tries hard to make it impossible.
In happy cases I can connect to the MQTT broker and send data more or less forever, no issues. But in cases where the broker is offline or the network has some issues, I run into crashes. What I do is basically:
-
open the socket:
mqttSocket.open(EthInterface::get_default_instance())
-
connect to the broker:
mqttSocket.connect( SocketAddress(brokerIp, brokerPort)
-
set it as async:
mqttSocket.set_timeout( 0 );
mqttSocket.set_blocking( false );
mqttSocket.sigio(callback(incomingDataCallback));
- send and receive data.
However, it connect()
fails or there’s an error later on I close the socket: mqttSocket.close()
and then try to reopen it again using open()
. Here it always crashes. Regardless if I use a single socket instance as above or if I always allocate a new one on the heap. Instant freeze and then a watchdog reboot. The socket has no active readers or writers at this point. Looking at the docs for TCPSocket
it seems that close()
does some deallocations of data? Reading this piece of docs:
/** Accepts a connection on a socket.
*
* The server socket must be bound and set to listen for connections.
* On a new connection, returns connected network socket which user is expected to call close()
* and that deallocates the resources. Referencing a returned pointer after a close()
* call is not allowed and leads to undefined behavior.
*
* By default, accept blocks until incoming connection occurs. If socket is set to
* non-blocking or times out, error is set to NSAPI_ERROR_WOULD_BLOCK.
*
* @param error pointer to storage of the error value or NULL
* @return pointer to a socket
*/
virtual TCPSocket *accept(nsapi_error_t *error = NULL);
It seems that close()
is only for accepted incoming sockets? Or is it? Nothing in the docs for TCPSocket
mentions closing a socket or reusing it. Neither do the docs for InternetSocket
say anything useful. All the examples that use sockets are happy cases that only connect once to a server and never have any errors, so they are not too much help.
So what would be the correct way to reconnect to a server in a correct way? Or is there some recommended other API that would be better, perhaps raw LWIP or something else that is stable?