Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Сети > Установка таймаута на сокет


Автор: dmitry8 7.2.2018, 07:45
Привет!
Подскажите, пожалуйста, как установить  в клиенте таймаут для отправки и получения данных на сокет в блокирующем режиме.
Пытаюсь сделать как в коде ниже, но функция getsockopt возвращает значения, равные 4 миллисекунды, хотя я устанавливал 500.
Проблема в том, что connect(fSocket, fSockAddr, sizeof(TSockAddr)) длится более 20 секунд, если сервер не доступен (скажем, нет пинга).
Код

function Form1.SockConnect: Boolean; 
var
  send_in, rec_in: Integer;
  send_out, rec_out: Integer;
  fSockConnected: Boolean;
begin
  Result := false;
  fSockConnected := true;
  fSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
  if fSocket = INVALID_SOCKET
   then
    begin
     fSockConnected := false;
     Exit;
    end;

  send_in:= 500;
  rec_in:= 500;

  if (setsockopt(fSocket, SOL_SOCKET, SO_SNDTIMEO, @send_in, SizeOf(send_in)) = 0)
   then
    begin
     if (getsockopt(fSocket, SOL_SOCKET, SO_SNDTIMEO, @send_out, send_out) = 0)
       then ShowMessage(IntToStr(send_out));
    end;

  if (setsockopt(fSocket, SOL_SOCKET, SO_RCVTIMEO, @rec_in, SizeOf(rec_in)) = 0)
   then
    begin
     if (getsockopt(fSocket, SOL_SOCKET, SO_RCVTIMEO, @rec_out, rec_out) = 0)
       then ShowMessage(IntToStr(rec_out));
    end;

  FillChar(fSockAddr, sizeof(TSockAddr), 0);
  fSockAddr.sin_family := AF_INET;
  fSockAddr.sin_port := htons(iPort);
  fSockAddr.sin_addr.S_addr := inet_addr(PAnsiChar(sIP));

  if (connect(fSocket, fSockAddr, sizeof(TSockAddr)) = SOCKET_ERROR)
   then
    begin
     fSockConnected := false;
     Exit;
    end;

  Result := true;
end;


Автор: Snowy 7.2.2018, 11:40
SO_RCVTIMEO и SO_SNDTIMEO устанавливают таймаут на приём и отправку данных. не на коннект. То есть уже после соединения.

В случае ожидания соединения, следует поместить connect в цикл и делать последовательные попытки соединения.

Попытка соединения 1...
Попытка соединения 2...
Попытка соединения 3...
Попытка соединения 4...

Автор: dmitry8 7.2.2018, 12:13
Как же тогда досрочно прервать не успешный коннект, скажем, через 500 мсек, если сервер не отвечает (нет пинга).
Т.е. не ждать 20 секунд, чтобы понять, что коннект не удачен?

Автор: Snowy 8.2.2018, 11:27
Ну так цикл же твой. Как хочешь так его и прерывай.
Можешь завести переменную-флажок и устанавливать её, например, по нажатию кнопки, а в цикле проверять.

Автор: dmitry8 27.2.2018, 12:22
connect проходит успешно,
после него пытаюсь установить таймаут,
однако же getsockopt возвращает 4 миллисекунды вместо 500
??? 

Код

function Form1.SockConnect: Boolean; 
var
  send_in, rec_in: Integer;
  send_out, rec_out: Integer;
  fSockConnected: Boolean;
begin
  Result := false;
  fSockConnected := true;
  fSocket := socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
  if fSocket = INVALID_SOCKET
   then
    begin
     fSockConnected := false;
     Exit;
    end;

  FillChar(fSockAddr, sizeof(TSockAddr), 0);
  fSockAddr.sin_family := AF_INET;
  fSockAddr.sin_port := htons(iPort);
  fSockAddr.sin_addr.S_addr := inet_addr(PAnsiChar(sIP));
  if (connect(fSocket, fSockAddr, sizeof(TSockAddr)) = SOCKET_ERROR)
   then
    begin
     fSockConnected := false;
     Exit;
    end;

  send_in:= 500;
  rec_in:= 500;
  if (setsockopt(fSocket, SOL_SOCKET, SO_SNDTIMEO, @send_in, SizeOf(send_in)) = 0)
   then
    begin
     if (getsockopt(fSocket, SOL_SOCKET, SO_SNDTIMEO, @send_out, send_out) = 0)
       then ShowMessage(IntToStr(send_out));
    end;
  if (setsockopt(fSocket, SOL_SOCKET, SO_RCVTIMEO, @rec_in, SizeOf(rec_in)) = 0)
   then
    begin
     if (getsockopt(fSocket, SOL_SOCKET, SO_RCVTIMEO, @rec_out, rec_out) = 0)
       then ShowMessage(IntToStr(rec_out));
    end;

  Result := true;
end;

Автор: Snowy 27.2.2018, 17:56
4 - это не таймаут - это длина Integer - ты же используешь одну и ту же переменную для получения значения и для размера.
Попробуй наоборот:
Код
(getsockopt(fSocket, SOL_SOCKET, SO_SNDTIMEO, @send_out, send_in)

Код
(getsockopt(fSocket, SOL_SOCKET, SO_SNDTIMEO, @send_in, send_out)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)