Main Site Documentation

Raptor board has SocketException ErrorCode 10055 about every 30 minutes


#1

Cobra board did not have this problem. I am using .NETMF 4.2. My code is making an HTTP request every 30 seconds to a web server. It works ok for about 30 minutes, then the exception is thrown.

Here is an example activity log:

StatusMonitorLoop() - InputCoilStatus changed
13:38:57.290 Request: http://192.168.8.134/api/device/03f6dd58-b27f-7c5a-921d-711d014f836a/notification
13:38:57.313 Method = POST ContentType = application/json Auth-DeviceID = 03f6dd58-b27f-7c5a-921d-711d014f836a Timeout = 120000 Body = {“notification”: “EquipmentStatus”, “parameters”: { “Left Traffic Eye X2”: “Unblocked”, “Right Traffic Eye X3”: “Unblocked”, “PLC Status”: “OnLine”, “equipment”: “CONTROLLER”, “PLC Error Code”: “RECEIVE_SUCCESS”, “Front Traffic Eye X0”: “Blocked”, “Back Traffic Eye X1”: “Unblocked” }}
#### Exception System.Net.Sockets.SocketException - CLR_E_FAIL (230) ####
#### Message:
#### Microsoft.SPOT.Net.SocketNative::socket [IP: 0000] ####
#### System.Net.Sockets.Socket::.ctor [IP: 001f] ####
#### System.Net.HttpWebRequest::EstablishConnection [IP: 0132] ####
#### System.Net.HttpWebRequest::SubmitRequest [IP: 0019] ####
#### System.Net.HttpWebRequest::GetRequestStream [IP: 0008] ####
#### SocketException ErrorCode = 10055
#### SocketException ErrorCode = 10055
A first chance exception of type ‘System.Net.Sockets.SocketException’ occurred in Microsoft.SPOT.Net.dll
#### SocketException ErrorCode = 10055
#### SocketException ErrorCode = 10055
#### SocketException ErrorCode = 10055
#### SocketException ErrorCode = 10055
A first chance exception of type ‘System.Net.Sockets.SocketException’ occurred in System.Http.dll
#### SocketException ErrorCode = 10055
#### SocketException ErrorCode = 10055
13:38:57.668 GetRequestStreamAsync(): System.Net.Sockets.SocketException
The thread ‘’ (0xe6) has exited with code 0 (0x0).
#### Exception System.Net.Sockets.SocketException - CLR_E_FAIL (11) ####
#### Message:
#### DeviceHive.HttpClient::GetRequestStreamAsync [IP: 002d] ####
#### DeviceHive.HttpClient::MakeRequest [IP: 00e2] ####
#### DeviceHive.HttpClient::PostNotification [IP: 0039] ####
#### DeviceHive.DeviceEngine::SendNotification [IP: 003d] ####
#### DeviceHive.EquipmentEngine::SendNotificationList [IP: 002b] ####
#### SmartTruckRaptor.BusinessLogic::SendNotification [IP: 0005] ####
#### SmartTruckRaptor.BusinessLogic::StatusMonitorLoop [IP: 012b] ####
#### SocketException ErrorCode = 10055
#### SocketException ErrorCode = 10055
A first chance exception of type ‘System.Net.Sockets.SocketException’ occurred in HttpClient.dll
#### SocketException ErrorCode = 10055
#### SocketException ErrorCode = 10055
08/07/2014 13:38:57 Exception in StatusMonitorLoop(): Exception was thrown: System.Net.Sockets.SocketException
08/07/2014 13:38:57 DeviceHive.HttpClient::GetRequestStreamAsync
DeviceHive.HttpClient::MakeRequest
DeviceHive.HttpClient::PostNotification
DeviceHive.DeviceEngine::SendNotification
DeviceHive.EquipmentEngine::SendNotificationList
SmartTruckRaptor.BusinessLogic::SendNotification
SmartTruckRaptor.BusinessLogic::StatusMonitorLoop

Here is my code for the HTTP request. The function GetRequestStreamAsync() has thread that calls GetRequestStream(), which throws the exception.


using System;
using Microsoft.SPOT;
using System.Net;
using System.IO;
using Json.Serialization;
using System.Text;
using System.Collections;
using System.Threading;


using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
//using GTME = Gadgeteer.Modules.GHIElectronics;

namespace DeviceHive
{
    /// <summary>
    /// HTTP client for restful HTTP service
    /// </summary>
    /// <remarks>
    /// Complies to HTTP protocol v.6.
    /// Implements device-specific commands for .NET Micro Framework device.
    /// </remarks>
    public class HttpClient : IFrameworkClient
    {
        public string CloudUrl { get; set; }

        private const string PutMethod = "PUT";
        private const string GetMethod = "GET";
        private const string PostMethod = "POST";
        private const string DeleteMethod = "DELETE";

        private const string ContentType = "application/json";

        //private const string PutDeviceCommand = "/device";
        private const string InfoCommand = "/info/";
        private const string DeviceCommand = "/device/";
        private const string NotificationCommand = "/notification";
        private const string PollCommandName = "/command/poll?timestamp=";
        //private const string GetCommandName = "/command?start=";
        private const string CommandStatus = "/command/";
        // v6
        private const string IdHeader = "Auth-DeviceID";
        private const string KeyHeader = "Auth-DeviceKey";

        private Queue CommandQueue;
        private string lastTimeStamp;
        private int AsyncTimeout;

        //private int counter;
        /// <summary>The Button module using socket 11 of the mainboard.</summary>


        /// <summary>
        /// Constructs an HTTP client object
        /// </summary>
        /// <param name="Url">URL of the DeviceHive server</param>
        /// <param name="RequestTimeout">Maximum request timeout</param>
        /// <param name="TimeStamp">Timastamp of the last command</param>
        /// <remarks>
        /// If the caller has no intention to set a specific time stamp, DeteTime.MinValue can be used.
        /// </remarks>
        public HttpClient( string Url, int RequestTimeout, string TimeStamp = null)
        {
            CloudUrl = Url;
            
            CommandQueue = new Queue();
            AsyncTimeout = RequestTimeout;
            LastTimeStamp = TimeStamp;
        }

        private string LastTimeStamp
        {
            get
            {
                if (lastTimeStamp == null)
                {
                    lastTimeStamp = GetApiInfo().serverTimestamp;
                }
                return lastTimeStamp;
            }
            set
            {
                lastTimeStamp = value;
            }
        }

        //public Device GetDevice(Guid id)
        //{
        //    HttpWebRequest req = HttpWebRequest.Create(CloudUrl + GetDeviceCommand + id.ToString()) as HttpWebRequest;
        //    req.Method = GetMethod;
        //    WebResponse resp = req.GetResponse();
        //    Stream stm = resp.GetResponseStream();
        //    JsonSerializer js = new JsonSerializer();
        //    return (Device)js.Deserialize(stm, typeof(Device));
        //}

        /// <summary>
        /// Performs an asynchronous request and returns its response
        /// </summary>
        /// <param name="req">Request to be executed</param>
        /// <returns>HTTP response; it can be null in case of an error</returns>
        private HttpWebResponse GetResponseAsync(HttpWebRequest req)
        {
            HttpWebResponse resp;
            //_req = req;
            resp = null;
            Exception exthread = null;
            Thread th = new Thread(() =>
            {
                try
                {
                    resp = (HttpWebResponse)req.GetResponse();
                }
                catch (Exception ex)
                {
                    Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") + " GetResponseAsync(): " + ex.ToString());
                    exthread = ex;
                }
                //_recvEvent.Set();
            });
            
            
            th.Start();
            if (!th.Join(AsyncTimeout))
            {
                Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") + " GetResponseAsync() aborting the GetResponse thread on timeout");
                th.Abort();
                resp = null;
                throw new System.Net.WebException("HTTP connection timeout",  WebExceptionStatus.Timeout);    //InvalidOperationException("Timeout!");
            }
            if (resp == null)
            {
                if (exthread != null)
                    throw exthread;
                else
                    throw new System.Net.WebException("GetResponse failed");
            }
            return resp;
        }


        private Stream GetRequestStreamAsync( HttpWebRequest req  )
        {
            Stream rs = null;
            Exception exthread = null;
            Thread th = new Thread(() =>
            {
                try
                {
                    rs = req.GetRequestStream();
                }
                catch (Exception ex)
                {
                    Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") + " GetRequestStreamAsync(): " + ex.ToString());
                    exthread = ex;
                }
            });

            th.Start();
            if (!th.Join(AsyncTimeout))
            {
                Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") + " GetRequestStreamAsync() aborting the GetRequestStream thread on timeout");
                th.Abort();
                rs = null;
                throw new System.Net.WebException("HTTP connection timeout", WebExceptionStatus.Timeout);   //InvalidOperationException("Timeout!");
            }
            if (rs == null)
            {
                if (exthread != null)
                    throw exthread;
                else
                    throw new System.Net.WebException("GetResponse failed");
            }
            return rs;
        }

        private WebResponse MakeRequest(string url, object obj, string Method, string id, string key)
        {
            StringBuilder headers = new StringBuilder();
            Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") + " Request: " + url);
            using (HttpWebRequest req = HttpWebRequest.Create(url) as HttpWebRequest)
            {

                req.Method = Method;
                req.ContentType = ContentType;
                req.KeepAlive = false;
                req.Headers.Add(IdHeader, id);
                req.Headers.Add(KeyHeader, key);
                req.ReadWriteTimeout = AsyncTimeout;
                req.Timeout = AsyncTimeout;

                headers.Append(" Method = " + Method);
                headers.Append(" ContentType = " + ContentType);
                headers.Append(" " + IdHeader + " = " + id);
                //headers.Append(" " + KeyHeader + " = " + key);
                headers.Append(" Timeout = " + AsyncTimeout.ToString());

                if (obj != null)
                {
                    JsonFormatter js = new JsonFormatter();

                    string s = js.ToJson(obj);
                    req.ContentLength = s.Length;

                    //headers.Append(" ContentLength = " + s.Length);
                    headers.Append(" Body = " + s);
                    Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") + headers.ToString());

                    Stream rs = GetRequestStreamAsync(req);
                    if (rs == null)
                        return (null);
                    using (rs)
                    {
                        rs.Write(Encoding.UTF8.GetBytes(s), 0, s.Length);
                        rs.Close();
                    }
                }
                else
                {
                    Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") + headers.ToString());
                }

                HttpWebResponse resp = GetResponseAsync(req); //was (HttpWebResponse)req.GetResponse(); //
                if (resp != null)
                {
                    Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") + " Request done. Response code = " + resp.StatusCode.ToString());
                }
                return resp;
            }
        }


        /// <summary>
        /// Gets API info.
        /// </summary>
        /// <returns><see cref="ApiInfo"/> object.</returns>
        public ApiInfo GetApiInfo()
        {
            byte[] bts = null;
            HttpWebResponse resp = MakeRequest(CloudUrl + InfoCommand, null, GetMethod, null, null) as HttpWebResponse;

            if (resp.ContentType.IndexOf(ContentType) >= 0)
            {

                if (resp.ContentLength > 0)
                {
                    using (Stream rs = resp.GetResponseStream())
                    {
                        bts = new byte[(int)rs.Length];
                        rs.Read(bts, 0, bts.Length);
                        rs.Close();
                    }
                }
            }
            resp.Close();

            if (bts != null)
            {
                JsonFormatter js = new JsonFormatter();
                object o = js.FromJson(bts, typeof(ApiInfo));

                ApiInfo ai = o as ApiInfo;
                if (ai != null)
                {
                    return ai;
                }
            }
            throw new Exception("Unknown error while getting ApiInfo.");
        }

        /// <summary>
        /// Registers a device
        /// </summary>
        /// <param name="device">Device data structure</param>
        /// <returns>True, if registration succeeds; false - otherwise</returns>
        /// <remarks>
        /// This method is called by device to register it at the server.
        /// </remarks>
        public bool SetDevice(Device device)
        {
            //bool rv = false;
            HttpWebResponse resp = MakeRequest(CloudUrl + DeviceCommand + device.id.ToString(), 
                device, 
                PutMethod, 
                device.id.ToString(), 
                device.key) as HttpWebResponse;
            return resp.StatusCode == HttpStatusCode.OK || resp.StatusCode == HttpStatusCode.NoContent;
        }

        /// <summary>
        /// Sends a notification
        /// </summary>
        /// <param name="device">Device data of the device that is sending the notification</param>
        /// <param name="notification">Notification to be sent</param>
        /// <returns>True if the notification succeeds; false - otherwise</returns>
        /// <remarks>
        /// This method can be used by devices to send notifications.
        /// </remarks>
        public bool PostNotification(Device device, INotification notification)
        {
            //bool rv = false;

            HttpWebResponse resp = MakeRequest(
                CloudUrl + DeviceCommand + device.id.ToString() + NotificationCommand,
                notification.Data,
                PostMethod,
                device.id.ToString(),
                device.key) as HttpWebResponse;
            return resp.StatusCode == HttpStatusCode.OK || resp.StatusCode == HttpStatusCode.Created;
                //resp.Close();
        }

        /// <summary>
        /// Polls command for execution
        /// </summary>
        /// <param name="device">Device data of the device that is polling a command</param>
        /// <param name="onlyUnprocessed">Get commands with empty status only</param>
        /// <returns>Command data structure or null if there are no commands</returns>
        /// <remarks>
        /// This method returns the next command from the command queue. If there are no commands in the queue, it waits for ~30 seconds to receive a new command.
        /// </remarks>
        public DeviceCommand PollCommand(Device device, bool onlyUnprocessed = true)
        {
            if (CommandQueue.Count != 0)
            {
                return (DeviceCommand)CommandQueue.Dequeue();
            }
            string TimeString = UriExtensions.EscapeDataString(LastTimeStamp);
            string Url = CloudUrl + DeviceCommand + device.id.ToString() + PollCommandName + TimeString;

            byte[] bts = null;
            WebResponse resp = MakeRequest(Url, null, GetMethod, device.id.ToString(), device.key);

            if (resp.ContentType.IndexOf(ContentType) >= 0)
            {

                if (resp.ContentLength > 0)
                {
                    using (Stream rs = resp.GetResponseStream())
                    {
                        bts = new byte[(int)rs.Length];
                        rs.Read(bts, 0, bts.Length);
                        rs.Close();
                        try
                        {
                            string strjson = new string(Encoding.UTF8.GetChars(bts));
                            if ( strjson != "[]" )
                                Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") + " " + strjson);
                        }
                        catch (Exception ex)
                        {
                            Debug.Print("PollCommand() : " + ex.ToString());
                        }
                    }
                }
            }
            resp.Close();

            if (bts != null)
            {
                JsonFormatter js = new JsonFormatter();
                object o = js.FromJson(bts, typeof(DeviceCommand));

                DeviceCommand dc = o as DeviceCommand;
                if (dc != null && (!onlyUnprocessed || StringExtensions.IsNullOrEmpty(dc.status)))
                {
                    return dc;
                }
                ArrayList al = o as ArrayList;
                if (al != null)
                {
                    if (al.Count == 0) return null;

                    for (int x = 0; x < al.Count; ++x)
                    {
                        dc = (DeviceCommand)al[x];
                        if (!onlyUnprocessed || StringExtensions.IsNullOrEmpty(dc.status))
                        {
                            CommandQueue.Enqueue(dc);
                        }
                    }
                    DeviceCommand ldc = (DeviceCommand)al[al.Count - 1];
                    LastTimeStamp = ldc.timestamp;

                    return CommandQueue.Count == 0 ? null : (DeviceCommand)CommandQueue.Dequeue();
                }
            }
            return null;
        }

        /// <summary>
        /// Gets a command
        /// </summary>
        /// <param name="device">Device data of the device that is getting a command</param>
        /// <param name="onlyUnprocessed">Get commands with empty status only</param>
        /// <returns>Command data structure or null if there are no pending commands</returns>
        /// <remarks>
        /// This method returns all the commands that are waiting at the server since last GetCommand call. It returns immediately, regardless if there are commands to execute or not.
        /// </remarks>
        public DeviceCommand GetCommand(Device device, bool onlyUnprocessed = true)
        {
            if (CommandQueue.Count != 0)
            {
                return (DeviceCommand)CommandQueue.Dequeue();
            }
            string TimeString = UriExtensions.EscapeDataString(LastTimeStamp);
            string Url = CloudUrl + DeviceCommand + device.id.ToString() + PollCommandName + TimeString + "&waitTimeout=0";

            byte[] bts = null;
            WebResponse resp = MakeRequest(Url, null, GetMethod, device.id.ToString(), device.key);

            if (resp.ContentType.IndexOf(ContentType) >= 0)
            {

                if (resp.ContentLength > 0)
                {
                    using (Stream rs = resp.GetResponseStream())
                    {
                        bts = new byte[(int)rs.Length];
                        rs.Read(bts, 0, bts.Length);
                        rs.Close();
                    }
                }
            }
            resp.Close();

            if (bts != null)
            {
                JsonFormatter js = new JsonFormatter();
                object o = js.FromJson(bts, typeof(DeviceCommand));

                DeviceCommand dc = o as DeviceCommand;
                if (dc != null && (!onlyUnprocessed || StringExtensions.IsNullOrEmpty(dc.status)))
                {
                    return dc;
                }
                ArrayList al = o as ArrayList;
                if (al != null)
                {
                    if (al.Count == 0) return null;

                    for (int x = 0; x < al.Count; ++x)
                    {
                        dc = (DeviceCommand)al[x];
                        if (!onlyUnprocessed || StringExtensions.IsNullOrEmpty(dc.status))
                        {
                            CommandQueue.Enqueue(dc);
                        }
                    }
                    DeviceCommand ldc = (DeviceCommand)al[al.Count - 1];
                    LastTimeStamp = ldc.timestamp;

                    return CommandQueue.Count == 0 ? null : (DeviceCommand)CommandQueue.Dequeue();
                }
            }
            return null;
        }

        /// <summary>
        /// Updates command status
        /// </summary>
        /// <param name="device">Device data of the device that is updating a command status</param>
        /// <param name="CommandId">ID of the command to be updated</param>
        /// <param name="status">Status of the command</param>
        /// <returns>True if the status update was successfull; false - otherwise</returns>
        /// <remarks>
        /// The devices are using this method to notify the server of command completion and its result. 
        /// </remarks>
        public bool UpdateCommandStatus(Device device, string CommandId, CommandStatus status)
        {
            //bool rv = false;
            HttpWebResponse resp = MakeRequest(
                CloudUrl + DeviceCommand + device.id.ToString() + CommandStatus + CommandId,
                status,
                PutMethod,
                device.id.ToString(),
                device.key) as HttpWebResponse;

            return resp.StatusCode == HttpStatusCode.OK || resp.StatusCode == HttpStatusCode.NoContent;
        }
    }
}



#2

@ dspacek - The 10055 error code you see usually means that a buffer was exhausted. Can you create a very minimal example that reliably reproduces the problem? Is there any way you can get it to occur sooner than 30 minutes?


#3

My program communicates with the DeviceHive server available at
http://nn3993.pg.devicehive.com/admin/#user
This is where the http requests are being sent to.
You can get a sample for the .net MF from here
http://www.devicehive.com/
http://www.devicehive.com/devicehive-library-net-micro-framework
I have a Visual Studio project for the GHI Spider that talks to DeviceHive, derived from this sample on devicehive.com. Where can I upload it to you?


#4

@ dspacek - The program should be small enough that you can just post it on here. Can you modify your code a bit and try talking to a different HTTP server and see if the same error eventually presents itself?


#5

I believe I solved this problem. I have some functions in the DeviceHive framework that are calling HttpWebRequest.Create() about two times per minute, getting back an HttpWebResponse object, and not closing the HttpWebResponse object. An example is shown below, where I put in a resp.close() function. I have not seen the exception with error code 10055 again.


        /// <summary>
        /// Sends a notification
        /// </summary>
        /// <param name="device">Device data of the device that is sending the notification</param>
        /// <param name="notification">Notification to be sent</param>
        /// <returns>True if the notification succeeds; false - otherwise</returns>
        /// <remarks>
        /// This method can be used by devices to send notifications.
        /// </remarks>
        public bool PostNotification(Device device, INotification notification)
        {
            //bool rv = false;

            HttpWebResponse resp = MakeRequest(
                CloudUrl + DeviceCommand + device.id.ToString() + NotificationCommand,
                notification.Data,
                PostMethod,
                device.id.ToString(),
                device.key) as HttpWebResponse;
            HttpStatusCode StatusCode = resp.StatusCode;
            resp.Close();
            //return resp.StatusCode == HttpStatusCode.OK || resp.StatusCode == HttpStatusCode.Created;
            return StatusCode == HttpStatusCode.OK || StatusCode == HttpStatusCode.Created;
        }