Причина зависания сокета на send()?

277
03 марта 2017, 01:57

Приложение работает с тремя сокетами, отправляющими данные на один php-скрипт HTTP-сервера:

  1. управляющий сокет - постит присутствие клиента, получает ответы с запросами на активацию/деактивацию остальных двух сокетов. Есть команды send и recv

  2. сокет вебкамеры - стримит кадры с вебки по запросу. Только send

  3. сокет рабочего стола - стримит скриншоты по запросу. Только send

С 1-м проблем нет вообще - если не отправил или не получил - без каких либо ожиданий пересоздаёт подключение и работает дальше. Проблема со 2-м:

DWORD WINAPI NetExCamera(LPVOID){
    unsigned short StreamRate = 50;
    unsigned int OperationStartTime;
    string Header = "POST " + STREAM_URI + " HTTP/1.1\r\nHost: " + STREAM_Host + /*другие параметры*/"\r\nContent-Type: image/jpeg\r\nContent-Transfer-Encoding: binary\r\nContent-Length: ";
    CAMERA.Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (connect(CAMERA.Socket, (SOCKADDR*)(&Target), sizeof(Target)) == 0){
        cout << "Camera socket connected!\n";
    }
    while(CAMERA.Stream){
        OperationStartTime = GetTickCount();
        CameraFrameSize = WebCam->GetFrameSize();
        CameraFrameBuffer = (unsigned char *)realloc(CameraFrameBuffer, CameraFrameSize);
        compress_image_to_jpeg_file_in_memory(CameraFrameBuffer, CameraFrameSize, RES_X ,RES_Y, 3, WebCam->CaptureFrame(), CameraCompressor);
        CameraFrame = string(reinterpret_cast<char*>(CameraFrameBuffer), CameraFrameSize);
        stringstream SendBuffer;
        SendBuffer << Header << CameraFrame.size() << "\r\n\r\n" << CameraFrame;
        // Sending data...
        cout << "Sending data...\n";
        if (send(CAMERA.Socket, &SendBuffer.str()[0], SendBuffer.str().size(), 0) < 0){
            cout << "Camera socket send error: " << WSAGetLastError() << endl;
            CameraFrame = "";
            closesocket(CAMERA.Socket);
            CAMERA.Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
            if (connect(CAMERA.Socket, (SOCKADDR*)(&Target), sizeof(Target)) == 0){
                cout << "Camera socket connected!\n";
            }
        }
        cout << "Send OK!\n";
        while(OperationStartTime + StreamRate > GetTickCount()){
            if (!CAMERA.Stream){break;}
            Sleep(1);
        }
    }
    closesocket(CAMERA.Socket);
    cout << "Camera socket disconnected!\n";
    return 0;
}

Как видно из кода, сокет работает в своём потоке, более того send вроде по умолчанию не блокирующий, но в один момент, спустя 8-11 секунд с начала передачи данных, консольный вывод замирает на строчке cout << "Sending data...\n";, потом секунд через 15-20 "оттаивает", естественно сервер его уже откинул (на apache KeepAliveTimeout 5), и после этой задержки уже выходит cout << "Camera socket send error: " << WSAGetLastError() << endl; с кодом ошибки WSA 10054.

Такое ощущение, что у send есть какой-то невидимый буфер, который переполняется и отправка замирает. Размеры кадров с камеры 6-10 кб. Третий сокет работает по той же схеме, только частота у него не 20 кадров в секунду, а 2 - с ним никаких зависаний не происходит.

Проблема по какой-то причине не возникает на Windows 8.1 x64 на localhost-е, а на 7-ке вот такая беда.

В чём реально может быть причина и как это исправить?

Answer 1

В ответ на каждый HTTP POST запрос, которым вы шлете кадр с камеры, сервер шлет ответ.

Эти ответы надо читать (они переполняют буфер и http сервер, подвисая на очередном send, не в состоянии прочесть ваш очередной запрос).

Вот так обе стороны и висят, каждая на своем send.

Кроме того, возможна ситуация, когда ваш send отошлет не все данные. Поэтому его нужно выполнять в цикле, пока все SendBuffer.str().size() байт не будут отосланы.

READ ALSO
Вопрос по массивам

Вопрос по массивам

Есть структура (dadaInt), которая содержит ссылку на массив чисел и размер

246
C++ mfc как записать word документ?

C++ mfc как записать word документ?

Есть MFC проект на C++, и word 2007, надо сгенерировать новый word документ без сторонних библиотек, каким образом можно это сделать ?

237
Изменить позицию QHBoxLayout Qt

Изменить позицию QHBoxLayout Qt

У меня на QMainWindow находятся QGraphicsView и QHBoxLayoutНеобходимо, чтобы при расширении окна, QHBoxLayout отъезжал вправо, а QGraphicsView оставался на месте

325
Спецификатор noexcept

Спецификатор noexcept

noexcept надо тоже писать в определении?

228