Доброго времени суток многоуважаемые!
Помогите разобраться. стоит задача - демон подключается к некоему удалённому сетевому приложению и держит с ним keepalive TCP коннекцию. Если она порвётся - демон должен об этом узнать.
Насколько я вычитал из манов в модуле IO::Socket есть функция connected. Как маны сообщают, если конекция жива - функция вертает адрес удалённго пира, если нет undef.
В конструкции $peer=$socket->connected; возвращает полнейшую бинарную несвуразицу. что не так?
заранее благодарен.
Многоуважаемые? неужели ни у кого никогда не возникало подобной проблемы?
никто не может помочь?
Бесплатный совет: учись задавать вопросы.
Чтобы что-то сказать, нужно как минимум, язык программирования (PHP? Perl?) и используемую библиотеку. Не помешает ОС.
>Бесплатный совет: учись задавать вопросы.
>Чтобы что-то сказать, нужно как минимум, язык программирования (PHP? Perl?) и используемую
>библиотеку. Не помешает ОС.
Вообще то эхотага называется "Программирование под Юникс".... думаю не нужно быть семи пядей во лбу, что бы понять, что пишу не для полуоси. (ASP 9.0 / RedHat 9)
Ключевая тема сообщения - Perl. Опять же не слишком много ума стоит преложить, что бы догадаться, что за язык используется.
Ну и наконец третье: цитируя самого себя "Насколько я вычитал из манов в модуле IO::Socket есть функция connected" - какую же я библиотеку использую, а?
встречный совет - зрите глобальней! читайте мелкий текст, или просто сходите к окулисту.
Огромное спасибо всем, кто принял участие в дисскуссии!
После многочасаовых изысканий нашел довольно приемлемый вариант.
публикую его тут, если вдруг кому понадобится:#!/usr/bin/perl
use IO::Socket;
sub err
{
$reason=shift;
if ($reason ne 'Resource temporarily unavailable'){ #Если сокет поднят, но данных для чтения нет
$netfault=1;
$reconnect=1;
close($socket);
}
}
sub dc_connect
{
$netfault=0;
$reconnect=0;
$socket = IO::Socket::INET->new(PeerAddr=> "localhost",
PeerPort => 7777,
Proto => 'tcp',
Timeout => 1,
Type => SOCK_STREAM) || &err("$!");
if ($netfault)
{
print "Can't establish connection: $reason\n";
$reconnect=1;
}
}
################# GENERAL VARIABLES ###################
$netfault=0; #network fail
$reconnect=1; #need try to connect
while (1)
{
################ ESTABLISH CONNECTION##################
&dc_connect if ($reconnect);
############## CHECK NETWORK CONNECTION ##################
##################### NET CHECK ##########################
recv ($socket,$netdata,512,MSG_DONTWAIT)||&err("$!") if (!$netfault);
print "Error receving: $reason\n" if ($netfault);
if ($netdata)
{
print "recv from socket:$netdata";
$netdata='';
}
##########################################################sleep 1;
}
Сегдня буду разбираться с этим, в случае положительного результата - доложу
>Сегдня буду разбираться с этим, в случае положительного результата - доложуОчень жду Вашего результата. сам - разбился в лепёшку об этот "камень преткновения".
Единственный способ, что для себя нашел - анализировать что выдает netstat.
Еще "Сишники" посоветовали скажем раз в 1 - 10 секунд отправлять в сокет 0 байт и слушать return функции send()....
Если 0 - все ок, если -1 - конекция умерла. - экспериментировал -возвращается 0 в любом случае...
Пока узнал вот что:
connected возвращает undef, только если руками засрываеш соединение
если послать определенное кол-во данных в "мертвый" сокет получаем Broken pipe;
так-же пробовал по спотреть return write() и send()
но!
я паралельно вижу _живое_ соеденинеие с помощю sockstat (netstat)
те, операционка считает подключение ещё живым.
>Еще "Сишники" посоветовали скажем раз в 1 - 10 секунд отправлять в
>сокет 0 байт и слушать return функции send()....
>Если 0 - все ок, если -1 - конекция умерла. -
>экспериментировал -возвращается 0 в любом случае...Я на C делал так:
С помощью select проверял есть ли данные для чтения. Если ответ
положительный (данные для чтения есть) и количество байт для чтения равно
0, то соединение "умерло". Количетсво байт для чтения можно получить
функциями read, recv и т.д. или через ioctl, например в Линуксе,
ioctl(sock_fd,FIONREAD,&nbytes). Возможно, подобная схема реализуема и на
перле.
P.S. Демон на перле - извращение, ИМХО :)))
Решение нашел, но кривое.# cat conn.pl
#!/usr/bin/perl
use strict;
use IO::Socket;
use Fcntl qw(:mode);
$|=1;my $host = '127.0.0.1';
my $port = '1234';
my $r = IO::Socket::INET->new ( Proto => "tcp",
PeerAddr => $host,
PeerPort => $port ) || die "can`t connect";
while ('true')
{
my @a = $r->stat;
print join(':',@a), "\n";
printf "Permissions are %04o\n", S_IMODE($a[2]), "\n";
print $r "asdfa sdfa sdf asdf adsf ";
sleep 4;
}вывод:
# ./conn.pl
0:0:49590:0:0:0:0:0:0:0:0:57344:0
Permissions are 0666
0:0:49590:0:0:0:0:0:0:0:0:57344:0
Permissions are 0666# в этот момент я убиваю сервер
0:0:49298:0:0:0:0:0:0:0:0:57344:0
Permissions are 0222
0:0:49152:0:0:0:0:0:0:0:0:57344:0
Permissions are 0000
Broken pipeКомментировать или из кода поятно?
В принципе все доступно, только разве что в стремлении к ясности и новым знаниям просил бы дать ремарки на 2 строчки Вашего кода. а именно :my @a = $r->stat;
printf "Permissions are %04o\n", S_IMODE($a[2]), "\n";Заранее благодарен.
perldoc -f stat
stat () - возвращает массив с парметрами файла.
(в данном случае с параметрами сокета)
нас интересует 2-ая запись - права доступа.
сокет становится read-only, когда соединение рвется.
(если я все павильно понял)S_IMODE()
(perldoc POSIX)
преобразует mode, возвращаемый stat() в привычный вид (user-group-other)
Прошу прощения, что вклиниваюсь...
Я на перле почти не програмлю, так что сорри если что-то невпопад:сервер srv.pl:
#!/usr/bin/perl
use IO::Socket;
$srv_sock = new IO::Socket::INET (
LocalHost => 'localhost',
LocalPort => '4000',
Proto => 'tcp',
Listen => 1,
Reuse => 1,
);die "Could not create socket: $!\n" unless $srv_sock;
$clnt_sock=$srv_sock->accept();
print $clnt_sock "I am here\n";
while (<$clnt_sock>) {
print "Got: ",$_,"\n";
}
close($srv_sock);
#== cut ======================
Клиент cln.pl:
#!/usr/bin/perl
use IO::Socket;
use IO::Select;
use Fcntl qw(:mode);$sock = new IO::Socket::INET (
PeerAddr => 'localhost',
PeerPort => '4000',
Proto => 'tcp',
);
die "Could not create socket: $!\n" unless $sock;@a = $sock->stat;
print join(':',@a), "\n";
printf "1. Permissions are o\n", S_IMODE($a[2]), "\n";
print $sock "asdfa sdfa sdf asdf adsf ";sleep 5;
print "Passed sleep\n";
@a = $sock->stat;
print join(':',@a), "\n";
printf "2. Permissions are o\n", S_IMODE($a[2]), "\n";
print $sock "asdfa sdfa sdf asdf adsf ";$readfs=new IO::Select();
$readfs->add($sock);while ($res = IO::Select->select($readfs, undef, undef, 0)) {
printf "1. res=%s\n", $res;
foreach $rh (@$readfs) {
if ($rh == $sock) {
$buf = <$rh>;
if (!length($buf)) {
print "I got 0 bytes to read - supposed connection was closed\n";
exit;
}
printf "Got from server: '%s', %u\n", $buf,length($buf);
}
}
$readfs->remove($rh);
}print "Prepare to send data\n";
print $sock "Hello, world!\n";
print "Data was sent\n";
close($sock);
#==== cut ====================1.
Запускаю srv.pl
Запускаю cln.pl
Получаю на клиенте
4:4776:49663:1:1000:1000:0:0:0:0:0:1024:0
1. Permissions are 0777И спустя пять секунд:
Passed sleep
4:4894:49663:1:1000:1000:0:0:0:0:0:1024:0
2. Permissions are 0777
1. res=3
Got from server: 'I am here
', 10
Prepare to send data
Data was sentПолучаю на сервере:
Got: asdfa sdfa sdf asdf adsf asdfa sdfa sdf asdf adsf Hello, world!2. Запускаю srv.pl
запускаю cln.plПолучаю:
4:4946:49663:1:1000:1000:0:0:0:0:0:1024:0
1. Permissions are 0777Примерно через секунду убиваю сервер.
Еще через четыре секунды получаю:Passed sleep
4:4946:49663:1:1000:1000:0:0:0:0:0:1024:0
2. Permissions are 0777
1. res=3
Got from server: 'I am here
', 10
1. res=3
I got 0 bytes to read - supposed connection was closed
Т.е. трюк со stat почему-то не сработал, возможно я сделал, что-то не так.
Но select отработал как надо.
2 Soldier
во-первых, каждый пишет на чем умеет
во-вторых, перл мне наравиться, потому, что он более высокого уровня, те на создание нужного алгоритма ужодить меньше вермени. (не сочтите это за попытку развязвть "религиозную войну" )
2 rWizardПризнаю, что перл - довольно мощная штука, хоть мне он и не нравится, но...
Во-первых, знать С должен каждый уважающий себя юникс-программер, ИМХО.
Во-вторых, вот потому, что он (перл) более высокого уровня, плюс ко всему
еще и интерпретатор, писать на нем демона и есть извращение, ИМХО ;-)P.S. Никого не хотел задеть или обидеть, просто высказал свое мнение.