Close Sockets

08 Aug 2011

Hello! I´m programming a client-server, using the TCPSocket and EthernetNetIf I have a problem to change from client to server, if I do it more than once. I close the sockets before doing the second bind. I receive the error TCPSOCKET_INUSE, but I close the sockets before. Is there some kind of function to release the socket or something? Because I think that the close is not enough. Thanks a lot!

María.

09 Aug 2011

This is what I think your scenario is:

  • You create a socket for your server (I will call this the LISTEN socket.)
  • Bind it to a specific port
  • Listen on this port
  • Accept a connection which creates a new socket (I will call this the ACCEPT socket.)
  • Transfer some data between this server and the client
  • Issue a close on the ACCEPT socket from the server. If the client was the first to issue the close then this problem would not occur.
  • Sounds like you are closing the LISTEN socket as well.
  • Try to do everything again.

If this is the case then you are probably hitting an issue where the ACCEPT socket isn't completely freed. It is in a state called TIME_WAIT. It is placed in this state for a few minutes after the close since there is a chance that it might need to resend a packet. If you know the internals of TCP/IP then the particular packet it might need to resend is an ACK for the client's last FIN packet. If you don't know about the internals of TCP/IP then you don't need to worry about ACK and FIN packets...just know that it leaves the socket around in limbo for awhile.

There are a couple of solutions to this problem. From best to worst based on nothing more than my own personal opinion:

  • Don't close the LISTEN socket! Just close the ACCEPT socket and keep the LISTEN socket around for later use.
  • Use the SOF_REUSEADDR option on your LISTEN sockets. This will allow bind to proceed even when you hit the above scenario. However, to use this feature, you need to turn on a compile time define that isn't currently enabled in NetServices so this isn't very convenient.
  • As a work around, I think you might want to try opening 3 new sockets and once they are all created, close all 3 of them (just create them and close them...don't bind them or anything else.) The internals of the lwIP network stack will actually reuse sockets that are in the TIME_WAIT state if it runs out of free sockets. The NetServices that I have in my project (which is likely to be the same as you have) is configured to only have 3 sockets in its TCP pool so opening 3 sockets should guarantee that the socket giving you the INUSE error will truly get discarded and then you can rebind.