W5100 - Issue - Maximum number of sockets

After the receive problem was resolved, I tried to get four sockets working. I was only able to get three. Not the four expected.

Following is the code for an echo server which can handle multiple sessions:


using System;
using System.Threading;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Net;
using GHIElectronics.NETMF.Net.Sockets;
using GHIElectronics.NETMF.Net.NetworkInformation;
using System.Text;
//using Socket = GHIElectronics.NETMF.Net.Sockets.Socket;

namespace EchoServer
{
    public class EchoServer
    {
        private static int sessionCount = 0;
        private const int MAX_SESSIONS = 4;

        // putting the new session into a static variable
        // to be picked up by the new session thread is
        // NOT a good idea. It will create a race condition
        // should two sessions start at the same time
        // This was only done for testing...
        private static Socket newSessionSocket = null;

        public static void Main()
        {

            const Int32 c_port = 80;

            byte[] ip = { 192, 168, 1, 201 };
            byte[] subnet = { 255, 255, 255, 0 };
            byte[] gateway = { 192, 168, 1, 1 };
            byte[] mac = { 43, 185, 44, 2, 206, 127 };
            WIZnet_W5100.Enable(SPI.SPI_module.SPI1, (Cpu.Pin)FEZ_Pin.Digital.Di10, (Cpu.Pin)FEZ_Pin.Digital.Di9);
            NetworkInterface.EnableStaticIP(ip, subnet, gateway, mac);
            NetworkInterface.EnableStaticDns(new byte[] { 192, 168, 1, 1 });

            Socket server = new Socket(AddressFamily.InterNetwork,
            SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, c_port);
            server.Bind(localEndPoint);
            server.Listen(1);

            Debug.Print("*** Echo Server Listening");

            while (true)
            {
                // check for four running sessions
                if (sessionCount < MAX_SESSIONS)
                {

                    // Wait for a client to connect.
                    newSessionSocket = server.Accept();
                    Debug.Print("New Sesion");

                    Thread newSession = new Thread(new ThreadStart(SessionThread));
                    newSession.Start();
                    Thread.Sleep(0);
                    Interlocked.Increment(ref sessionCount);
                }
                else
                {
                    Thread.Sleep(250);
                }
            }
        }

        static private void SessionThread()
        {
            byte[] buffer = new byte[1024];
            Socket socket = newSessionSocket;
            socket.ReceiveTimeout = -1;

            while (true)
            {
                try
                {
                    if (socket.Poll(-1, SelectMode.SelectRead))
                    {
                        int bytesToRead = socket.Available;
                        //Debug.Print("bytesToRead: " + bytesToRead.ToString());
                        if (bytesToRead == 0)
                        {
                            throw new Exception("Remote Disconnect");
                        }
                        else
                        {
                            int bytesRead = socket.Receive(buffer, bytesToRead, SocketFlags.None);
                            socket.Send(buffer, bytesRead, SocketFlags.None);
                            socket.Poll(-1, SelectMode.SelectWrite);
                        }
                    }
                    else
                    {
                        Debug.Print("Poll False");
                    }
                }
                catch (Exception ex)
                {
                    socket.Close();
                    Interlocked.Decrement(ref sessionCount);
                    break;
                }
            }
        }
    }
}

Upon startup, one socket is consumed with the listening socket. I was then able to get two sessions working. When I started the third session, which would have been the fourth socket, I got the following output:

*** Echo Server Listening
New Sesion
New Sesion
#### Exception System.Exception - 0x00000000 (1) ####
#### Message: No free sockets
#### GHIElectronics.NETMF.Net.SocketNative::socket [IP: 0024] ####
#### GHIElectronics.NETMF.Net.SocketNative::accept [IP: 0007] ####
#### GHIElectronics.NETMF.Net.Sockets.Socket::Accept [IP: 0023] ####
#### EchoServer.EchoServer::Main [IP: 009b] ####
A first chance exception of type ‘System.Exception’ occurred in GHIElectronics.NETMF.W5100.dll
An unhandled exception of type ‘System.Exception’ occurred in GHIElectronics.NETMF.W5100.dll

Additional information: No free sockets

We reserve one socket for DNS and DHCP for future.

Josef:

I understand the design decision.

I could argue that it is the application developer’s responsibility to make sure that there is a socket available for DNS and DHCP lease renewal.

If a server, which only receives incoming requests, is set up with a static ip address, then there would be no need to DNS or DHCP, and the fourth socket would be lost.

I don’t really have a strong opinion on this issue.

We may add something in future to give you the 4th socket bit for now we want to reserve it. It is easier to add in future, not remove :slight_smile:

Why not just allow the user to enable/disable DNS/DHCP to use the extra socket?

That could work too

Yeah, I’d prefer to have that. I’ll know if I need DNS/DHCP and I can enable them if I need to and code around the socket limit. Otherwise, I want my 4 sockets! :smiley:

No need for special enable/disable:

The only time a restriction needs to be made on the fourth socket is when DHCP is used. This is needed to insure the socket is available for lease renewal. No regular DHCP enable , no reservation on fourth socket and it is available.

Nothing needs to be done for DNS. When a DNS request is made, check for the availibility of a socket. No socket then an exception.

*** Let’s not forget that Joe has done a great job of implementing W5100 support. Let’s get it out to users and see what additional requirements come back.

Thank you guys for your suggestions and comments.
Let’s get the current firmware rolling with this feature for now then we will look for more optimization to make the driver better. :wink: