Всем привет. Пишу локальный http прокси сервер для фильтрации трафика по контенту. Интересует такой вопрос: какая величина таймаута чтения ( setsockopt(... SO_RCVTIMEO ...) ) и размер читаемого блока будут наиболее оптимальны в плане скорости получения данных? В данный момент наблюдается довольно продолжительная задержка после получения последнего блока данных от хоста. Код (Text): #include <windows.h> #define BIND_PORT 8080 #define HTTP_PORT 80 // ... ULONG ProcessClientThread(PVOID pParam) { SOCKET MessageSocket = *(SOCKET*)pParam, ConnectSocket; struct sockaddr_in clientService; PCHAR pBuffer = NULL; ULONG dwRecvRet = 0, dwBufferSize = 15000, i = 0, dwTimeOut = 100; CHAR szHost[100] = "\0", szPath[250] = "\0", szDestIp[17] = "\0"; pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize); if(pBuffer) { // // Receive data from the application // setsockopt(MessageSocket, SOL_SOCKET, SO_RCVTIMEO, &dwTimeOut, 4); while(dwRecvRet = recv(MessageSocket, pBuffer + i, 100, 0)) { if(dwRecvRet == SOCKET_ERROR || dwRecvRet == WSAECONNRESET) break; i += dwRecvRet; if(i + 100 > dwBufferSize) { dwBufferSize *= 2; pBuffer = HeapReAlloc(GetProcessHeap(), 0, pBuffer, dwBufferSize); if(!pBuffer) break; } } while(i) { if(!GetHttpHost(pBuffer, i, szHost, 100, szPath, 250)) break; if(!GetIpByHostName(szHost, szDestIp, 17)) break; // // Send data to the host // ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(ConnectSocket == INVALID_SOCKET) break; clientService.sin_family = AF_INET; clientService.sin_port = htons(HTTP_PORT); clientService.sin_addr.s_addr = inet_addr(szDestIp); if(SOCKET_ERROR == connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService))) break; if(SOCKET_ERROR == send(ConnectSocket, pBuffer, i, 0)) break; // // Receive data from the host // memset(pBuffer, 0, dwBufferSize); i = 0; setsockopt(ConnectSocket, SOL_SOCKET, SO_RCVTIMEO, &dwTimeOut, 4); while(dwRecvRet = recv(ConnectSocket, pBuffer + i, 100, 0)) { if(dwRecvRet == SOCKET_ERROR || dwRecvRet == WSAECONNRESET) break; i += dwRecvRet; if(i + 100 > dwBufferSize) { dwBufferSize *= 2; pBuffer = HeapReAlloc(GetProcessHeap(), 0, pBuffer, dwBufferSize); if(!pBuffer) break; } } // // Content filter // // ... // // Send data to the application // send(MessageSocket, pBuffer, i, 0); break; } if(ConnectSocket) closesocket(ConnectSocket); if(pBuffer) HeapFree(GetProcessHeap(), 0, pBuffer); } closesocket(MessageSocket); return 0; } ULONG AcceptConnectionsThread(PVOID pParam) { HANDLE hThread = NULL; SOCKET ConnectSocket, MessageSocket; struct sockaddr_in serverService; struct sockaddr serverServiceFrom; int dwServiceFromLen = sizeof(struct sockaddr); ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(ConnectSocket == INVALID_SOCKET) { return -1; } memset(&serverService, 0, sizeof(struct sockaddr_in)); serverService.sin_family = AF_INET; serverService.sin_addr.s_addr = htonl(INADDR_ANY); serverService.sin_port = htons(BIND_PORT); if(SOCKET_ERROR == bind(ConnectSocket, (struct sockaddr*)&serverService, sizeof(struct sockaddr_in))) { closesocket(ConnectSocket); return -1; } if(SOCKET_ERROR == listen(ConnectSocket, SOMAXCONN)) { closesocket(ConnectSocket); return -1; } while(1) { MessageSocket = accept(ConnectSocket, &serverServiceFrom, &dwServiceFromLen); if(MessageSocket != INVALID_SOCKET) { hThread = CreateThread(NULL, 0, ProcessClientThread, &MessageSocket, 0, NULL); if(hThread) { CloseHandle(hThread); } } } closesocket(ConnectSocket); return 0; } VOID Entry() { HANDLE hThread = NULL; struct WSAData WsaData; if(NO_ERROR != WSAStartup(MAKEWORD(2, 2), &WsaData)) { ExitProcess(0); } hThread = CreateThread(NULL, 0, AcceptConnectionsThread, NULL, 0, NULL); if(hThread) { WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); } WSACleanup(); ExitProcess(0); }
Http-прокси доволно геморный протокол. Таймауты и размеры блоков не как не повлияют на скорость впринипе. Таймауты что-то решает если сервер не отвечает, если там не http-сервер и т.д. А задержка о которой Вы говрите вероятно объясняется, тем что при чтении последнего блока, функция recv ожидает получения всегда 100 байт, а вить в последенм блоке может быть 99 байт. Вот и задержка идет, что он ждет 1 байт еще. Выход - изучить протоколь http-proxy, если память не подводит нужно анализировать ответ сервера, смотреть как именно предеается содержимое и сколько содержит байт.
Просто само по себе подключение остается висеть, после того как браузер отправил данные и сервер так же может не закрывать соединение, для повторных запросов. См. значение заголовка Connection. Не нужно ждать пока подключение отвалится, нужно сразу как принял, отправлять дальше, а там они разберутся
Return Value If no error occurs, recv returns the number of bytes received это понятно, но у вас сокеты в блокировочном режиме, и он будет пытаться ждать поулчения всех 100 байтов. даже если вы сделаете не блокируемые, это будет не правильно. нужно анализировать http-заголовки возращаемые сервером.
Ключевая фраза здесь - Тут djmans, видимо, немножко путает. Задержка как раз происходит тогда, когда в заголовке указано больше байт чем передано и это браузер будет некторое время тупить, прежде чем отобразит страницу... Я давно с этим разбирался, но одно могу сказать точно - recv здесь не-причем.
Всем спасибо. Решение проблемы сводится к анализу заголовка ответа http протокола и принятию решения о прекращении чтения на основе этих данных. Будут ждать данные до истечения времени таймаута (SO_RCVTIMEO).
Вобще когда-то писал что-то подобное. Такая проблема(задержка после прихода последнего пакета) наблюдалась при наличии в ответе параметра keep alive(или как-то так.) там за ним ещё размер этой задержки в секундах стоял.
asd Такого не должно быть, ведь это просто время до разрыва соеденения сервером. Такая шляпа означает, что где-то в коде зарыта ашипка.
Aspire не чего не путаю. >заголовке указано больше байт чем передано это говрит о том что сервер работает с ошибки. )) кол. переданых байт вообще может быть не указано при кодировке кажется chunk(chuked, не помню как правильно называется) SlyBit да все верно. Такчто нужно изучать ответ сервера. и все методы получения ответа сервера.
Извините, а можете дать ссылку на описание протокола http-proxy. Желательно, чтоб понаглядней: что отправилось, а что придёт.