Локальный http прокси сервер

Тема в разделе "WASM.WIN32", создана пользователем SlyBit, 20 июн 2009.

  1. SlyBit

    SlyBit New Member

    Публикаций:
    0
    Регистрация:
    4 июл 2008
    Сообщения:
    43
    Всем привет.

    Пишу локальный http прокси сервер для фильтрации трафика по контенту. Интересует такой вопрос: какая величина таймаута чтения ( setsockopt(... SO_RCVTIMEO ...) ) и размер читаемого блока будут наиболее оптимальны в плане скорости получения данных? В данный момент наблюдается довольно продолжительная задержка после получения последнего блока данных от хоста.

    Код (Text):
    1. #include <windows.h>
    2.  
    3. #define BIND_PORT 8080
    4. #define HTTP_PORT 80
    5.  
    6. // ...
    7.  
    8. ULONG ProcessClientThread(PVOID pParam)
    9. {
    10.     SOCKET MessageSocket = *(SOCKET*)pParam, ConnectSocket;
    11.     struct sockaddr_in clientService;
    12.     PCHAR pBuffer = NULL;
    13.     ULONG dwRecvRet = 0,
    14.         dwBufferSize = 15000, i = 0, dwTimeOut = 100;
    15.     CHAR szHost[100] = "\0",
    16.         szPath[250] = "\0",
    17.         szDestIp[17] = "\0";
    18.    
    19.     pBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferSize);
    20.     if(pBuffer)
    21.     {
    22.         //
    23.         // Receive data from the application
    24.         //
    25.        
    26.         setsockopt(MessageSocket, SOL_SOCKET, SO_RCVTIMEO, &dwTimeOut, 4);
    27.  
    28.         while(dwRecvRet = recv(MessageSocket, pBuffer + i, 100, 0))
    29.         {                        
    30.             if(dwRecvRet == SOCKET_ERROR || dwRecvRet == WSAECONNRESET)
    31.                 break;
    32.            
    33.             i += dwRecvRet;
    34.            
    35.             if(i + 100 > dwBufferSize)
    36.             {
    37.                 dwBufferSize *= 2;
    38.                 pBuffer = HeapReAlloc(GetProcessHeap(), 0, pBuffer, dwBufferSize);
    39.                 if(!pBuffer)
    40.                     break;
    41.             }
    42.         }
    43.      
    44.         while(i)
    45.         {
    46.             if(!GetHttpHost(pBuffer, i, szHost, 100, szPath, 250))
    47.                 break;
    48.            
    49.             if(!GetIpByHostName(szHost, szDestIp, 17))
    50.                 break;
    51.  
    52.             //
    53.             // Send data to the host
    54.             //
    55.  
    56.             ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    57.             if(ConnectSocket == INVALID_SOCKET)
    58.                 break;
    59.  
    60.             clientService.sin_family = AF_INET;
    61.             clientService.sin_port = htons(HTTP_PORT);
    62.             clientService.sin_addr.s_addr = inet_addr(szDestIp);
    63.  
    64.             if(SOCKET_ERROR == connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService)))
    65.                 break;
    66.  
    67.             if(SOCKET_ERROR == send(ConnectSocket, pBuffer, i, 0))
    68.                 break;
    69.            
    70.             //
    71.             // Receive data from the host
    72.             //
    73.  
    74.             memset(pBuffer, 0, dwBufferSize);
    75.             i = 0;
    76.            
    77.             setsockopt(ConnectSocket, SOL_SOCKET, SO_RCVTIMEO, &dwTimeOut, 4);
    78.  
    79.             while(dwRecvRet = recv(ConnectSocket, pBuffer + i, 100, 0))
    80.             {                        
    81.                 if(dwRecvRet == SOCKET_ERROR || dwRecvRet == WSAECONNRESET)
    82.                     break;
    83.                
    84.                 i += dwRecvRet;
    85.                
    86.                 if(i + 100 > dwBufferSize)
    87.                 {
    88.                     dwBufferSize *= 2;
    89.                     pBuffer = HeapReAlloc(GetProcessHeap(), 0, pBuffer, dwBufferSize);
    90.                     if(!pBuffer)
    91.                         break;
    92.                 }
    93.             }    
    94.            
    95.             //
    96.             // Content filter
    97.             //
    98.            
    99.             // ...
    100.            
    101.             //
    102.             // Send data to the application
    103.             //
    104.  
    105.             send(MessageSocket, pBuffer, i, 0);
    106.            
    107.             break;
    108.         }
    109.  
    110.         if(ConnectSocket)
    111.             closesocket(ConnectSocket);
    112.        
    113.         if(pBuffer)
    114.             HeapFree(GetProcessHeap(), 0, pBuffer);
    115.     }
    116.    
    117.     closesocket(MessageSocket);
    118.  
    119.     return 0;
    120. }
    121.  
    122. ULONG AcceptConnectionsThread(PVOID pParam)
    123. {
    124.     HANDLE hThread = NULL;
    125.     SOCKET ConnectSocket, MessageSocket;
    126.     struct sockaddr_in serverService;
    127.     struct sockaddr serverServiceFrom;
    128.     int dwServiceFromLen = sizeof(struct sockaddr);
    129.  
    130.     ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    131.     if(ConnectSocket == INVALID_SOCKET)
    132.     {
    133.         return -1;
    134.     }
    135.  
    136.     memset(&serverService, 0, sizeof(struct sockaddr_in));
    137.     serverService.sin_family = AF_INET;
    138.     serverService.sin_addr.s_addr = htonl(INADDR_ANY);
    139.     serverService.sin_port = htons(BIND_PORT);
    140.     if(SOCKET_ERROR == bind(ConnectSocket, (struct sockaddr*)&serverService, sizeof(struct sockaddr_in)))
    141.     {
    142.         closesocket(ConnectSocket);
    143.         return -1;
    144.     }
    145.  
    146.     if(SOCKET_ERROR == listen(ConnectSocket, SOMAXCONN))
    147.     {
    148.         closesocket(ConnectSocket);
    149.         return -1;
    150.     }
    151.  
    152.     while(1)
    153.     {
    154.         MessageSocket = accept(ConnectSocket, &serverServiceFrom, &dwServiceFromLen);
    155.         if(MessageSocket != INVALID_SOCKET)
    156.         {
    157.             hThread = CreateThread(NULL, 0, ProcessClientThread, &MessageSocket, 0, NULL);
    158.             if(hThread)
    159.             {
    160.                 CloseHandle(hThread);
    161.             }            
    162.         }
    163.     }    
    164.    
    165.     closesocket(ConnectSocket);
    166.  
    167.     return 0;
    168. }
    169.  
    170. VOID Entry()
    171. {
    172.     HANDLE hThread = NULL;
    173.     struct WSAData WsaData;
    174.  
    175.     if(NO_ERROR != WSAStartup(MAKEWORD(2, 2), &WsaData))
    176.     {
    177.         ExitProcess(0);
    178.     }    
    179.    
    180.     hThread = CreateThread(NULL, 0, AcceptConnectionsThread, NULL, 0, NULL);
    181.     if(hThread)
    182.     {
    183.         WaitForSingleObject(hThread, INFINITE);
    184.         CloseHandle(hThread);
    185.     }
    186.    
    187.     WSACleanup();
    188.  
    189.     ExitProcess(0);
    190. }
     
  2. djmans

    djmans New Member

    Публикаций:
    0
    Регистрация:
    27 дек 2006
    Сообщения:
    312
    Http-прокси доволно геморный протокол. Таймауты и размеры блоков не как не повлияют на скорость впринипе. Таймауты что-то решает если сервер не отвечает, если там не http-сервер и т.д. А задержка о которой Вы говрите вероятно объясняется, тем что при чтении последнего блока, функция recv ожидает получения всегда 100 байт, а вить в последенм блоке может быть 99 байт. Вот и задержка идет, что он ждет 1 байт еще. Выход - изучить протоколь http-proxy, если память не подводит нужно анализировать ответ сервера, смотреть как именно предеается содержимое и сколько содержит байт.
     
  3. djmans

    djmans New Member

    Публикаций:
    0
    Регистрация:
    27 дек 2006
    Сообщения:
    312
    вообщем socks5 рулит)
     
  4. ohne

    ohne New Member

    Публикаций:
    0
    Регистрация:
    28 фев 2009
    Сообщения:
    431
    djmans
     
  5. wertyman

    wertyman Member

    Публикаций:
    0
    Регистрация:
    13 дек 2006
    Сообщения:
    74
    Просто само по себе подключение остается висеть, после того как браузер отправил данные и сервер так же может не закрывать соединение, для повторных запросов. См. значение заголовка Connection. Не нужно ждать пока подключение отвалится, нужно сразу как принял, отправлять дальше, а там они разберутся :)
     
  6. djmans

    djmans New Member

    Публикаций:
    0
    Регистрация:
    27 дек 2006
    Сообщения:
    312
    Return Value
    If no error occurs, recv returns the number of bytes received

    это понятно, но у вас сокеты в блокировочном режиме, и он будет пытаться ждать поулчения всех 100 байтов. даже если вы сделаете не блокируемые, это будет не правильно. нужно анализировать http-заголовки возращаемые сервером.
     
  7. asd

    asd New Member

    Публикаций:
    0
    Регистрация:
    12 мар 2005
    Сообщения:
    952
    Адрес:
    Russia
    С чего это вдруг?
     
  8. Aspire

    Aspire New Member

    Публикаций:
    0
    Регистрация:
    19 май 2007
    Сообщения:
    1.028
    Ключевая фраза здесь -
    Тут djmans, видимо, немножко путает. Задержка как раз происходит тогда, когда в заголовке указано больше байт чем передано и это браузер будет некторое время тупить, прежде чем отобразит страницу... Я давно с этим разбирался, но одно могу сказать точно - recv здесь не-причем.
     
  9. SlyBit

    SlyBit New Member

    Публикаций:
    0
    Регистрация:
    4 июл 2008
    Сообщения:
    43
    Всем спасибо. Решение проблемы сводится к анализу заголовка ответа http протокола и принятию решения о прекращении чтения на основе этих данных.

    Будут ждать данные до истечения времени таймаута (SO_RCVTIMEO).
     
  10. asd

    asd New Member

    Публикаций:
    0
    Регистрация:
    12 мар 2005
    Сообщения:
    952
    Адрес:
    Russia
    Вобще когда-то писал что-то подобное. Такая проблема(задержка после прихода последнего пакета) наблюдалась при наличии в ответе параметра keep alive(или как-то так.) там за ним ещё размер этой задержки в секундах стоял.
     
  11. Aspire

    Aspire New Member

    Публикаций:
    0
    Регистрация:
    19 май 2007
    Сообщения:
    1.028
    asd Такого не должно быть, ведь это просто время до разрыва соеденения сервером. Такая шляпа означает, что где-то в коде зарыта ашипка.
     
  12. djmans

    djmans New Member

    Публикаций:
    0
    Регистрация:
    27 дек 2006
    Сообщения:
    312
    Aspire не чего не путаю.
    >заголовке указано больше байт чем передано
    это говрит о том что сервер работает с ошибки. ))
    кол. переданых байт вообще может быть не указано при кодировке кажется chunk(chuked, не помню как правильно называется)

    SlyBit да все верно. Такчто нужно изучать ответ сервера. и все методы получения ответа сервера.
     
  13. slavanap

    slavanap Вячеслав

    Публикаций:
    0
    Регистрация:
    10 сен 2008
    Сообщения:
    300
    Адрес:
    Смоленск, Россия
    Извините, а можете дать ссылку на описание протокола http-proxy. Желательно, чтоб понаглядней: что отправилось, а что придёт.