Модераторы: feodorv

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> POST запрос, Отправить POST запрос 
:(
    Опции темы
feodorv
Дата 7.12.2015, 15:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 10
Всего: 45



Цитата(rudolfninja @  7.12.2015,  10:51 Найти цитируемый пост)
Вам нужен весь код или только того участка, где приосходит прием данных?

Хотелось бы весь код, работающий с сокетом smile 


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
rudolfninja
Дата 7.12.2015, 18:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 341
Регистрация: 19.2.2013
Где: г. Минск

Репутация: нет
Всего: 6



Код

// Создаем socket
        cout << "Creating socket... ";
        if ((hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
            throw HeadReqException("could not create socket.");
        cout << "created.\n";

        // Соединяемся с сервером
        cout << "Attempting to connect to " << inet_ntoa(sockAddr.sin_addr)
            << ":" << SERVER_PORT << "... ";
        if (connect(hSocket, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr)) != 0)
            throw HeadReqException("could not connect.");
        cout << "connected.\n";

        cout << "Sending request... ";

        // Отправляем запрос part 1
        if (send(hSocket, HEAD_REQUEST_PART1, sizeof(HEAD_REQUEST_PART1)-1, 0) == SOCKET_ERROR)
            throw HeadReqException("failed to send data.");

        cout << "request sent.\n";

        cout << "Dumping received data...\n\n";
        // Выводим все данные в цикле
        string sresult;
        int iResult = 0;
        u_long buffsize = 1024;
        char* buff = new char[buffsize];
        u_long arg;
        ofstream fout;
        fout.open("D:\\answer.txt");
        do
        {
            ioctlsocket(hSocket, FIONREAD, &arg);
            if (arg == 0)
                break;
            if (arg > buffsize)
                arg = buffsize;
            iResult = recv(hSocket, buff, arg, 0);
            if (iResult > 0)
            for (int i = 0; i < iResult; ++i)
                sresult.append(1, buff[i]);
            fout << sresult;
            sresult.clear();
        } while (iResult > 0);
        fout.close();
    }


Вот код отправки и получения данных. 
Еще заметил такую странность, что сегодня такой запрос не работает =) После
Код

ioctlsocket(hSocket, FIONREAD, &arg);

В arg 0.
Повторяется не стабильно. Где-то через раз.

Это сообщение отредактировал(а) rudolfninja - 7.12.2015, 18:57
PM MAIL Skype   Вверх
feodorv
Дата 7.12.2015, 22:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 10
Всего: 45



Поверхностный осмотр кода привел к таким выводам:
  • Сервер возвращает отнюдь не текст, а заголовки плюс поток байт. Поэтому приёмный файл нужно делать бинарным. От string отказываться, использовать fout.write().
  • Вызов ioctlsocket() может завершиться с ошибкой, этот случай в коде не реализован.
  • Для ожидания данных используется совсем другая схема. ioctlsocket() возвращает число байт, готовых для чтения из буфера приёма, но он может быть ещё пуст на момент проверки (данные не успели дойти, сервер тормозит с отправкой данных и т.д.). В вашем случае разумно использовать вызов select() (например). Кстати, какая у Вас ОС?



--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
rudolfninja
Дата 7.12.2015, 22:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 341
Регистрация: 19.2.2013
Где: г. Минск

Репутация: нет
Всего: 6



feodorv, спасибо, вроде работает.
Гляньте, пожалуйста, код на наличие ошибок\недочетов.
Код

try
    {
        // Ищем имя хоста и заполняем структуру sockaddr_in:
        cout << "Looking up hostname " << pServername << "... ";
        FillSockAddr(&sockAddr, pServername, SERVER_PORT);
        cout << "found.\n";

        // Создаем socket
        cout << "Creating socket... ";
        if ((hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
            throw HeadReqException("could not create socket.");
        cout << "created.\n";

        // Соединяемся с сервером
        cout << "Attempting to connect to " << inet_ntoa(sockAddr.sin_addr)
            << ":" << SERVER_PORT << "... ";
        if (connect(hSocket, reinterpret_cast<sockaddr*>(&sockAddr), sizeof(sockAddr)) != 0)
            throw HeadReqException("could not connect.");
        cout << "connected.\n";

        cout << "Sending request... ";

        // Отправляем запрос part 1
        if (send(hSocket, HEAD_REQUEST_PART1, sizeof(HEAD_REQUEST_PART1)-1, 0) == SOCKET_ERROR)
            throw HeadReqException("failed to send data.");

        cout << "request sent.\n";

        cout << "Dumping received data...\n\n";
        // Выводим все данные в цикле
        string sresult;
        timeval tv;  
        tv.tv_sec = 1; // устанавливаем время ожидания в 1 сек.
        tv.tv_usec = 0;
        int iResult = 0;
        fd_set rfds;        // проверяем наличие данных в сокете, установив файловый дескриптор сокета в множестве "на чтение"
        FD_ZERO(&rfds);    // очищаем множество "на чтение"
        FD_SET(hSocket, &rfds);    // помещаем дескриптор сокета в множество "на чтение"
        u_long buffsize = 1024;
        char* buff = new char[buffsize];
        u_long arg;
        ofstream fout;
        fout.open("D:\\answer.out", std::ios::binary);
        do
        {
            if (select(0, &rfds, 0, 0, &tv) > 0)
            {
                if (ioctlsocket(hSocket, FIONREAD, &arg) != SOCKET_ERROR)
                {

                    if (arg == 0)
                        break;
                    if (arg > buffsize)
                        arg = buffsize;
                    iResult = recv(hSocket, buff, arg, 0);
                    if (iResult > 0)
                        fout.write(buff, arg);
                    sresult.clear();
                }
            }
        } while (iResult > 0);
        fout.close();
        delete buff;
    }

PM MAIL Skype   Вверх
feodorv
Дата 8.12.2015, 09:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 10
Всего: 45



Цитата(rudolfninja @  7.12.2015,  22:44 Найти цитируемый пост)
Гляньте, пожалуйста, код на наличие ошибок\недочетов.
  • Сокет не закрывается.
  • Одной секунды таймаута явно мало, дайте хотя бы 30.
  • Вызов ioctlsocket(FIONREAD) вообще не нужен. Нужен recv и анализ возвращаемого значения.
  • Не понял, где фиксируется успех-неуспех (если неуспех, то файл надо даже удалить, если он создан).
  • Запрос не виден. Для Вас существенно будет, чтобы сервер закрывал соединение по окончании передачи страницы (поэтому нужен Connection как "close").
  • iResult - это число прочтенных из сокета байт, но записываете в файл Вы почему-то arg байт (могут не совпадать).
  • На всякий случай я бы сокету выставил SO_OOBINLINE.
  • Зачем для размера буфера тип u_long? Чем int не угодил?
  • Болтается ненужная переменная sresult.
Я бы сделал как бы так:
Код

bool success = true;
...
do
{
   int bytes;
   FD_ZERO( &rfds );
   FD_SET( hSocket, &rfds);
   int rv = select( 0, &rfds, 0, 0, &tv);

   if( rv == SOCKET_ERROR )
   {
      if( WSAGetLastError() == WSAEINTR ) continue;
      success = false; // ошибка вызова select()
   }
   else if( rv == 0 )
   {
      success = false; // таймаут
   }
   else
   {
      do
      {
          bytes = recv( hSocket, buff, buffsize, 0);
      } while( bytes == SOCKET_ERROR && WSAGetLastError() == WSAEINTR );

      if( bytes == SOCKET_ERROR )
      {
         success = false; // ошибка вызова recv
      }
      else if( bytes == 0 )
      {
         break; // сервер закрыл соединение, страница принята до конца
      }
      else
         fout.write( buff, bytes);
   }
} while( success );



Это сообщение отредактировал(а) feodorv - 8.12.2015, 09:30


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
feodorv
Дата 8.12.2015, 09:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 10
Всего: 45



Если грузится библиотека WinSock второй версии, то от проверок EINTR можно отказаться.

Если таймаут не важен (но при этом сервер заставляем закрывать соединение), то всё ещё проще (можно и от select() отказаться):
Код

do
{
   int bytes = recv( hSocket, buff, buffsize, 0);

   if( bytes == SOCKET_ERROR )
   {
      success = false; // ошибка вызова recv
   }
   else if( bytes == 0 )
   {
      break; // сервер закрыл соединение, страница принята до конца
   }
   else
      fout.write( buff, bytes);
} while( success );


Добавлено через 14 минут и 15 секунд
А как Вы будете высвобождать память, выделенную под buff, если после возникнет исключение? Вообще, здесь смысла в выделении памяти мало, можно же просто
Код
char buff[1024];



Это сообщение отредактировал(а) feodorv - 8.12.2015, 09:30


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
rudolfninja
Дата 8.12.2015, 09:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 341
Регистрация: 19.2.2013
Где: г. Минск

Репутация: нет
Всего: 6



Спасибо за замечания. Исправлю.
Помечаю тему как решенную.
PM MAIL Skype   Вверх
Google
  Дата 23.5.2019, 05:43 (ссылка)  





  Вверх
Ответ в темуСоздание новой темы Создание опроса
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Сети | Следующая тема »


 




[ Время генерации скрипта: 0.1274 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.