Forum Webscript.Ru

Программирование => Perl => Тема начата: ZMeY от 25 Февраля 2004, 15:11:32

Название: Ошибка в коде
Отправлено: 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) - всё работает нормально (но обрабатывать дисконнекты - обязательно) Как быть?
Название: Ошибка в коде
Отправлено: NeoNox от 25 Февраля 2004, 16:24:03
наверное нужно убрать ошибки сначала?
Что это за строки?
$select->remove($cllent);
delete $client;
Название: Ошибка в коде
Отправлено: ZMeY от 25 Февраля 2004, 19:43:17
NeoNox
foreach $client ($select->can_read(1)) - $client это элемент селекта
Нельзя же до бесконечности увеличивать селект - надо удалять неиспользованные элементыселекта

delete $client; - ошибка...следует читать close($client)

проблема в том, что my $new_client = $server->accept(); - действие совершается, но не возвращается сообщения о том, что оно совершено!
Название: Ошибка в коде
Отправлено: NeoNox от 25 Февраля 2004, 20:14:25
поставь use strict и убери все ошибки в этом коде - потом будем разбираться
Название: Ошибка в коде
Отправлено: ZMeY от 25 Февраля 2004, 20:25:19
[moderator ]
Здесь был код с ошибками.
[\\moderator ]


вот рабочая версия...
а нельзя ли как-то определить оборвавшегося клиента кроме, как строчками

      my $data = \'\';
      my $rv = $client->recv($data, POSIX::BUFSIZ, 0);
      unless (defined($rv) && length $data)
      {
....
а то без них - всё работает...да и у меня такое подозрение, что они и get_request обнуляют...
Название: Ошибка в коде
Отправлено: NeoNox от 26 Февраля 2004, 11:06:29
ZMeY я не понимаю кому это нужно - тебе или мне?
1) Код без use strict в начале скрипта рассматриваться больше не будет.
2) исправь опечатку в $select->remove($cllent);
3) что ты вкладываеш в понятие обрабатывать дисконекты? Кем, сервером или тобой?
Название: Ошибка в коде
Отправлено: ZMeY от 26 Февраля 2004, 14:39:40
исправь опечатку в $select->remove($cllent); - это не ошибка, а спецально написанная строка - ужаляет ненужный экземпляр массива select сокетов..а что в этой строке не так?
Название: Ошибка в коде
Отправлено: КшЫуфксрук от 26 Февраля 2004, 16:30:13
> а что в этой строке не так?

Вот именно поэтому тебя и просят поставить strict и проверить весь код на отсутствие опечаток. А потом можно будет алгоритмом заняться.
Название: Ошибка в коде
Отправлено: mike от 26 Февраля 2004, 16:30:48
Цитировать
ZMeY:
а что в этой строке не так?

Просто опечатка. Думаю, поймешь где и в чем собственно дело, когда начнешь использовать use strict;.
Название: Ошибка в коде
Отправлено: ZMeY от 26 Февраля 2004, 19:41:13
ошибку я нашёл - скрипт работает прекрасно..но одно НО - чисто алгоритмическое.
Я определяю, что клиент "умер" по:
       my $rv = $client->recv($data, POSIX::BUFSIZ, 0);
        unless (defined($rv) && length $data)
но после этого вызывать
request - бессмысленно recv всё забирает...как по другому определить статус сокета, что бы и овцы сыты и волки целы то есть что бы и реквест получать и вовремя узнавать о "падении" клиента?
Название: Ошибка в коде
Отправлено: NeoNox от 26 Февраля 2004, 19:55:12
Ты исправил код и вставил use strict?
Замени его тогда в первом сообщении.
Название: Ошибка в коде
Отправлено: ZMeY от 26 Февраля 2004, 20:02:57
да я уже снял старый вопрос новый:
как определить дисконнект сокета, не используя чтение буфера?
Название: Ошибка в коде
Отправлено: NeoNox от 27 Февраля 2004, 01:07:41
А я еще не снял старый вопрос.
Тебе шашечки или ехать? Если шашечки то тебе в форум по изготовлению скриптов. Если ехать - отвечай на вопросы.
На данном этапе я хочу увидеть рабочий код.
Вторым я тебя спрошу про эти строки:
        my $data = \'\';
        my $rv = $client->recv($data, POSIX::BUFSIZ, 0);
        unless (defined($rv) && length $data)
и хочу узнать нафига тебе unless если length $data всегда равен 0?
Ты понимаеш что вообще происходит в этом коде?
Название: Ошибка в коде
Отправлено: ZMeY от 27 Февраля 2004, 06:57:49
Цитировать

Вторым я тебя спрошу про эти строки:
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...Хотя честно говоря этот участок мне мало понятен. Поэтому я хочу его заменить.
Название: Ошибка в коде
Отправлено: NeoNox от 27 Февраля 2004, 13:27:34
Вот мне интересно почему тебе на том форуме не показали как \'это\' заставить работать? Мастера блин...
Замени блок на
unless (defined($rv) && length $data) {
 disconnect($client);
 next;
}

И что за else там стоит после unless?

Значит так, или я тебе даю рабочий код чата под nix и эту тему к чертям закрываю, либо ты пишеш сюда код с комментариями что каждая строка делает в цикле while(1). Выбирай.
Название: Ошибка в коде
Отправлено: ZMeY от 27 Февраля 2004, 15:49:35
NeoNox я прокоментирую каждую строку - ок?
Название: Ошибка в коде
Отправлено: NeoNox от 27 Февраля 2004, 16:17:32
конечно
Название: Ошибка в коде
Отправлено: NeoNox от 27 Февраля 2004, 16:28:22
кстати, посмотри вот сюда - http://poe.perl.org/?Listing.evolution.select учиться лучше на правильном коде.
Название: Ошибка в коде
Отправлено: ZMeY от 27 Февраля 2004, 16:31:15
Код:

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 от 27 Февраля 2004, 17:27:16
То что тебя интересует это чтение из ранее установленного сокета.
Название: Ошибка в коде
Отправлено: ZMeY от 27 Февраля 2004, 21:12:46
NeoNox я знаю, что это чтение - я не совсем пониаю, как с его помощью определяется статус клиента...ну да это и не важно!

Как заменить этот код другими кодом, который однозначно будет определять - на связи клиент или уже отключился