-
Всем привет! Есть небольшая трабла: если соединение с сетью неактивно или отключено, то попытка соединиться через него затягивается секунд на 10-15, что слишком уж долго. Сокет создаётя с таймаутом 5000, то есть по идее должен вываливаться гораздо раньше. Может, где-то в недрах WinSock-а есть некая глобальная переменная? У кого-нибудь есть идеи?
-
Похоже ты путаешь лукап с коннектом
-
> SpellCaster
ждет на функции Connect() ? Если да, то используй неблокирующие сокеты или хотя бы неблокирующий Connect.
-
> Сокет создаётя с таймаутом 5000
Что за сокет ты создаешь? (Компонент или сам). И где ты указал таймаут?
-
> Сергей М.
Да нет вроде > DVM
Ага, на ней. Неблоки не хочется, а неблок. коннект нет смысла, т.к. сокет в отдельном треде. > Что за сокет ты создаешь? (Компонент или сам).
Свой класс, простая обёртка над АПИ. Блокирующий сокет, вот кусок кода его создания: fSckt:=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if fSckt=INVALID_SOCKET then Exit;
if bind(fSckt,fLocalAddr,SizeOf(TSockAddr))=SOCKET_ERROR then Exit;
fInTraf:=0; fOutTraf:=0;
Result:=WinSock.connect(fSckt,tmp_addr,SizeOf(TSockAddr));
if Result=SOCKET_ERROR then Exit;
> И где ты указал таймаут?
Мда, сейчас посмотрел, там у меня таймаут используется только при проверке готовности, т.е. в коннекте он не участвует. Интересно, его вообще можно поменять?
-
> а неблок. коннект нет смысла, т.к. сокет в отдельном треде.
Смысл есть, т.к. даже если все помещено в отдельный поток, ты завершения потока не дождешься, пока Connect() не отработает. Имеет смысл переводить сокет перед выполнением Connect() в неблокирующий режим, а после возвращать в блокирующий как более простой для работы. Сам Connect() никаким образом не прервать, не помогает ни закрытие сокета из другого потока, ни что другое. > Интересно, его вообще можно поменять?
Можно. Я вот так делал с неблокирующим режимом (можно и с блокирующим, но с неблок лучше - можно мгновенно прервать коннект)
function THTTPInputThread.SocketConnect: integer;
var
NoBlock: integer;
Wfd, EFd: TFDSet;
TimeVal: TTimeVal;
begin
Result := socket(AF_INET, SOCK_STREAM, 0);
if Result = INVALID_SOCKET then
begin
Result := -1;
exit;
end;
NoBlock := 1;
if ioctlsocket(Result, FIONBIO, NoBlock) = SOCKET_ERROR then
begin
CloseSocket(Result);
Result := -1;
exit;
end;
if Connect(Result, FAddr, SizeOf(FAddr)) = SOCKET_ERROR then
begin
if WSAGetLastError = WSAEWOULDBLOCK then
begin
while not Terminated do
begin
FD_ZERO(wfd);
FD_SET(result, wfd);
FD_ZERO(efd);
FD_SET(result, efd);
TimeVal.tv_sec := 0;
TimeVal.tv_usec := 50;
case select(0, nil, @wfd, @efd, @TimeVal) of
0: sleep(50);
1: if FD_ISSET(Result, wfd) then
break
else
if FD_ISSET(Result, efd) then
begin
NoBlock := 0;
ioctlsocket(Result, FIONBIO, NoBlock);
CloseSocket(Result);
Result := -1;
exit;
end;
SOCKET_ERROR:
begin
NoBlock := 0;
ioctlsocket(Result, FIONBIO, NoBlock);
CloseSocket(Result);
Result := -1;
exit
end;
end;
end;
end
else
begin
NoBlock := 0;
ioctlsocket(Result, FIONBIO, NoBlock);
CloseSocket(Result);
Result := -1;
end;
end;
NoBlock := 0;
if ioctlsocket(Result, FIONBIO, NoBlock) = SOCKET_ERROR then
begin
CloseSocket(Result);
Result := -1;
end;
end;
-
> Смысл есть, т.к. даже если все помещено в отдельный поток, > ты завершения потока не дождешься, пока Connect() не отработает.
Логично! Ты прав! Пример сейчас поковыряю, а пока еще вопрос:
> можно и с блокирующим, но с неблок лучше - можно мгновенно > прервать коннект
Как с блокирующими сделать?
-
Кстати, "Result := -1;" легче присвоить в начале функции, а при ошибке просто выходить - сэкономит несколько строчек )).
|