Main Site Documentation

HTTPWebRequest GetRequestStream() seems to last 4 s!


#1

Hello,

I am trying to make my FEZ Cobra communicate in SOAP with a service asmx on my PC, using SOAP 1.1.

It works fine but when I execute it several times on my FEZ, the GetRequestStream() takes between 300 ms to 4 s !!

Any idea what can make this time so unpredictable :’(and so long :o ??

Here is the code of my client. The dealing of the response is not important now :


using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using Socket = System.Net.Sockets.Socket;
using System.IO;

using MFUtilities;

namespace HttpClientSample
{
    public static class MyHttpClient
    {

        static string url = "http://172.30.5.135/Services/LioService.asmx";
        static string action = string.Empty;

        private static string CreateSoapEnvelope()
        {
            // Add
            
            String request = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
            request += "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n";
            request += "<soap:Body>\n";
            request += "<Add xmlns=\"http://tempuri.org/\">\n";
            request += "<firstNum>5</firstNum>\n";
            request += "<secondNum>2</secondNum>\n";
            request += "</Add>\n";
            request += "</soap:Body>\n";
            request += "</soap:Envelope>\n\n";
            action = "http://tempuri.org/Add";

            return request;
        }

        public static byte[] ConvertStringToBytes(string input)
        {
            MemoryStream stream = new MemoryStream();

            using (StreamWriter writer = new StreamWriter(stream))
            {
                writer.Write(input);
                writer.Flush();
            }

            return stream.ToArray();
        }

        public static void Main()
        {
            byte[] body = ConvertStringToBytes(CreateSoapEnvelope());

            // Create an HTTP Web request.
            HttpWebRequest request =
                HttpWebRequest.Create(url) as HttpWebRequest;

            // set the request type
            // we user utf-8 but set the content type here
            request.Method = "POST";
            request.ContentType = "text/xml;charset=\"utf-8\"";
            request.Accept = "text/xml";
            request.ContentLength = body.Length;

            // add the headers
            // the SOAPACtion determines what action the web service should use
            request.Headers.Add("SOAPAction", action);

            // Set request.KeepAlive to use a persistent connection. 
            request.KeepAlive = false;

            // add our body to the request

            Stopwatch sw1 = Stopwatch.StartNew();

            Stopwatch sw2 = Stopwatch.StartNew();
            Stream stream = request.GetRequestStream();
            Stopwatch sw4 = Stopwatch.StartNew();
            stream.Write(body, 0, body.Length);
            sw4.Stop();
            stream.Close();
            sw2.Stop();

            // Get a response from the server.
            Debug.Print("Request : " + DateTime.Now.ToString() + "-" + DateTime.Now.Millisecond);
            WebResponse resp = null;

            Stopwatch sw3 = null;

            try
            {
                sw3 = Stopwatch.StartNew();
                resp = request.GetResponse();
                sw3.Stop();
            }
            catch (Exception e)
            {
                Debug.Print("Exception in HttpWebRequest.GetResponse(): " +
                    e.ToString());
            }

            sw1.Stop();

            Debug.Print("stream taked : " + sw2.ElapsedMilliseconds + " ms");
            Debug.Print("stream.Write taked : " + sw4.ElapsedMilliseconds + " ms");
            Debug.Print("request.GetResponse taked : " + sw3.ElapsedMilliseconds + " ms");
            Debug.Print("total taked : " + sw1.ElapsedMilliseconds + " ms");

            // Get the network response stream to read the page data.
            if (resp != null)
            {
                sw1 = Stopwatch.StartNew();

                Stream respStream = resp.GetResponseStream();
                string page = null;
                byte[] byteData = new byte[4096];
                char[] charData = new char[4096];
                int bytesRead = 0;
                Decoder UTF8decoder = System.Text.Encoding.UTF8.GetDecoder();
                int totalBytes = 0;

                // allow 2 seconds for reading the stream
                respStream.ReadTimeout = 2000;

                // If we know the content length, read exactly that amount of 
                // data; otherwise, read until there is nothing left to read.
                if (resp.ContentLength != -1)
                {
                    Debug.Print("Response : " + DateTime.Now.ToString() + "-" + DateTime.Now.Millisecond);
                    for (int dataRem = (int)resp.ContentLength; dataRem > 0; )
                    {
                        Thread.Sleep(500);
                        Stopwatch sw5 = Stopwatch.StartNew();
                        bytesRead =
                            respStream.Read(byteData, 0, byteData.Length);
                        sw5.Stop();
                        if (bytesRead == 0)
                        {
                            Debug.Print("Error: Received " +
                                (resp.ContentLength - dataRem) + " Out of " +
                                resp.ContentLength);
                            break;
                        }
                        dataRem -= bytesRead;

                        // Convert from bytes to chars, and add to the page 
                        // string.
                        int byteUsed, charUsed;
                        bool completed = false;
                        totalBytes += bytesRead;
                        UTF8decoder.Convert(byteData, 0, bytesRead, charData, 0,
                            bytesRead, true, out byteUsed, out charUsed,
                            out completed);
                        page = page + new String(charData, 0, charUsed);

                        // Display the page download status.
                        Debug.Print("Bytes Read Now: " + bytesRead +
                            " Total: " + totalBytes);

                        Debug.Print("respStream.Read : " + sw5.ElapsedMilliseconds + " ms");
                    }

                    page = new String(
                        System.Text.Encoding.UTF8.GetChars(byteData));
                }
                else
                {
                    // Read until the end of the data is reached.
                    while (true)
                    {
                        // If the Read method times out, it throws an exception, 
                        // which is expected for Keep-Alive streams because the 
                        // connection isn't terminated.
                        try
                        {
                            Thread.Sleep(500);
                            bytesRead =
                                respStream.Read(byteData, 0, byteData.Length);
                        }
                        catch (Exception)
                        {
                            bytesRead = 0;
                        }

                        // Zero bytes indicates the connection has been closed 
                        // by the server.
                        if (bytesRead == 0)
                        {
                            break;
                        }

                        int byteUsed, charUsed;
                        bool completed = false;
                        totalBytes += bytesRead;
                        UTF8decoder.Convert(byteData, 0, bytesRead, charData, 0,
                            bytesRead, true, out byteUsed, out charUsed,
                            out completed);
                        page = page + new String(charData, 0, charUsed);

                        // Display page download status.
                        Debug.Print("Bytes Read Now: " + bytesRead +
                            " Total: " + totalBytes);
                    }

                    Debug.Print("Total bytes downloaded in message body : "
                        + totalBytes);
                }

                // Display the page results.
                Debug.Print(page);

                // Close the response stream.  For Keep-Alive streams, the 
                // stream will remain open and will be pushed into the unused 
                // stream list.
                resp.Close();

                sw1.Stop();
                Debug.Print("response treatment taked : " + sw1.ElapsedMilliseconds + " ms");
            }
        }
    }
}

I’ve got :

sw1 on writting = 500 ms … 4129 ms
sw2 = 292 ms … 3963 ms
sw3 = 3 ms
sw4 = 144 ms
sw1 or reception = 542 ms


#2

As Im test cobra HttpWebRequest is very slow on it. Try use socket if will be faster for your application…


#3

Well. Not the response I was hoping but thank you Dejan…

I’ve noticed that while I keep sending request to my server, only the first request is long. And if I stay more than 20 mn without sending anything, the next request will be long too. I’ve done a .Net client on my PC and I have the same issue.

So I’m trying to install a keep alive request every 15 mn to keep having the server responding me quickly.

And off course I keep in mind the possibility of using sockets.

Thank you.


#4

Hi,

Regarding this delay you are experiencing with the first call to the web service: most likely it is related with the recycling of the working process of IIS.
As you are calling an .asmx I’m assuming that it is hosted in a IIS.
When sessions are idling IIS recycles them and further, if no requests are being served it shuts down the web application restarting it again at the next request.
This is why you are seeing that extended delay in the first call and then an acceptable time on subsequent requests.

Adding a keepalive call to the web application will prevent IIS from shutting down the web application.
Moving to sockets will give you the same results as this issue is caused at the server side not with your client code.

Hope this helps. :slight_smile:


#5

Hi,

yes I agree : with a keep alive every 15 mn, it seems to be ok for now on.

I did watch with WireShark and notice that the server answer changed after 20 mn. Before 20 mn it answers to my first request indicating I’m gonna do SOAP with a continue. After, it only sends an ACK like 200 ms after. And the same with my SOAP request, it answers very fast with the response, or slowly with an ACK and a response a little while later.

So it is on the server side. And yes I am on IIS.

Thank you.