Тайм-аут подключения TCP (портативный Unix / Windows) - PullRequest
4 голосов
/ 11 января 2010

Я использую Perl (который, надеюсь, ни на что не повлияет), но мне нужно знать, как установить тайм-аут для операции подключения. Проблема в том, что я не могу ждать вечно, чтобы произошла операция подключения. Если это не произойдет в течение нескольких секунд, я бы предпочел сдаться и идти дальше.

socket(my $sock, PF_INET, SOCK_STREAM, (getprotobyname('tcp'))[2]);
setsockopt($sock, SOL_SOCKET, SO_SNDTIMEO, 10); # send timeout

print "connecting...\n";
connect($sock, sockaddr_in(80,scalar gethostbyname('lossy.host.com')));
print "connected...\n";

Проблема в том, что, если соединение с «lossy.host.com» является «потерянным» или медленным или что-то иное, но быстрое, я бы скорее сдался, чем заставил пользователя ждать. (Думайте об этом как о побочном эффекте для программы, которая делает что-то еще ... пользователь, вероятно, не ожидает, что этот скрипт будет где-то взаимодействовать с сервером ...).

Threading Case: как бы вы прервали соединение ()? Вы бы просто отсоединили нить и забыли об этом?

Ответы [ 3 ]

2 голосов
/ 17 февраля 2010

Вы можете использовать fcntl, чтобы установить сокет как неблокирующий, затем select с таймаутом, ожидающим, чтобы он стал читаемым. Если он не станет читаемым до истечения времени ожидания, вы можете закрыть его в этот момент.

Я знаю, как сделать это на C, но не на Perl, иначе я бы привел вам пример. В man-странице perlfunc говорится, что все эти функции существуют, и при беглом чтении кажется, что они будут работать так, как вы хотите.

Редактировать: извините, пропустил ту часть, где perlfunc говорит, что они могут быть недоступны в не-Unix системах, и действительно, fcntl недоступен в win32. Существует библиотека IO :: Socket, которую вы можете использовать, которая будет правильно работать в Windows.

Вот пример кода, который работает для меня (в любом случае на Linux):

#!/usr/bin/perl

use IO::Socket::INET;
use IO::Select;

$sock = IO::Socket::INET->new('PeerAddr' => 'lossy.host.com',
                              'PeerPort' => 80,
                              'Blocking' => 0 );

$sel = IO::Select->new( $sock );

@writes = $sel->can_write(10);

if ( $sock->connected ) {
    print "socket is connected\n";
} else {
    print "socket not connected after however long\n";
    $sock->close;
}
1 голос
/ 11 января 2010

Вы можете создать отдельный поток, чтобы сделать это, а затем выполнить временное ожидание результата. Если вы не получили результат за соответствующее время, откажитесь от ожидания и просто продолжите поток. Это в конечном итоге истечет время ожидания, или вы можете убить поток.

Чтобы ответить на первоначальный вопрос, я не думаю, что есть способ изменить время ожидания connect(), по крайней мере, через сокеты API. В Windows я не удивлюсь, если есть какой-то раздел реестра, который вы можете изменить, который повлияет на него, но я не знаю, что это будет.

0 голосов
/ 18 февраля 2010

Если вы в конечном итоге выполняете многопоточный случай, когда отсоединяете соединительный поток, не убивая его, остерегайтесь следующего: Windows позволяет вам иметь максимум 10 ожидающих исходящих соединений TCP (одиннадцатый будет блокироваться до тех пор, пока один из ожидающих не будет раз выход).

Это стало причиной большого разочарования для меня. Я думаю, что MS вставил это, чтобы предотвратить распространение ботнетов или что-то в этом роде. Я не думаю, что есть какой-либо способ его выключить.

...