Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Работа с сетью в Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 08.07.2017, 17:51   #1
GreenWizard
мальчик-помогай =)
Форумчанин
 
Регистрация: 16.09.2010
Сообщений: 522
По умолчанию Indy, Synapse или что-то другое?

Доброе время суток!

Есть среднего размера проект, что-то типа граббера ВК, и в нём используется сейчас Indy. Настроено практически всё что можно (таймауты, в частности), но иногда запрос намертво виснет на неопределённое время (счёт на часы идёт).

Гуглил я эту проблему не один десяток раз (2 месяца веду проект и проблема периодически "всплывала" в списке задач, но потом откладывалась или же считалась решённой) и там пишут, мол, это проблема winsocks.dll. Решений тут два:
1) переходить с Indy на тот же Synapse и т. п... тут мне интересен опыт форумчан, стоит ли оно того, поддерживает ли ssl и т.д.
2) создавать свой поток, который и будет отслеживать и "прибивать" зависшие соединения.... очень не охота так делать т. к. совсем не факт, что можно нормально прервать работу winsocks и что оно не породит ещё кучу багов... опять же, интересен опыт форумчан.

P. s. в этот раз проблема, судя по всему, связана с прокси, он перестаёт отвечать, но это не отменяет проблему с нерабочими таймаутами... stacktrace рабочего потока почему-то содержит только:
Код:
:7c90e526 ntdll.KiIntSystemCall + 0x6
:7c90df5a ntdll.ZwWaitForSingleObject + 0xc
:71a357c9 ; C:\WINDOWS\system32\mswsock.dll
:71a94d16 ws2_32.WSARecv + 0x61
:71ab2ea3 WSOCK32.recv + 0x33
:110433b7 libeay32.BIO_sock_should_retry + 0x57
GreenWizard вне форума Ответить с цитированием
Старый 08.07.2017, 17:57   #2
Aliens_wolfs
Форумчанин
 
Регистрация: 16.12.2009
Сообщений: 902
По умолчанию

Если вы работаете по HTTP то попробуйте использовать WinInit работает без индейских компонентов. Я тоже в них замечал иногда проблему связанную с winsocks.dll

Последний раз редактировалось Aliens_wolfs; 08.07.2017 в 18:03.
Aliens_wolfs вне форума Ответить с цитированием
Старый 08.07.2017, 18:11   #3
GreenWizard
мальчик-помогай =)
Форумчанин
 
Регистрация: 16.09.2010
Сообщений: 522
По умолчанию

Aliens_wolfs, а как там дела с httpS? на msdn пишут якобы там только два флага меняются, но чую они лукавят + мне бы ещё и прокси поддерживать.... боюсь угробить кучу времени на написание своей обёртки над WinInet
GreenWizard вне форума Ответить с цитированием
Старый 08.07.2017, 19:01   #4
Aliens_wolfs
Форумчанин
 
Регистрация: 16.12.2009
Сообщений: 902
По умолчанию

Вот код в WinInet
Код:
uses
WinInet, ............;

//Функция запроса WinInit Get и Post
function GetPostSite(Method, URLRes: String; SendHeader: string=''; SendStream: TStream=nil): string;
const
 Accept = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' + sLineBreak;
 ProxyConnection = 'Proxy-Connection: Keep-Alive' + sLineBreak;
 LNG = 'Accept-Language: ru' + sLineBreak;
 AGENT = 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '+
 'Chrome/56.0.2924.87 Safari/537.36 OPR/43.0.2442.1144 (Edition Yx)' + sLineBreak;
var
Host, URL, URL_Base, URL_Page, s: String;
hInet, hCon, hReq: Pointer;
  Status, StatusSize, Index, Port: DWORD;
  bytes, b, posi: Cardinal;
  ResponseString: AnsiString;
  SRequest: String;
begin

  URL:= URLRes;
  if pos('http://', URL) <> 0 then
  Port:= 80
  else
  if pos('https://', URL) <> 0 then
  Port:= 443;

  B:= pos('://', URL);
  if b > 0 then
  delete(URL, 1, B + 2);

  B:= pos('/', URL);
  if b > 0 then
  URL_Base:= copy(URL, 1, b - 1)
  else
  URL_Base:= URL;

  B:= pos(':', URL_Base);
  if  b > 0 then
  begin
  Port:= StrToInt(Copy(URL_Base, b + 1, MaxInt));
  delete(URL_Base, b, maxint);
  end;

  b:= pos('/', URL);
  if b <> 0 then
  URL_Page:= copy(URL, b, maxint)
  else
  URL_Page:= '/';

 hInet:= InternetOpen('My Agent',INTERNET_OPEN_TYPE_PRECONFIG,nil,nil,0);
 if not Assigned(hInet) then
begin
Showmessage('Error: InternetOpen');
exit;
end;

 hCon:= InternetConnect(hInet, PChar(URL_Base), Port, nil, nil, INTERNET_SERVICE_HTTP, 0, 0);
  if not Assigned(hCon) then
  begin
  Showmessage('Error: InternetConnect');
  exit;
   end;

  if Port <> 443 then
  hReq:= HttpOpenRequest(hCon, PAnsichar(Method), PAnsichar(URL_Page),HTTP_VERSION, nil,nil,
  INTERNET_FLAG_KEEP_CONNECTION or INTERNET_FLAG_RELOAD, 0)
  else
  hReq:= HttpOpenRequest(hCon, PAnsichar(Method), PAnsichar(URL_Page),HTTP_VERSION, nil,nil,
  INTERNET_FLAG_SECURE, 0);

  if not Assigned(hReq) then
  begin
  Showmessage('Error: HttpOpenRequest');
  exit;
  end;

         // добавляем необходимые заголовки к запросу
      Host:= 'Host: ' + URL_Base;
     if Port <> 80 then
     Host:= Format('%s:%d', [Host, Port]);
     HttpAddRequestHeaders(hReq, PAnsiChar(Host),
     Length(Host), HTTP_ADDREQ_FLAG_ADD);

      HttpAddRequestHeaders(hReq, Accept,
        Length(Accept), HTTP_ADDREQ_FLAG_ADD);
      HttpAddRequestHeaders(hReq, ProxyConnection,
        Length(ProxyConnection), HTTP_ADDREQ_FLAG_ADD);
      HttpAddRequestHeaders(hReq, LNG,
        Length(LNG), HTTP_ADDREQ_FLAG_ADD);
      HttpAddRequestHeaders(hReq, AGENT,
        Length(AGENT), HTTP_ADDREQ_FLAG_ADD);

      if SendHeader <> '' then
     begin
     HttpAddRequestHeaders(hReq, PAnsichar(SendHeader),
     Length(SendHeader), HTTP_ADDREQ_FLAG_ADD);
     end;

        // Проверяем запрос:
      StatusSize := 0;
      Index := 0;
      SRequest := '';
      HttpQueryInfo(hReq, HTTP_QUERY_RAW_HEADERS_CRLF or
        HTTP_QUERY_FLAG_REQUEST_HEADERS, @SRequest[1], StatusSize, Index);
      if StatusSize > 0 then
      begin
         SetLength(SRequest, StatusSize);
        HttpQueryInfo(hReq, HTTP_QUERY_RAW_HEADERS_CRLF or
          HTTP_QUERY_FLAG_REQUEST_HEADERS, @SRequest[1], StatusSize, Index);
      end;

  // Отправляем запрос
  if (SendStream <> nil) then
  begin
  if not (HttpSendRequest(hReq, nil, 0, TMemoryStream(SendStream).Memory, SendStream.Size)) then
  begin
  Showmessage('Error: HttpSendRequest SendStream');
  exit;
  end;
  end
  else
  if  not (HttpSendRequest(hReq, nil, 0, nil, 0)) then
  begin
  Showmessage('Error: HttpSendRequest');
  exit;
  end;
  
  //Смотрим ответ сервера
     S:= GetQueryInfo(hReq);
     Result:= Copy(S, 1, Length(S)-1);

         posi := 1;
          b := 1;
          ResponseString := '';
          while b > 0 do
          if InternetQueryDataAvailable( hReq, bytes, 0, 0 ) then
          begin
            SetLength(ResponseString, Length(ResponseString) + bytes );
            InternetReadFile(hReq, @ResponseString[Posi], bytes, b );
            Inc(Posi, b);
          end;

   InternetCloseHandle(hReq);
   InternetCloseHandle(hCon);
   InternetCloseHandle(hInet);

  Result:= Result + ResponseString;
end;

//использовать Get запрос
procedure TForm1.Button1Click(Sender: TObject);
begin
memo1.Text:= UTF8ToAnsi(GetPostSite('GET', 'https:/...........'));
end;

//использовать Post запрос
procedure TForm1.Button2Click(Sender: TObject);
var
stream: TStringStream;
begin
stream:= TStringStream.Create('');
try
stream.WriteString('что то вписываем для отправки в запросе');
memo1.Text:= UTF8ToAnsi(GetPostSite('POST', 'https:/...........', '', stream));
finally
stream.Free;
end;
end;

Последний раз редактировалось Aliens_wolfs; 08.07.2017 в 19:15.
Aliens_wolfs вне форума Ответить с цитированием
Старый 08.07.2017, 19:02   #5
Pavia
Лис
Старожил
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 2,409
По умолчанию

Цитата:
Сообщение от GreenWizard Посмотреть сообщение
и там пишут, мол, это проблема winsocks.dll.
Эта проблема антивируса. Сносишь антивирус и зависания пропадают.

Цитата:
Сообщение от GreenWizard Посмотреть сообщение
1) переходить с Indy на тот же Synapse и т. п... тут мне интересен опыт форумчан, стоит ли оно того, поддерживает ли ssl и т.д.
А смысл? Да поддерживает. Проблема в том что Synapse это тот же Indy 10 летней давности. Небольшая обёртка над сокетами, без нормально поддержки параллельности и асинхронности. По сути придётся кучу кода дописать самому чтобы привести в чувство.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .
Pavia вне форума Ответить с цитированием
Старый 08.07.2017, 19:05   #6
GreenWizard
мальчик-помогай =)
Форумчанин
 
Регистрация: 16.09.2010
Сообщений: 522
По умолчанию

Цитата:
Сообщение от Pavia Посмотреть сообщение
Эта проблема антивируса. Сносишь антивирус и зависания пропадают
Снесён, особенно под ВМ.... ещё идеи?

Цитата:
А смысл? Да поддерживает. Проблема в том что Synapse это тот же Indy 10 летней давности. Небольшая обёртка над сокетами, без нормально поддержки параллельности и асинхронности. По сути придётся кучу кода дописать самому чтобы привести в чувство.
Мне лишь бы работали post/get однопоточные, но с таймаутами (думаю такое реализовано в самом WinInet/WinSocks). Synapse просто как пример альтернативы

Последний раз редактировалось GreenWizard; 08.07.2017 в 19:10.
GreenWizard вне форума Ответить с цитированием
Старый 08.07.2017, 19:07   #7
Aliens_wolfs
Форумчанин
 
Регистрация: 16.12.2009
Сообщений: 902
По умолчанию

Цитата:
Эта проблема антивируса. Сносишь антивирус и зависания пропадают.
У меня как то без антивируса была похожая проблема когда часто запросы делаешь через Synapse, а WinInit такого не видел, не знаю с чем связанно, поэтому и отказался от этих компонентов.

Попробуй код что я написал в посте #4.

Последний раз редактировалось Aliens_wolfs; 08.07.2017 в 19:22.
Aliens_wolfs вне форума Ответить с цитированием
Старый 08.07.2017, 19:42   #8
Pavia
Лис
Старожил
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 2,409
По умолчанию

Цитата:
Сообщение от GreenWizard Посмотреть сообщение
.... ещё идеи?
Плоха линия связи. При пропадание пакета. TCP связь может перестать отвечать. Пакеты уходят, отправляющая сторона думает, что соединение живое, а принимающее что мёртвое и отфутболивший сообщения. В TCP на этот счёт ничего не предусмотрено.
В принципе Indy это нормально отрабатывает, и такие ошибки ловятся по тайм-ауту. Проблемы начинаются при работе с прокси, тайм ауты не работают.
В отсюда можно сделать вывод, что это проблемы в Indy.
Проблемы произошли в сегменте прокси - конечный сервер, а Indy.

Честно я думал они уж это поправили за столько лет. Видимо ещё нет ;(
Какая у вас версия Delphi и indy?
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .
Pavia вне форума Ответить с цитированием
Старый 08.07.2017, 19:54   #9
GreenWizard
мальчик-помогай =)
Форумчанин
 
Регистрация: 16.09.2010
Сообщений: 522
По умолчанию

Цитата:
Сообщение от Pavia Посмотреть сообщение
Какая у вас версия Delphi и indy?
Пишут:
Код:
  gsIdVersion = '10.5.8.0'; {do not localize}
  gsIdProductName = 'Indy';  {do not localize}
GreenWizard вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
У меня не работает: Ubuntu->(Indy или Synapse)->SMTP. А у Вас? BOEHKOM Lazarus, Free Pascal, CodeTyphon 25 17.08.2015 23:45
Indy или Synapse. кусками забрать файл. КАК? Человек_Борща Работа с сетью в Delphi 2 07.04.2012 12:13
Ошибка в коде или что-то другое? Яр|/||< (^_^) PHP 17 17.06.2010 18:10
preg_replace ?? или что то другое... micron PHP 14 18.02.2010 15:10
Перегрев или что то другое? AbRaKaTaBrA Компьютерное железо 11 09.02.2010 14:45