Почему отправка данных сообщения с помощью WebRequest занимает так много времени?

В настоящее время я создаю приложение С# для привязки к онлайн-системе php/MySQL. Приложение должно отправлять данные публикации в скрипты и получать ответ.

Когда я отправляю следующие данные

username=test&password=test  

получаю следующие ответы...

Starting request at 22/04/2010 12:15:42  
Finished creating request : took 00:00:00.0570057  
Transmitting data at 22/04/2010 12:15:42  
Transmitted the data : took 00:00:06.9316931       <<--
Getting the response at 22/04/2010 12:15:49  
Getting response 00:00:00.0360036  
Finished response 00:00:00.0360036  
Entire call took 00:00:07.0247024  

Как вы можете видеть, на самом деле отправка данных в скрипт занимает 6 секунд, я провел дальнейшее тестирование, отправляя данные из telnet и отправляя данные из локального файла на URL-адрес, и они даже не занимают секунды, так что это не проблема с размещенным скриптом на сайте.

Почему для передачи данных требуется 6 секунд, когда это две простые строки?

Я использую собственный класс для отправки данных

class httppostdata
{
    WebRequest request;
    WebResponse response;

    public string senddata(string url, string postdata)
    {
        var start = DateTime.Now;
        Console.WriteLine("Starting request at " + start.ToString());

        // create the request to the url passed in the paramaters
        request = (WebRequest)WebRequest.Create(url);


        // set the method to post
        request.Method = "POST";
        // set the content type and the content length
        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = postdata.Length;
        // convert the post data into a byte array
        byte[] byteData = Encoding.UTF8.GetBytes(postdata);
        var end1 = DateTime.Now;
        Console.WriteLine("Finished creating request : took " + (end1 - start));

        var start2 = DateTime.Now;
        Console.WriteLine("Transmitting data at " + start2.ToString());
        // get the request stream and write the data to it
        Stream dataStream = request.GetRequestStream();
        dataStream.Write(byteData, 0, byteData.Length);
        dataStream.Close();
        var end2 = DateTime.Now;
        Console.WriteLine("Transmitted the data : took " + (end2 - start2));


        // get the response
        var start3 = DateTime.Now;
        Console.WriteLine("Getting the response at " + start3.ToString());


        response = request.GetResponse();
        //Console.WriteLine(((WebResponse)response).StatusDescription);
        dataStream = response.GetResponseStream();
        StreamReader reader = new StreamReader(dataStream);
        var end3 = DateTime.Now;
        Console.WriteLine("Getting response " + (end3 - start3));

        // read the response
        string serverresponse = reader.ReadToEnd();
        var end3a = DateTime.Now;
        Console.WriteLine("Finished response " + (end3a - start3));

        Console.WriteLine("Entire call took " + (end3a - start));

        //Console.WriteLine(serverresponse);
        reader.Close();
        dataStream.Close();
        response.Close();

        return serverresponse;
    }
}

И чтобы назвать это, я использую

private void btnLogin_Click(object sender, EventArgs e)
{
    // string postdata;

    if (txtUsername.Text.Length < 3 || txtPassword.Text.Length < 3)
    {
        MessageBox.Show("Missing your username or password.");
    }
    else
    {
        string postdata = "username=" + txtUsername.Text +
                          "&password=" + txtPassword.Text;

        httppostdata myPost = new httppostdata();
        string response = myPost.senddata("http://www.domainname.com/scriptname.php", postdata);
        MessageBox.Show(response);
    }
}

person Community    schedule 22.04.2010    source источник
comment
Я понимаю, что в вашем примере это http, но в вашем реальном шестисекундном тестовом сценарии URL https? Могут быть накладные расходы из-за рукопожатия, проверки списка отзыва сертификатов, вызова OCSP и т. д.   -  person John Wu    schedule 23.10.2013


Ответы (2)


Убедитесь, что вы явно установили для свойства прокси WebRequest значение null, иначе он попытается автоматически определить настройки прокси, что может занять некоторое время.

person Mant101    schedule 22.04.2010
comment
Если это случай с прокси, не лучше ли мне загрузить заставку и сделать пустой вызов? причина, по которой я спрашиваю, заключается в том, что программное обеспечение используется в нескольких сетях с ноутбуков, а в некоторых сетях используются прокси-серверы. - person ; 22.04.2010

Скорее всего, поскольку в вашем тесте вы вызываете это только один раз, задержка, которую вы видите, является кодом C #, компилируемым JIT.

Лучшим тестом было бы вызвать это дважды, отбросить тайминги с первого раза и посмотреть, лучше ли они.

Еще лучшим тестом было бы отбросить первый набор таймингов, а затем запустить его много раз и взять среднее значение, хотя для очень свободного «индикативного» представления в этом, вероятно, нет необходимости.

Кроме того, для такого времени вам лучше использовать класс System.Diagnostics.Stopwatch вместо System.DateTime.

[РЕДАКТИРОВАТЬ] Кроме того, принимая во внимание предложение Mant101 о прокси-серверах, если установка без прокси-сервера не решает проблемы, вы можете настроить Fiddler и настройте запрос на использование Fiddler в качестве прокси-сервера. Это позволит вам перехватывать фактические http-вызовы, чтобы вы могли получить более точную разбивку по времени самих http-вызовов из-за пределов фреймворка.

person Rob Levine    schedule 22.04.2010
comment
Это так неправильно. (1) Метод компилируется JIT перед запуском, а не на полпути. (2) JIT-компиляция такого короткого метода не занимает 6 секунд. (3) Время, необходимое для получения таймингов, незначительно по сравнению с 6 секундами. (4) Вы берете средние значения, когда измеряете короткие, критичные ко времени операции, которые занимают миллисекунды; не при общении с HTTP-сервером занимает 6 секунд. (5) Хотя точность DateTime.Now не так точна, как у секундомера, в диапазоне секунд разница в точности совершенно незначительна. - person dtb; 22.04.2010
comment
1) ЭТОТ метод может быть скомпилирован перед запуском, но вы заметите, что он вызывает другие методы. Именно эти могут быть сброшены по мере продвижения этого метода. 2) Время, необходимое для JIT, зависит от многих факторов, включая текущее использование памяти (и необходимость выгрузки страниц), скорость диска и т. д. Обычно это быстро. Всегда? нет. 3) Я никогда не говорил, что это не так. 4) Моя точка зрения заключается в том, что если этот медленный опыт был вызван чем-то вроде дискового ввода-вывода, усреднение может помочь уменьшить влияние. Я не говорил об усреднении для устранения временного джиттера. Ваше предположение, не мое. 5) Я сказал как общее правило. - person Rob Levine; 22.04.2010
comment
Дополнение к вашему пункту 4 - в вашей формулировке подразумевается, что вы чувствуете, что 6 секунд связаны с общением с HTTP-сервером. Я предполагаю, что это может быть не так. Вы выполняете усредненные кратковременные операции, чтобы уменьшить влияние джиттера тактовых импульсов и других источников случайных ошибок. Вы также можете сделать то же самое, чтобы уменьшить влияние на компьютер того, что ваша машина занята выполнением других задач, которые не очевидны во время тестирования. Возможно, стоит запускать одну и ту же задачу снова и снова, возможно, в разное время, чтобы исключить влияние скрытых запланированных или других задач. - person Rob Levine; 22.04.2010
comment
Спасибо за рекомендацию секундомера, я посмотрю на это, что касается JIT, это не так, поскольку я сделал несколько вызовов одной и той же функции один за другим и всегда получаю 5+ секунд, а система здесь представляет собой полноценный сервер с 6Gb оперативной памяти, собранной для разработки - person ; 22.04.2010
comment
Да - в этом случае вы, вероятно, устранили JITing как причину. - person Rob Levine; 22.04.2010
comment
это может показаться прокси, но как я могу проверить, настроен ли прокси перед отправкой передачи, и если прокси не настроен, установите для него значение null - person ; 22.04.2010
comment
Вам нужно проверить HttpWebRequest.Proxy, чтобы узнать, установлен ли прокси-сервер, но прочитайте документацию, потому что я не могу вспомнить точных деталей: msdn.microsoft.com/en-us/library/ IIRC , запрос будет использовать прокси-сервер по умолчанию (как в прокси-сервере IE), если он определен, если вы не переопределите его, чтобы использовать другой или не использовать его. - person Rob Levine; 22.04.2010