Тема: WinSock + Timeout
Показать сообщение отдельно
  #2  
Старый 25.08.2011, 09:22
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

при подключении переводи сокет в неблокирующий режим через ioctlsocket, потом select с таймаутом ожидай завершения операции connect, потом обратно в блокирующий режим.

при чтении опять же через select определяй readability статус у сокета.

Код:
procedure connect;
var
  WSAData: TWSAData;
  FSocket: TSocket;
  FAddr: sockaddr_in;
  arg: Integer;
  ErrorCode: Integer;
  FDSetW: TFDSet;
  FDSetE: TFDSet;
  TimeVal: TTimeVal;
const
  FTimeOutConnect: Cardinal = 5000;
begin
  WSAStartup($0101, WSAData);
  FSocket:=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  FAddr.sin_family:=AF_INET;
  FAddr.sin_port:=htons(80);
  FAddr.sin_addr.S_addr:=inet_addr(PChar('74.125.232.51'));
  arg:=1;
  ioctlsocket(FSocket, FIONBIO, arg);
  if WinSock.connect(FSocket, FAddr, SizeOf(FAddr))<>0 then
  begin
    ErrorCode:=WSAGetLastError;
    if ErrorCode<>WSAEWOULDBLOCK then
      raise Exception.Create('connect(): '+SysErrorMessage(ErrorCode));
    FD_ZERO(FDSetW);
    FD_ZERO(FDSetE);
    FD_SET(FSocket, FDSetW);
    FD_SET(FSocket, FDSetE);
    TimeVal.tv_sec:=FTimeOutConnect div 1000;
    TimeVal.tv_usec:=(FTimeOutConnect mod 1000)*1000;
    select(0, nil, @FDSetW, @FDSetE, @TimeVal);
    if not FD_ISSET(FSocket, FDSetW) then
      raise Exception.Create('connect(): timeout');
  end;
  arg:=0;
  ioctlsocket(FSocket, FIONBIO, arg);
end;

function recv(FSocket: TSocket; var Buf; Count: Integer): Integer;
var
  ErrorCode: Integer;
  FDSet: TFDSet;
  TimeVal: TTimeVal;
const
  FTimeOutRead: Cardinal = 5000;
begin
  FD_ZERO(FDSet);
  FD_SET(FSocket, FDSet);
  TimeVal.tv_sec:=FTimeOutRead div 1000;
  TimeVal.tv_usec:=(FTimeOutRead mod 1000)*1000;
  if select(0, @FDSet, nil, nil, @TimeVal)=SOCKET_ERROR then
    raise Exception.Create('recv: invalid socket');
  if not FD_ISSET(FSocket, FDSet) then
    raise Exception.Create('recv(): timeout');
  Result:=WinSock.recv(FSocket, Buf, Count, 0);
  if Result=0 then
  begin
    closesocket(FSocket);
    raise Exception.Create('recv: closed');
  end;
  if (Result=SOCKET_ERROR) then
  begin
    ErrorCode:=WSAGetLastError;
    closesocket(FSocket);
    raise Exception.Create('recv: '+SysErrorMessage(ErrorCode));
  end;
end;
__________________
Пишу программы за еду.
__________________
Ответить с цитированием