Re[4]: HTTP Winsock
От: my_problem  
Дата: 23.11.11 17:40
Оценка:
Здравствуйте, okman, Вы писали:

O>Здравствуйте, my_problem, Вы писали:


_>>Однако не совсем ясно, если у меня сейчас мульти-поточный accept при каждом новом соединении создаёт поток, в который просто передает сокет, откуда к нему приконнектились в параметр, и, далее, созданный поток уже самостоятельно создает второй сокет для исходящего соединения, ну и соединяется с заданным узлом...


_>>С начала, таких потоков одновременно обычно 5 штук (тестирую с Mozilla FF, предполагаю, что в зависимости от браузера данное поведение будет сильно меняться), про асинхронность не до конца понял... В чём плох подход создавать поток для каждого нового соединения забирая в параметр сокет, и исходящий сокет создавать в потоке?


O>Так тоже можно делать.

O>Но моя статистика показывает, что браузеры очень активно создают и завершают соединения, и даже
O>когда открыто всего несколько вкладок, этих соединений легко может оказаться под сотню.
O>Создавать поток на каждое соединение — слишком дорого, и после определенного порога чем больше
O>потоков, тем хуже производительность.

O>Неужели все "настолько" асинхронно, что в потоке №1 будет запрошено что-то либо

_>>
_>>GET /images/1.jpg HTTP/1.1
_>>

_>>, а ответ от сервера на этот запрос, уже с бинарными данными картинки, будет в потоке №3, например? Мне казалось, что обычно программы ожидают ответа на определенный запрос именно в том сокете, через который они этот запрос отправили (ну при наличии Keep-Alive подобного алгоритма)? И ещё, наверное торможу, но почему же потоки "висят" минуту + перед завершением?

O>Как-то путанно излагаете. Или я неправильно понимаю.

O>В любом случае, Ваша задача — разгрузить главный поток приложения, в котором вызывается accept,
O>от лишней работы и ожиданий, потому что сервер тогда станет недоступным и некоторые типичные
O>операции сломаются. Приняли коннект — сразу отдаем на обработку свободному потоку и быстро
O>возвращаемся к приему следующих соединений.

O>Рабочие потоки должны быть спроектированы так, чтобы они могли передавать данные от клиента (браузера)

O>серверу и в обратном направлении, причем одновременно. Используя синхронные сокеты, этого
O>достичь не получится, потому что поток будет "спать" либо на send, либо на recv, и встречные
O>данные "застопорятся". На первый взгляд кажется, что для HTTP это вроде как и не нужно,
O>так как запросы и ответы чередуются, следуя в строгом порядке друг за другом, но это только на
O>первый взгляд.

O>Именно поэтому я советую использовать асинхронные сокеты и WSASend/WSARecv, ну

O>а координировать их работу не обязательно портом завершения ввода/вывода, есть и другие механизмы.
O>Тогда у Вас получится схема, когда данные смогут беспрепятственно идти в обоих направлениях,
O>не мешая друг другу, а без этого некоторые сайты будут "зависать" на долгое время.

O>Когда я начал заниматься этими вопросами, то первое, что попытался сделать — написать

O>простейший веб-сервер, который бы принимал GET-запросы и отдавал ответы.
O>А потом стал бомбить его множеством одновременных запросов из разных браузеров и под
O>разными версиями Windows — оказалось, что мой сервер не работает так, как надо,
O>иногда повисает по непонятным причинам, иногда не может толком отдать контент, и т.д.
O>Потом, разбирая "по косточкам", открыл для себя много нового.

Спасибо большое ещё раз. Ну чтож, раз проще никак, буду мучать WSASend/WSARecv.

На данный момент бесконечный цикл accept'a выглядит так:


    while(ClientSocket = accept(ListenSocket, (sockaddr *)&client_addr, &client_addr_size))
    {
        if (ClientSocket == INVALID_SOCKET)
        {
#ifdef DEBUG
            sprintf_s(errormsg,"accept failed with error: %d\n", WSAGetLastError());
            Errorlog(errormsg);
#endif
            //TODO - report error
            closesocket(ListenSocket);
            WSACleanup();
            return 1;
        }
        else
        { //Multithread clients accept
            DWORD thID;
            CreateThread(NULL, NULL, HandShake, &ClientSocket, NULL, &thID);
            nClients++;
#ifdef DEBUG
            sprintf(errormsg, "\n[nClients = %d]", nClients);
            Errorlog(errormsg);
#endif
            WaitForSingleObject(0, 50000);
        }
    }


Как я понимаю, это полностью удовлетворяет условия задачи. Асинхронно надо в моём случае переделать HandShake... Этим и займусь.

Ну а функция "рабочего потока" выше постом. Хотя она конечно изменится. Спасибо за помощь.

Если я правильно понимаю, я делаю их не блокируемыми и в цикле проверяю, в каком из них на данный момент времени есть данные (клиент или сервер), и читая с этого сокета — отправляю в "противоположный".
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.