Member 12601798 Ответов: 2

C++ socket recv почему так медленно


недавно я встретил вопрос о функции recv программирования сокетов, позвольте мне представить предысторию вопроса ,
теперь у меня есть клиент и сервер на другом компьютере, клиент - это ОС Linux без какой-либо 3-й сетевой библиотеки, такой как ACE, curl ... и сервер - это ОС Windows - и я развернул http-сервер - Apache в моем проекте, Я отправлю HTTP-запрос от программирования сокетов на сервер, который является своевременным веб-сайтом php (примерно 1 раз в 2 секунды), и данные публикации инкаплюируются в формате Json, то есть http Content-Type: application / json, но когда я отправляю запрос, затем я получаю ответ в формате Json с сервера (на самом деле данные ответа не большие <5 * 1024), но в следующий, очень медленно, примерно более 10 секунд, тогда я могу получить ответ полностью , иногда не может быть никакого ответа Json, я полагаю, причина в том, что неподходящая длина буфера, я пробовал 1024, 2048, 512 ..., и результат разочаровал, ниже мой код recv, не могли бы вы помочь его увидеть ? заранее спасибо, кстати, я использую SOCK_STREAM в сокете
      void Communication::receive(char buffer[], int BUFFER_SIZE){
        static const int small_buf = 512;
        char buf[small_buf];
        bzero(buf,small_buf);
        int length = 0;
        char* pp = buffer;
        do{
            length = recv(socket_,buf,small_buf,0);
             if(length < 0)
                {
                connect_state_ = false;
                break;
                }else if(length == small_buf){
                connect_state_ = true;
                memcpy(pp, buf, small_buf);
                pp = pp+small_buf;  
            }else if(length < small_buf && length > 0)
            {
                connect_state_ = true;
                memcpy(pp, buf, length);
                pp = pp + length;
            }else if(length == 0)
            {
                break;
            }
        }while(length > 0);
//merge the small_buf into a big buffer which is big enough (50*1024), which is one of function's param 
}


Что я уже пробовал:

Я изменил длину buf, 512, 1024 ,2048, даже я изменил SOCK_DGRAW, чтобы отправить json, а затем recv , но результат тот же , recv очень медленный , я использую синхронизацию для связи с php-сайтом на сервере apache

Mohibur Rashid

Вы уверены, что ваш запрос работает быстро?

Member 12601798

да, ответ сервера очень короткий , и я пишу серверный код

2 Ответов

Рейтинг:
2

Jochen Arndt

Ваш сокет блокирует или не блокирует?

С блокирующими розетками, recv вызов будет возвращен только при наличии доступных данных (возвращаемое значение > 0), тайм-аута (возвращаемое значение 0) или ошибки (возвращаемое значение -1).

Ваш код будет ждать данных, получать их и снова ждать. Это будет бесконечный цикл, если вы не установили значение тайм-аута. При значении тайм-аута recv вызов будет возвращен по истечении этого времени, когда данные не будут получены. Согласно вашему описанию, это, по-видимому, имеет место со значением таймаута 10 секунд.

С неблокирующими сокетами вы должны использовать какую-то сигнализацию, когда данные доступны, и звонить recv неоднократно в то время как он возвращает -1 и errno является EAGAIN или EWOULDBLOCK.

Я предлагаю использовать неблокирующую розетку. С помощью блокирующих сокетов вы должны немедленно проанализировать полученные данные, чтобы определить, все ли данные были получены или их еще предстоит получить.


Member 12601798

спасибо Вам заранее, синхронизация и асинхронность не имеют ничего, чтобы улучшить ситуацию, я нахожу причину, по которой ответ идет так медленно , на самом деле я использую приведенный ниже код c++ для отправки Post-запроса,

строки PostString::prepare_send(константные строки&амп; хозяин, константная строка&амп; путь , константная строка&амп; content_type){
струнный поток;
инт content_length = str_.длина();
//соиь <&ЛТ; "длина содержимого" &ЛТ;&ЛТ; content_length на << епси;
char buffer[20] = { 0 };
num_to_buffer(content_length, buffer, 10);
строка str;
cp_buffer_string(буфер, кв. 20, );
поток + = " пост ";
поток += путь;
stream + = " HTTP / 1.1\r\n";
поток + = " хост: ";
трансляция += хозяин;
поток + = " \r\n";
трансляция += "пользователь-агент: корпорация Mozilla/5.0 (Windows; В У; для NT 5.1; ж-СН; как RV:1.9.2.3) движок Gecko/20100401 для Firefox/3.6.3\р\н";
если("JSON с" == content_type){

stream + = " Content-Type: application / json\r\n";
}еще{
stream + = " Content-Type: application/x-www-form-urlencoded\r\n";
}
stream + = " Content-Length: ";
ул. трансляцию += ;
поток + = " \r\n";
//stream + = " соединение: keep-alive\r\n";
поток + = " соединение: закрыть\r\n";
поток + = " \r\n";
ул. трансляцию += _;
обратный поток;

}
пожалуйста, обратите внимание: соединение: keep-alive\r\n";
поток + = " соединение: закрыть\r\n";

Я использовал режим keep_alive, http будет продолжать открывать соединение , сервер будет предполагать, что клиент продолжит отправлять post-запрос, поэтому сервер будет ждать, на самом деле я больше не буду отправлять в сеансе, поэтому сервер закроет соединение, когда истечет время, вот и все :)

Рейтинг:
0

KarstenK

Ваш код выглядит прямолинейным, как и во многих других местах, которые я видел. Влияние размера буфера меньше, как вы думаете. Вы также должны использовать буфер 8k, чтобы получить все данные сразу.

Мой совет заключается в том, что ваш сервер или сеть работают медленно. Взгляните на него. Вам нужно найти узкое место. Попробуйте выполнить локальную выборку на сервере.

Совет 2: Используйте Wireshark для исследования сетевого трафика.


Member 12601798

спасибо Вам заранее , но я нахожу причину, по которой ответ идет так медленно, в лицо, я использую приведенный ниже код c++ для отправки Post-запроса,

строки PostString::prepare_send(константные строки&амп; хозяин, константная строка&амп; путь , константная строка&амп; content_type){
струнный поток;
инт content_length = str_.длина();
//соиь <&ЛТ; "длина содержимого" &ЛТ;&ЛТ; content_length на << епси;
char buffer[20] = { 0 };
num_to_buffer(content_length, buffer, 10);
строка str;
cp_buffer_string(буфер, кв. 20, );
поток + = " пост ";
поток += путь;
stream + = " HTTP / 1.1\r\n";
поток + = " хост: ";
трансляция += хозяин;
поток + = " \r\n";
трансляция += "пользователь-агент: корпорация Mozilla/5.0 (Windows; В У; для NT 5.1; ж-СН; как RV:1.9.2.3) движок Gecko/20100401 для Firefox/3.6.3\р\н";
если("JSON с" == content_type){

stream + = " Content-Type: application / json\r\n";
}еще{
stream + = " Content-Type: application/x-www-form-urlencoded\r\n";
}
stream + = " Content-Length: ";
ул. трансляцию += ;
поток + = " \r\n";
//stream + = " соединение: keep-alive\r\n";
поток + = " соединение: закрыть\r\n";
поток + = " \r\n";
ул. трансляцию += _;
обратный поток;

}
пожалуйста, обратите внимание: соединение: keep-alive\r\n";
поток + = " соединение: закрыть\r\n";

Я использовал режим keep_alive, http будет продолжать открывать соединение , сервер будет предполагать, что клиент продолжит отправлять post-запрос, поэтому сервер будет ждать, на самом деле я больше не буду отправлять в сеансе, поэтому сервер закроет соединение, когда истечет время, вот и все :)