[WinSock] Зависает при использование прокси

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by Kandi, 29 Nov 2012.

  1. Kandi

    Kandi Member

    Joined:
    18 Nov 2009
    Messages:
    344
    Likes Received:
    17
    Reputations:
    0
    Такая вот беда, при использование HTTP прокси, зависает на recv(); В чем может быть проблема? Возможно прокси попадаются HTTPS / SOCKS - ну это я думаю роли особой не играет в данном случае!?


    Из 1к прокси осталось 4шт. и висели они долго и счастливо))) Может, как то можно принудительно оборвать коннект?
    Code:
                      phe := gethostbyname(PAnsiChar(IP));
                      if phe = nil then Exit;
                      ZeroMemory(@TAddr, SizeOf(TAddr));
                      TAddr.sin_family := AF_INET;
                      TAddr.sin_addr := PInAddr(phe^.h_addr^)^;
                      TAddr.sin_port := htons(Port);
                      Arg := 1;
                      ioctlsocket(TCPSocket, FIONBIO, Arg);
                      if Connect(TCPSocket, TAddr, SizeOf(TSockAddr)) = SOCKET_ERROR then
                        begin
                          if WSAGetLastError = WSAEWOULDBLOCK then // проверяем что сокет перешел в неблокируемый режим
                            begin
                              FD_ZERO(FDS);
                              FD_SET(TCPSocket, FDS);
                              TimeOut.tv_sec := ATimeOut;
                              TimeOut.tv_usec := 0;
                              RC := select(0, nil, @FDS, nil, @TimeOut); // ожидаем
                            end;
                        end;
                      Arg := 0;
                      ioctlsocket(TCPSocket, FIONBIO, Arg);
                      // Проверяем ответ от прокси
                      if RC = 0 then
                        begin
                          InterlockedIncrement(CountBad);
                        end
                        else
                        begin
                          SendBuffer := AnsiString(AMethod) + ' / HTTP/1.1' + #13#10 + 'Host: ' + AnsiString(AHost) + #13#10 + AnsiString(AHeaders);
                          if AMethod = 'POST' then
                            SendBuffer := SendBuffer + #13#10 +
                            'Content-Type: application/x-www-form-urlencoded' + #13#10 +
                            'Content-Length: ' + AnsiString(IntToStr(Length(AData))) + #13#10 + #13#10 + AnsiString(AData)
                          else
                            SendBuffer := SendBuffer + #13#10#13#10;
                              
                          // Отправляем данные на сервер
                          send(TCPSocket, SendBuffer[1], Length(SendBuffer), 0);
    
                          // Читаем ответ от сервера
                          FillChar(RecvBuff, 1024, 0);
                          recv(TCPSocket, RecvBuff[0], SizeOf(RecvBuff), 0);
    
    P.S. Где можно спалить тему, по реализации HTTPS прокси на сокетах? Заранее мерси. :)
     
    #1 Kandi, 29 Nov 2012
    Last edited: 29 Nov 2012
  2. Jingo Bo

    Jingo Bo Member

    Joined:
    25 Oct 2009
    Messages:
    368
    Likes Received:
    51
    Reputations:
    7
    Не понимаю, какой смысл сначала переводить сокет в неблокирующий режим, потом обратно. Раз необходим неблокирующий режим, значит переводим его и обратно только перед удалением. Проверять после коннекта тоже нет смысла в каком он режиме, оно проверяется вообще после ioctlsocket, а не после connect.

    Далее, recv естественно будет останавливать работу потока пока не получит хотя бы 1 байт или пока не уничтожится сокет. Такая шляпа из-за того, что у тебя сокет один фик остается в блокирующем режиме, в таком случае можно создать левый поток, который удалит сокет через N милисекунд и recv тут же возвратит 0, можно установить сокету какую то опцию, я не помню какую. Или работать в неблокирующем режиме, но это уже сложнее, что бы сделать "как надо" тут нужно расписывать много, в инете полно инфы.

    Забудь.
     
  3. muip

    muip New Member

    Joined:
    1 Sep 2011
    Messages:
    45
    Likes Received:
    4
    Reputations:
    0
    Используй старую добрую обертку для рецва, которая препятствует зависанию потока при работе на винсоках:

    Code:
    function recvdata(sock:TSocket):string;
    var
       tv : timeval;
       fds : TFDSet;
       buf : array [1..4096] of char;
       res : string;
       r : integer;
    begin
       r:=1;
       FD_ZERO(fds);
       FD_SET(sock, fds);
       tv.tv_sec := 5;
       tv.tv_usec := 0;
       res:='';
    
       while (r>0) do
       begin
          if select(0, @fds, nil, nil, @tv)<=0 then break;
          r := recv(sock, buf, 4096, 0);
          res:=res+copy(buf,1,r);
       end;
       result:=res;
    end;
    
    
    Также обрабатывай еще сам коннект сока.
     
  4. Jingo Bo

    Jingo Bo Member

    Joined:
    25 Oct 2009
    Messages:
    368
    Likes Received:
    51
    Reputations:
    7
    не советую использовать код, приведенный выше, он тебе не пригодится в данной зача, тем более он не корректный.
     
  5. Kandi

    Kandi Member

    Joined:
    18 Nov 2009
    Messages:
    344
    Likes Received:
    17
    Reputations:
    0
    Античат, только критика - только HARDCORE. Я всё понимаю. Ну показали бы свой пример, либо подскажите где можно порыться и увидеть более корректный код?!

    P.S. Меньше слов, дешевле телеграмма. Как говорится.
     
  6. Gar|k

    Gar|k Moderator

    Joined:
    20 Mar 2009
    Messages:
    1,166
    Likes Received:
    266
    Reputations:
    82
    Книги надо читать молодой человек. Йона Снейдера с его TCP/IP очень вам рекомендую-с
     
    _________________________