G120 and Sockets, reliability problem - Need help!

@ zigbox: but with the wired connection using ENC28J60 still hangs at socket.accept() right?

@ PhilM: do you face this problem only with sockets ?

Iā€™m using HTTPListener and I imagine that behind is calling sockets, but I donā€™t see this problem. Iā€™ve a windows service that polls via ethernet calling HTTPWebRequest to Cobra II every 10secs and doesnā€™t lock in any way for days. Iā€™m using fixed IP addr and ENC28 Gadgeteer board. The msg exchanged between server and cobra may vary in length from few bytes to 5-6k using GET and POST.

I never tried HTTPListener, I should give it a try.
But otherwise yes I use sockets, and I face this problem with server sockets and clients socket.

@ GHI, did you have time to run my example code, and can you confirm that you have the same results? That is it hangs at Socket.Accept() eventually and no more client connection is possible ?
I think there might be a workaround possible, but that would need to fix another problem in the ENC28J60 interface.
If I detect that there is no more client connection after X seconds, then I can dispose and recreate the ENC28J60 interface.
That did work for a while, but eventually the flash is corrupt.
I think it is because the ENC28J60 uses EWR or something, bu it is difficult to know since I donā€™t have access to the code.

Can you guys at least could see if that workaround could be made to work ? Resolve the exception being thrown in another thread on the interface disposal, and not rewrite on the flash everytime (I think the MAC address and other things are written using EWR)?

This is starting to be a major issue for us, we have a product being shipped to a customer this week, but luckily he wonā€™t use it until late august.

@ PhilM -

Our engineer is starting with that, and he will have something soon.

@ PhilM - Can you try increasing your Socket.Listen from 1 to, say 5, and see if that helps at all?

@ James - I just tried 5 and 50 ā€¦ still same problem. :frowning:

Then we will continue investigating this issue. Thank you for your cooperation and patience.

I just tried HttpListener, and so far it never hanged.
I will test some more, and if it is really stable, I will use HttpListener as a temp fix.
Will post later on my resuts.

using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Touch;

using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Microsoft.SPOT.Hardware;
using GHI.Premium.Net;
using System.Net;
using System.Text;

namespace TestHttpListenerNetwork {
    public partial class Program {

        static OutputPort output;

        static Timer stateTimer;

        static EthernetENC28J60 Eth1;

        private Thread serverThread;

        // if you were to use ENC28J60-based Ethernet connection16.        
        //static EthernetENC28J60 Eth1 = new EthernetENC28J60(add code here to configure it);
        // wifi is same thing18.        
        // static WiFiRS9110 wifi = new WiFiRS9110(......);

        static byte[] outBuffer;
        static public ManualResetEvent NetworkAvailablityBlocking = null;
        static public ManualResetEvent IPAddressSetResetEvent = null;
        static string myIP = "192.168.1.180";

        // This method is run when the mainboard is powered up or reset.   
        void ProgramStarted() {
            /*******************************************************************************************
            Modules added in the Program.gadgeteer designer view are used by typing 
            their name followed by a period, e.g.  button.  or  camera.
            
            Many modules generate useful events. Type +=<tab><tab> to add a handler to an event, e.g.:
                button.ButtonPressed +=<tab><tab>
            
            If you want to do something periodically, use a GT.Timer and handle its Tick event, e.g.:
                GT.Timer timer = new GT.Timer(1000); // every second (1000ms)
                timer.Tick +=<tab><tab>
                timer.Start();
            *******************************************************************************************/


            // Use Debug.Print to show messages in Visual Studio's "Output" window during debugging.
            Debug.Print("Program Started");

            //output = new OutputPort(GHI.Hardware.G120.Pin.P1_5, false);

            //---- timer tick
            TimerCallback timerDelegate = new TimerCallback(TimerTick);
            AutoResetEvent autoEvent = new AutoResetEvent(false);
            stateTimer = new Timer(timerDelegate, autoEvent, 400, 171);


            //----  timer tick1 for a nice effect frequency  blinking blue led
            TimerCallback timerDelegate1 = new TimerCallback(TimerTick1);
            AutoResetEvent autoEvent1 = new AutoResetEvent(false);
            stateTimer = new Timer(timerDelegate1, autoEvent1, 500, 175);

            //--- Some sample grabed on the net, hope the GPIO pin are ok 
            //Eth1 = new EthernetENC28J60(SPI.SPI_module.SPI2, GHI.Hardware.G120.Pin.P1_9, GHI.Hardware.G120.Pin.P2_4, GHI.Hardware.G120.Pin.GPIO_NONE);
            Eth1 = new EthernetENC28J60(SPI.SPI_module.SPI2, GHI.Hardware.G120.Pin.P1_17, GHI.Hardware.G120.Pin.P2_21, GHI.Hardware.G120.Pin.P1_14, 4000);
            StartServer();

        }


        static public void TimerTick(Object stateInfo) {

            // TODO: Do Timer Tick stuff here...

            //output.Write(!output.Read());


        }


        static public void TimerTick1(Object stateInfo) {

            // TODO: Do Timer Tick stuff here...

            //output.Write(!output.Read());
        }


        void StartServer() {

            serverThread = new Thread(ServerThread);
            serverThread.Priority = ThreadPriority.Normal;
            serverThread.Start();

        }

        public static void ServerThread() {
            Eth1.Open();   // its hanging here ...

            NetworkInterfaceExtension.AssignNetworkingStackTo(Eth1);
            Eth1.NetworkInterface.EnableStaticIP(myIP, "255.255.255.0", "192.168.1.1");

            //Eth1.NetworkInterface.EnableDhcp();
            IPAddressSetResetEvent = new ManualResetEvent(false);
            Eth1.CableConnectivityChanged += new EthernetENC28J60.CableConnectivityChangedEventHandler(Eth1_CableConnectivityChanged);
            Eth1.NetworkAddressChanged += new NetworkInterfaceExtension.NetworkAddressChangedEventHandler(Eth1_NetworkAddressChanged);
            if (!Eth1.IsCableConnected) {
                NetworkAvailablityBlocking = new ManualResetEvent(false);
                do {
                    if (!Eth1.IsCableConnected) {
                        Debug.Print("Ethernet cable is not connected yet.");
                    } else
                        break;
                } while (!NetworkAvailablityBlocking.WaitOne(5000, false));
            }
            while (!IPAddressSetResetEvent.WaitOne(500, false)) {
                Debug.Print("IP address is not set yet.");
            }
            Debug.Print("IP address is set");
            //string str = Resources.GetString(Resources.StringResources.String1);


            string msgStr = "Hello, browser! I think the time is " + DateTime.Now.ToString();
            string str = "";
            for (int i = 0; i < 75; i++) {
                str = str + "\r" + msgStr;
            }
            outBuffer = Encoding.UTF8.GetBytes(str);
            try {
                Debug.Print("Running HttpServer");
                Debug.Print("Type this IP address to access the webpage: " + Eth1.NetworkInterface.IPAddress);
                RunServer();
            } catch (Exception e) {
                Debug.Print(e.Message);
            }
        }
        static void Eth1_CableConnectivityChanged(object sender, EthernetENC28J60.CableConnectivityEventArgs e) {
            Debug.Print("Built-in Ethernet Cable is " + (e.IsConnected ? "Connected!" : "Disconneced!"));
            if (e.IsConnected)
                NetworkAvailablityBlocking.Set();
        }
        static void Eth1_NetworkAddressChanged(object sender, EventArgs e) {
            Debug.Print("New address for The built-in Ethernet Network Interface ");

            Debug.Print("Is DhCp enabled: " + Eth1.NetworkInterface.IsDhcpEnabled);
            Debug.Print("Is DynamicDnsEnabled enabled: " + Eth1.NetworkInterface.IsDynamicDnsEnabled);
            Debug.Print("NetworkInterfaceType " + Eth1.NetworkInterface.NetworkInterfaceType);
            Debug.Print("Network settings:");
            Debug.Print("IP Address: " + Eth1.NetworkInterface.IPAddress);
            Debug.Print("Subnet Mask: " + Eth1.NetworkInterface.SubnetMask);
            Debug.Print("Default Getway: " + Eth1.NetworkInterface.GatewayAddress);
            Debug.Print("Number of DNS servers:" + Eth1.NetworkInterface.DnsAddresses.Length);
            for (int i = 0; i < Eth1.NetworkInterface.DnsAddresses.Length; i++)
                Debug.Print("DNS Server " + i.ToString() + ":" + Eth1.NetworkInterface.DnsAddresses[i]);
            Debug.Print("------------------------------------------------------");
            if (Eth1.NetworkInterface.IPAddress == myIP || Eth1.NetworkInterface.IPAddress != "0.0.0.0")
                IPAddressSetResetEvent.Set();
        }
        internal static void RunServer() {
            HttpListener listener = new HttpListener("http");
            listener.Start();

            while (true) {
                HttpListenerResponse response = null;
                HttpListenerContext context = null;

                try {
                    context = listener.GetContext();

                    response = context.Response;
                    HttpListenerRequest request = context.Request;
                    switch (request.HttpMethod.ToUpper()) {
                        case "GET": ProcessClientGetRequest(context);
                            break;
                    }
                    if (response != null) {
                        response.Close();
                    }
                } catch {
                    if (context != null) {
                        context.Close();
                    }
                }
            }
        }
        private static void ProcessClientGetRequest(HttpListenerContext context) {
            HttpListenerRequest request = context.Request;
            HttpListenerResponse response = context.Response;
            Debug.Print(request.RawUrl);
            response.OutputStream.Write(outBuffer, 0, outBuffer.Length);
        }
    }
}

I just converted from using socket to HttpListener for our application, and so far only 2 hangup in 24 hours, after thousands of requests.
This is the best results I could get so far, but not perfect yet.

@ PhilM - I confirm that httplistner is better reliableā€¦ When get context is executed, I suggest to run a separate thread to serve the caller http request

After reviewing the source code to the HTTP Listener class, there are only two things that directly stand-out as differences, and that has to do with the socket options. In the background, HTTPListener is using Socket.Accept, just as what was posted with the initial problem. Try adding these to parameters, replacing SOCKET with the name of your Socket.

// set NoDelay to increase HTTP(s) response times
                m_listener.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);

                // Start server socket to accept incoming connections.
                m_listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

I have tried to put those socket options before the listenSocket.Bind(ep);
after the listenSocket.Bind(ep);
and also after the listenSocket.Listen(5);
It still does the same behavior as before and this is with the same code posted on the first post of the thread.

I have a question though, just trying to clarify: do you guys have been able to reproduce the bug I posted in the first page of the thread?
On my end, Iā€™ve tested with a G120HDR+ENCJ60 gadgeteer module and still get the same problem (hang at Socket.Accept).
Also the wifi version does not seem to have this bug at all.
What is different between the RS21 socket code and ethernet ENC28J60 code?

Iā€™m ready to help and test more things if necessary to help resolve this bug.


void ServerThread() {
            
            // Bind the listening socket to the port
            IPAddress hostIP = IPAddress.Parse(NetInterface.NetworkInterface.IPAddress);
            IPEndPoint ep = new IPEndPoint(hostIP, 80);
            listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            

            listenSocket.Bind(ep);
            
            // Start listening
            listenSocket.Listen(5);
            // set NoDelay to increase HTTP(s) response times
            listenSocket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);

            // Start server socket to accept incoming connections.
            listenSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            string msgStr = "Hello, browser! I think the time is " + DateTime.Now.ToString();
            string responseStr = "";
            for (int i = 0; i < 150; i++) {
                responseStr = responseStr + "\r" + msgStr;
            }


            byte[] messageBytes = Encoding.UTF8.GetBytes(responseStr);

            //ExecutionConstraint.Install((int)(new TimeSpan(0, 0, 5)).Ticks, 0);

            // Main thread loop
            while (true) {
                try {
                    //ExecutionConstraint.Install((int)(new TimeSpan(0, 0, 5)).Ticks, 0);
                    serverSocket = listenSocket.Accept();
                    //ExecutionConstraint.Install(-1,0);
                    Debug.Print("Accepted a connection from " + serverSocket.RemoteEndPoint.ToString());
                } catch (ConstraintException e) {
                    Debug.Print("Constraint exception occured");
                    continue;
                } catch (Exception e) {
                    Debug.Print("Exception @ listenSocket.Accept():" + e.Message);
                    continue;
                }

              
                
                if (!ReadAll()) {
                    continue;
                }

                try {
                    serverSocket.Send(messageBytes);

                } catch (Exception e) {
                    Debug.Print("Exception @ listenSocket.Send():" + e.Message);
                    if (ReadAll()) {
                    }
                    CloseSocket();
                    continue;
                }
                CloseSocket();
                serverSocket = null;
            }



        }

Would it be possible to fix the exception when closing the ENC28J60 module? So it can be disposed gracefully?
Right now if you do a : enc28J60.Close() it throws an exception
Also if you reinstantiate and close the interface many times, it will corrupt the flash eventually.

I ask this because I could use that workaround as a temp fix: Close the enc28J60 interface, and instantiate it again, the socket.Accept() will generate an exception , and next time it is called after the IP address is UP, it will work, until it bugs out again and detect it with a timer. But at least the network will work most of the timeā€¦

@ dobova With httpListener, did you test if it can handle correctly the disconnection/reconnection of the network cable and other networking issues ?
Right Iā€™ve not been able to make it work reliably: If the network cable is removed and reconnected a couple times, eventually httpListener just generates tons of exceptions and is broken:(

Ok this is what I though Im already trying to implement what you described but still cannot get it done relaibly ā€¦ will work on it.!

@ PhilM - HttpListener has sure problems on cable detach/attach ā€¦ these are exception got under ā€œtryā€ block:



Built-in Ethernet Cable is Disconnected!
    #### Exception System.Net.Sockets.SocketException - CLR_E_FAIL (12) ####
    #### Message: 
    #### Microsoft.SPOT.Net.SocketNative::poll [IP: 0000] ####
    #### System.Net.Sockets.Socket::Poll [IP: 0011] ####
    #### System.Net.Sockets.Socket::Accept [IP: 0017] ####
    #### System.Net.HttpListener::AcceptThreadFunc [IP: 0020] ####
    #### SocketException ErrorCode = 10050
    #### SocketException ErrorCode = 10050
Eccezione first-chance di tipo 'System.Net.Sockets.SocketException' in Microsoft.SPOT.Net.dll
    #### SocketException ErrorCode = 10050
    #### SocketException ErrorCode = 10050
Il thread '<Nessun nome>' (0xc) ĆØ terminato con il codice 0 (0x0).

The simplyfied code :


... // listener Thread ...
            while (true)
            {
                // wait for call from client:
                try
                {
                    wctx = listener.GetContext();
                    // got call:            
                    wreq = wctx.Request;
                    wctx.Response.ContentType = "text/plain";
                    wctx.Response.SendChunked = false;
                    Debug.Print("URL: " + wctx.Request.RawUrl);
                }
                catch (Exception ex)
                {
                    listener.Stop();      // the underneath socket is complete messed up now ...
                    listener.Close();
                    listener = null;
                    return;
                }
.... 

When I reattach cable I have problem to restart thread, but not always. The CableConnectivityChanged event is fired, but after 2-3 times it fires but doesnā€™t restart thread never again until reset ā€¦

Just to better clarify what I get, it seems that once you disconnect the cable the httplistner (and so the socket ) is always binded to address/port, so any new attempt to start listener it fails due to locked port (socket error 10048).

This doesnā€™t change also if you Close() and then Open() again NetworkInterface.
For a temporary solution, I reset board by code any time the cable is disconnected and connected again, but this is very fancy solution ā€¦

I seeā€¦
So back to square one, if I cannot get disconnection/reconnection reliably with HttpListener, it does not help at all. My product need to be able to handle being disconnected/reconnected.
At least when using sockets, it was able to handle disconnection and reconnection with no problems, but it suffers from the Socket.Accept() ā€œhangā€ problemā€¦

@ PhilM - Yea, I find interesting the HttpListner, becouse it let you fastly develop without worry too much about the underlying socket.
Fortunately in my application the rialability of the connection is not an issue becouse itā€™s inserted in a big managed network; in any case it may happens, of course, but a complete restart of the application is accettable.