Socket.accept() periodic hang

I have been evaluating the capabilities of G80 and testing a few implementations of some socket servers, mostly based on some examples from this forum (specifically https://www.ghielectronics.com/community/forum/topic?id=22141&page=13#msg208815) before get stuck into fleshing out my own for a project coming up.

I have been having some problems diagnosing some strange behaviour:
I have setup a browser tab auto-refreshing every 2 seconds. The code (below) will serve responses back to the browser for hours so far but the socket seems to hang very reliably and periodically every 10sec or so then recover. The picture attached shows Chromeā€™s request timeline with the auto-refresher going at 2seconds.

Any help would be appreciated.

Looking down the line, this project will require reliable network access for weeks/months at a time. Is this feasible at the moment with netmf? Has anyone set up a server with this level of reliability? If so Iā€™d be interested in chatting about code and costs if anything is for sale.


public class SimpleWebServer
    {
        private AutoResetEvent _listenerStarted;
        internal Socket _socket;
        internal Thread _thread;
        internal Thread _acceptThread;
        private IPAddress _interfaceAddress = IPAddress.Any;
        private int _receiveTimeout = -1;
        private int _sendTimeout = -1;
        private int _listenBacklog = 5;
        private bool _isActive = false;

        const int BufferSize = 1460;
        const int StringLength = 500 * 1024;

        const int READ_CHUNK_SIZE = 1460;// 
        public static Object SDCardLock = new Object();

        static DateTime _bootTime = DateTime.Now;

        static string html = "";
        static byte[] response = new byte[BufferSize*2];

        static int _numReceived;
        static byte[] _receiveBuffer = new byte[BufferSize*2];

        static EndPoint remoteEndPoint;
        int numBytesToWrite ;
        int offset = 0;
        int bytesSent;
        int sendSize;

        static Microsoft.SPOT.Hardware.OutputPort LED2;
        static Microsoft.SPOT.Hardware.OutputPort LED3;
        static Microsoft.SPOT.Hardware.OutputPort LED4;

        public bool Start(int servicePort)
        {
            try
            {
                LED2 = new Microsoft.SPOT.Hardware.OutputPort(GHI.Pins.G80.Gpio.PE13, false);
                LED3 = new Microsoft.SPOT.Hardware.OutputPort(GHI.Pins.G80.Gpio.PE11, false);
                LED4 = new Microsoft.SPOT.Hardware.OutputPort(GHI.Pins.G80.Gpio.PE9, false);

                _listenerStarted = new AutoResetEvent(false);

                _interfaceAddress = System.Net.IPAddress.GetDefaultLocalAddress();

                _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint _localEndPoint = new IPEndPoint(_interfaceAddress, servicePort);

                _socket.Bind(_localEndPoint);
                _socket.ReceiveTimeout = _receiveTimeout;
                _socket.SendTimeout = _sendTimeout;

                _socket.Listen(_listenBacklog);

                _isActive = true;
                _thread = new Thread(StartListen);
                _thread.Start();

                _listenerStarted.WaitOne();

                
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }

        public bool Stop()
        {
            try
            {
                _isActive = false;
                _socket.Close();
            }
            catch (Exception)
            {
                return false;
            }

            return true;
        }

        private void StartListen()
        {

            _listenerStarted.Set();

            while (_isActive)
            {
                try
                {

                    LED2.Write(true);
                    var clientSocket = _socket.Accept();
                    _acceptEvent.Set();
                    LED2.Write(false);

                    LED3.Write(true);
                    new Thread(() =>
                    {
                        try
                        {
                            OnSocket(clientSocket);
                        }
                        catch (Exception ex)
                        {
                            throw ex;
                        }
                    }).Start();


                }
                catch (SocketException ex)
                {
                    Debug.Print("SocketException in Accept(): errorcode: " + ex.ErrorCode);
                    //throw;

                }
            }

            _socket.Close();
        }

        protected virtual void OnSocket(Socket socket)
        {
            try
            {
                //if (socket.Poll(-1, SelectMode.SelectRead))
                //{
                //    //remoteEndPoint = new IPEndPoint(0, 0);

                //    if (socket.Available == 0)
                //    {
                //        LED4.Write(true);
                //        return;
                //    }
                //}

                while (!socket.Poll(100000, SelectMode.SelectRead))
                {
                    if (socket.Poll(10, SelectMode.SelectError))
                    {
                        Debug.Print("RCP Client Socket error");
                        throw new ApplicationException("RCP Client Socket error");
                    }
                    Thread.Sleep(0);
                }
                if (socket.Available == 0)
                {
                    // disconnect
                    return ;
                }

                _numReceived = socket.Receive(_receiveBuffer, BufferSize*2, SocketFlags.None); 
                

                    html = "<!DOCTYPE html><html><body><h1> Sample Test. Uptime: " + (DateTime.Now - _bootTime).ToString() + "<br>GC: " + Debug.GC(false) + "</h1></html>";

                    response = Encoding.UTF8.GetBytes("HTTP/1.1 200 OK\nServer: dingus server\nContent-Length: " + html.Length + "\nAccept-Ranges: bytes\nContentType: application/octet-stream\nConnection: close\n\n" + html);

                    

                    numBytesToWrite = response.Length;
                    offset = 0;

                    do
                    {
                        sendSize = (numBytesToWrite <= BufferSize) ? numBytesToWrite : BufferSize;

                        bytesSent = socket.Send(response, offset, sendSize, SocketFlags.None);
                        numBytesToWrite -= bytesSent;
                        offset += bytesSent;

                    } while (numBytesToWrite > 0);



                    //response = Encoding.UTF8.GetBytes(html);

                    //numBytesToWrite = response.Length;
                    //offset = 0;

                    //do
                    //{
                    //    sendSize = (numBytesToWrite <= BufferSize) ? numBytesToWrite : BufferSize;

                    //    bytesSent = socket.Send(response, offset, sendSize, SocketFlags.None);
                    //    numBytesToWrite -= bytesSent;
                    //    offset += bytesSent;

                    //} while (numBytesToWrite > 0);


                    html = null;

                   //for (int i = 0; i < 1; i++)
                   // {
                   //     SendFile("\\SD\\LogFiles\\FTPTestingJune.pd0", socket);

                   // }
                

            }
            catch (SocketException ex)
            {
                Debug.Print("SocketException in OnSocket(): Code:" + ex.ErrorCode + ". Message: "+ ex.Message);
                if (ex.ErrorCode == (int)SocketError.ConnectionReset)
                    return;
            }
            catch (Exception ex)
            {
                Debug.Print("General exception in OnSocket(): " + ex.Message);

                throw ex;
            }
            finally
            {
                socket.Close();
                
            }
            LED3.Write(false);

        }
1 Like

Yes, I have read that browser refreshing breaks sockets etc. but is this the cause of the hang? At one point I thought it could be a memory-related problem but changing the refresh rate to a slower rate still shows the same behaviour: every 10 seconds (approx) the page request times out, or takes a [em]very[/em] long time to respond (~6-8sec) instead of the normal ~70ms

I will try an example not using page re-freshing to see if that makes any difference.

Ok, Iā€™ve just found and tried the Simple Network Test Tool code share (https://www.ghielectronics.com/community/codeshare/entry/1076) and modified it for the G80 dev board and it looks like Iā€™m getting the same behaviour: packets are sent and received correctly for about 5-15 seconds then it gets stuck in Accept and the request usually times out. Iā€™ve got some LEDā€™s around the Accept() and processRequest() to try see whats going on.

Any ideaā€™s would be much appreciated.

                    
 led2.Write(true);
clientSocket = socket.Accept();
led2.Write(false);
led3.Write(true);
ProcessClientRequest(clientSocket);
led3.Write(false);

Just an update on my ventures:
[ul]After the the same strange results I eventually figured out that the two G80 dev boards that Iā€™m using have the same MAC addressā€¦:wall:I see that I neglected to mention that I had two devices connected in my original question[/ul] [ul]with only 1 dev board on the network the code works well and as expected for hours with multiple tabs refreshing and GHIā€™s PC Client hitting it as well. It is running in single threaded mode at the moment, and Iā€™ll look into a Threadpool or something later[/ul][ul]I will run this over night, but the performance is leagues ahead of what it was before[/ul]

I now have another problem unrelated to sockets: I tried changing the MAC address using FEZ Config and now the dev board is in a very strange stateā€¦:
[ul]When I reset it, it pops up in Device Manager as ā€˜G80ā€™, and my application boots and runs fine, however[/ul][ul]I canā€™t see it in the list of USB devices in Visual Studio, MFDeploy or FEZ Config [/ul][ul]When I try boot into GHI Bootloader (holding down LDR0 and LDR1) the serial port appears in Device Manager, however I canā€™t ping it in MFDeploy or FEZ Config, and updating the firmware through the serial port fails tooā€¦[/ul]

Iā€™m sure where to go from here. Any ideas? Should I post this on a new thread?

Thanks!

those states youā€™re talking about are when that device is the ONLY Fez device connected to your PC at a time, right? Just to remove any confusion there, make sure you have no instances of VS running when doing work in Fez Config. I think youā€™re doing the right thing by trying to get into bootloader mode to erase the device and to reapply the firmware - that is the way to get to ā€œknown stateā€. And yes, you absolutely need two different MAC addressesā€¦

@ joshuaberry - The MAC address for the G80 should be updated in your program, not FEZ Config. Set the PhysicalAddress property on the network interface object.

I have actually re-named one of the board to ā€œG80_2ā€ to distinguish between them.

Thanks @ brett - After a restart and with VS closed the board is accessible nowā€¦ Something to keep in mind for later.

Iā€™m betting you had an active debug session to one kept openā€¦ always easiest to make sure you shut all related apps (fez config, mfdeploy, VS) down

I had to do the same when working on two G120 boards at the same time otherwise VS keeps swapping them over which is a pain if they, as in my case, running different hardware.