Как мне установить `SO_RCVTIMEO` для сокета в Perl?
Если я попытаюсь так:
my $sock = IO::Socket::INET->new( … ) or die "no socket for you";
defined $sock->setsockopt(SOL_SOCKET, SO_RCVTIMEO, 30) or die "setsockopt: $!";
тогда мой скрипт подвергается смерти от "setsockopt: Неверный аргумент в [строка 2]". IO::Socket
а также perlfunc
pods не говорят, хотя perlfunc приводит пример с TCP_NODELAY
что делает это похоже на то, что выше должно работать.
(быстрое примечание: я ответил на свой собственный вопрос, насколько смог, но, конечно, приветствую лучший ответ. Самое очевидное "лучшее" - это его переносимость, по крайней мере, на компьютерах POSIX)
2 ответа
Используя strace
при интерпретаторе Perl, выполняющем скрипт, становится ясно, что проблема в том, что Perl не упаковывает struct timeval
(требуется SO_RCVTIMEO
) для тебя. Кроме того, похоже, что нет вспомогательных функций, которые могли бы сделать это за вас. Вместо этого вы должны сделать это самостоятельно.
Это оказывается проблематичным, потому что struct timeval
зависит от машины. Спецификация Single Unix определяет это:
Заголовок должен определять временную структуру, которая должна включать как минимум следующие элементы:
time_t tv_sec Seconds. suseconds_t tv_usec Microseconds.
В нем также говорится, что time_t является целочисленным или вещественно-плавающим типом, и "suseconds_t должен быть целочисленным типом со знаком, способным хранить значения по крайней мере в диапазоне [-1, 1000000]" (см. Sys / types.h).
Без доступа к структуре C это невозможно сделать переносимым образом. Но если мы предположим, что glibc имеет более ограничительное определение, указав оба как long
и что они единственные два члена. Тем не менее, это ошибка документации. Так что не бери в голову.
Итак, лучшее, что я могу сделать, что, как я считаю, работает как на GNU/Linux IA-32, так и на GNU/Linux AMD64, это:
$sock->setsockopt(SOL_SOCKET, SO_RCVTIMEO, pack('l!l!', 30, 0))
or die "setsockopt: $!";
pack
формат l!
означает использовать родную текущую машину long
- то, что говорится в документации по glibc, и, по-видимому, реализовано, по крайней мере, для некоторых архитектур glibc (но не SPARC, в соответствии с ошибкой).
Есть ли $myiosockinet->timeout( 30 );
или же $myiosockinet->timeout( 30 * 1000000 );
Работа?
Если это не так, этот модуль (IO::Socket::INET
или же Socket
) нуждается в обновлении:), потому что http://search.cpan.org/~flora/perl-5.14.2/pod/perlfaq8.pod#Where_do_I_get_the_include_files_to_do_ioctl%28%29_or_syscall%28%29%3F не удовлетворяет