Forum Webscript.Ru
Программирование => Perl => Тема начата: ZMeY от 25 Февраля 2004, 15:11:32
-
код:
use IO::Socket;
use IO::Select;
use HTTP::Daemon;
use POSIX;
use Fcntl;
$|=1;
$port = 5555;
$max_clients = 35; #SOMAXCONN
%logon =();
%nick =();
%SID =();
%log_time =();
%perms =();
%IP=();
$server = HTTP::Daemon->new(Proto => \'tcp\', LocalPort => $port, Listen => $max_clients) or die "Can\'t make server socket: $@\\n";
nonblock($server);
$select = IO::Select->new($server);
print "[Chat server runing on ", $server->url, "] \\n\\n";
while (1)
{
foreach $client ($select->can_read(1))
{
if ($client == $server)
{
#обработка событий подключения
my $new_client = $server->accept();
if(defined($new_client))
{
print "Client accepted\\n";
nonblock($new_client);
$select->add($new_client);
$logon{$new_client}="";
$nick{$new_client}="";
#присвоение остальных переменных
}
}
else
{
my $data = \'\';
my $rv = $client->recv($data, POSIX::BUFSIZ, 0);
unless (defined($rv) && length $data)
{
#очистка переменных
#delete $inbuffer{$client};
#delete $outbuffer{$client};
#delete $ready{$client};
$select->remove($cllent);
delete $client;
print "Client closed\\n";
next;
}
else
{
my $request = $client->get_request();
if (defined($request))
{
if ($request->method eq \'GET\')
{
#обработка $Id.html
}
else
{
#выдать сообщение о неверном запросе и записать в лог ошибку.
}
}
}
}
}
}
sub nonblock {
my $sock = shift;
if ($^O eq \'MSWin32\')
{
sub FIONBIO { 0x8004667e }
my $set_it = "1";
ioctl($sock, FIONBIO, $set_it)
or die "Can\'t set the socket non-blocking: $!";
} else {
my $flags = fcntl($sock, F_GETFL, 0)
or die "fcntl fails with F_GETFL: $!";
fcntl($sock, F_SETFL, $flags | O_NONBLOCK)
or die "fcntl fails with F_SETFL: $!";
}
}
Эта прога - многопотоковый сервер, который акцептит клиентов и держит связь с ними.
Если какой-то клиент отключается срабатывает болк unless (defined($rv) && length $data) НО дальше идёт глюк - все последующие подключения акцептятся, но не обрабатываются, то есть $new_client - undefined, НО и ошибки не происходит и клиент сообщает об удачном коннекте.
Если убрать unless (defined($rv) && length $data) - всё работает нормально (но обрабатывать дисконнекты - обязательно) Как быть?
-
наверное нужно убрать ошибки сначала?
Что это за строки?
$select->remove($cllent);
delete $client;
-
NeoNox
foreach $client ($select->can_read(1)) - $client это элемент селекта
Нельзя же до бесконечности увеличивать селект - надо удалять неиспользованные элементыселекта
delete $client; - ошибка...следует читать close($client)
проблема в том, что my $new_client = $server->accept(); - действие совершается, но не возвращается сообщения о том, что оно совершено!
-
поставь use strict и убери все ошибки в этом коде - потом будем разбираться
-
[moderator ]
Здесь был код с ошибками.
[\\moderator ]
вот рабочая версия...
а нельзя ли как-то определить оборвавшегося клиента кроме, как строчками
my $data = \'\';
my $rv = $client->recv($data, POSIX::BUFSIZ, 0);
unless (defined($rv) && length $data)
{
....
а то без них - всё работает...да и у меня такое подозрение, что они и get_request обнуляют...
-
ZMeY я не понимаю кому это нужно - тебе или мне?
1) Код без use strict в начале скрипта рассматриваться больше не будет.
2) исправь опечатку в $select->remove($cllent);
3) что ты вкладываеш в понятие обрабатывать дисконекты? Кем, сервером или тобой?
-
исправь опечатку в $select->remove($cllent); - это не ошибка, а спецально написанная строка - ужаляет ненужный экземпляр массива select сокетов..а что в этой строке не так?
-
> а что в этой строке не так?
Вот именно поэтому тебя и просят поставить strict и проверить весь код на отсутствие опечаток. А потом можно будет алгоритмом заняться.
-
ZMeY:
а что в этой строке не так?
Просто опечатка. Думаю, поймешь где и в чем собственно дело, когда начнешь использовать use strict;.
-
ошибку я нашёл - скрипт работает прекрасно..но одно НО - чисто алгоритмическое.
Я определяю, что клиент "умер" по:
my $rv = $client->recv($data, POSIX::BUFSIZ, 0);
unless (defined($rv) && length $data)
но после этого вызывать
request - бессмысленно recv всё забирает...как по другому определить статус сокета, что бы и овцы сыты и волки целы то есть что бы и реквест получать и вовремя узнавать о "падении" клиента?
-
Ты исправил код и вставил use strict?
Замени его тогда в первом сообщении.
-
да я уже снял старый вопрос новый:
как определить дисконнект сокета, не используя чтение буфера?
-
А я еще не снял старый вопрос.
Тебе шашечки или ехать? Если шашечки то тебе в форум по изготовлению скриптов. Если ехать - отвечай на вопросы.
На данном этапе я хочу увидеть рабочий код.
Вторым я тебя спрошу про эти строки:
my $data = \'\';
my $rv = $client->recv($data, POSIX::BUFSIZ, 0);
unless (defined($rv) && length $data)
и хочу узнать нафига тебе unless если length $data всегда равен 0?
Ты понимаеш что вообще происходит в этом коде?
-
Вторым я тебя спрошу про эти строки:
my $data = \'\';
my $rv = $client->recv($data, POSIX::BUFSIZ, 0);
unless (defined($rv) && length $data)
и хочу узнать нафига тебе unless если length $data всегда равен 0?
Ты понимаеш что вообще происходит в этом коде?
Этот код на одном из форумов подсказали как код определения статуса скрипта. Если возвратит значение - сокет работает, если undefined - не работает. Этот код действительно чётко определяет, когда клиент отключился, НО. Он делает не возможным использование request . Я хочу заменить этот участок другим, который возвратит лож, если клиент отключился и истину, если клиент всё-ещё на связи. И length $data не всегда равна 0 т.к. recv($data...Хотя честно говоря этот участок мне мало понятен. Поэтому я хочу его заменить.
-
Вот мне интересно почему тебе на том форуме не показали как \'это\' заставить работать? Мастера блин...
Замени блок на
unless (defined($rv) && length $data) {
disconnect($client);
next;
}
И что за else там стоит после unless?
Значит так, или я тебе даю рабочий код чата под nix и эту тему к чертям закрываю, либо ты пишеш сюда код с комментариями что каждая строка делает в цикле while(1). Выбирай.
-
NeoNox я прокоментирую каждую строку - ок?
-
конечно
-
кстати, посмотри вот сюда - http://poe.perl.org/?Listing.evolution.select учиться лучше на правильном коде.
-
Код:
use IO::Socket;
use IO::Select;
use HTTP::Daemon;
use POSIX;
use strict;
use Fcntl;
$|=1;
my $port = 5555;
my $max_clients = 35; #SOMAXCONN
my $server = HTTP::Daemon->new(Proto => \'tcp\', LocalPort => $port, Listen => $max_clients) or die "Can\'t make server socket: $@\\n";
nonblock($server);
my $select = IO::Select->new($server);
print "[Chat server runing on ", $server->url, "] \\n\\n";
while (1)
{
my $client; #объявляю переменную
foreach $client ($select->can_read(1)) #по очереди обращаюсь ко всем сокетам объекта селект
{
if ($client == $server) #если сокет является слушающим сервером
{
my $new_client = $server->accept(); #акцепт нового клиента
if(defined($new_client)) #если новый клиент подключен
{
nonblock($new_client); #перевод клиента в неблокирующий режим
$select->add($new_client); #добавляем клиента в общую группу сокетов
print "Client accepted\\n";
}
}
else
{
#это подскажанный код - что он делает сказать не могу, но смысл такой: определение отключившихся клиентов
my $data = \'\';
my $rv = $client->recv($data, POSIX::BUFSIZ, 0);
if(!(defined($rv) && length $data))#если клиент отключился
{
$select->remove($client); #удаляем клиента из группы соктов
close($client); #закрываем клиента
print "Client closed\\n";
next; #переходим к следующему элементу группы клиентов
}
else #если клиент на связи
{
my $request = $client->get_request();#посылаем запрос
if (defined($request))#т.к. клиент в неблок. режиме - проверяем наличие запроса
{
if ($request->method eq \'GET\')#если отправлен запрос гет
{
print $request->as_string; #отладочная строка, поднее будет заменена кодом обработки строки запроса
}
}#конец обработки реквеста
}#конец обработки клиента
}
}
}
sub nonblock {
my $sock = shift;
if ($^O eq \'MSWin32\')
{
sub FIONBIO { 0x8004667e }
my $set_it = "1";
ioctl($sock, FIONBIO, $set_it)
or die "Can\'t set the socket non-blocking: $!";
} else {
my $flags = fcntl($sock, F_GETFL, 0)
or die "fcntl fails with F_GETFL: $!";
fcntl($sock, F_SETFL, $flags | O_NONBLOCK)
or die "fcntl fails with F_SETFL: $!";
}
}
Вопрос такой - как заменить непрокоментированный блок, таким обрахззом, что бы он возвращал истину, если клиент он-лайн и лож, если отключился
-
То что тебя интересует это чтение из ранее установленного сокета.
-
NeoNox я знаю, что это чтение - я не совсем пониаю, как с его помощью определяется статус клиента...ну да это и не важно!
Как заменить этот код другими кодом, который однозначно будет определять - на связи клиент или уже отключился