Модераторы: korob2001, ginnie
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> проблема с пониманием логики select, socket 
:(
    Опции темы
e7x
Дата 11.6.2007, 22:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 24.4.2007

Репутация: нет
Всего: нет



ребята, помогите, весь мозг сломал! хоть дубиной меня бейте, никак не могу понять логику работы select для неблокирущих сокетов... 
код я предельно упростил, для концентрации на сути проблемы

$wvec, $rvec, $evec - векторы с установленными битами для обработки действий на соотв. сокетах
$url - глобальный адрес, который нам нужен через прокси
$host - хост

программа иногда вываливается без сообщений об ошибке и видимых причин во время попытки записать что-нибудь в готовый для записи сокет syswrite'ом.

таким образом, код получается рабочий, но непонятным образом глючный...

вот код, место вылета отмечено в комментариях:
Код

        if(socket($sock, AF_INET, SOCK_STREAM, getprotobyname('tcp'))) {
            my $ip = inet_aton($proxy);
            my $paddr = sockaddr_in($port, $ip);
            setsockopt($sock, SOL_SOCKET, SO_SNDTIMEO, $config->{timeout});
            setsockopt($sock, SOL_SOCKET, SO_RCVTIMEO, $config->{timeout});
            fcntl($sock, F_SETFL, O_NONBLOCK);
            syswrite STDOUT, "connecting to $proxy:$port\n";
            connect($sock, $paddr);
        
            vec($rvec, fileno($sock), 1) = 0;
            vec($wvec, fileno($sock), 1) = 1;
            $evec = $rvec | $wvec;
            
            while (select($rovec=$rvec, $wovec=$wvec, $eovec=$evec, $config->{timeout})) {
                if (vec($wovec, fileno($sock), 1)) {
                    # готов для записи
                    syswrite STDOUT, "posting...\n";
                    # !!!!
                    # !!!! ВОТ ТУТ ВЫЛЕТАЕТ
                    # !!!!
                    syswrite $sock, "POST $url HTTP/1.0\nHost: $host\nContent-Type: application/x-www-form-urlencoded\nContent-Length: $cl\nConnection: close\n\n$postcontent";
                    syswrite STDOUT, "posted\n";
                    
                    vec($rvec, fileno($sock), 1) = 1;
                    vec($wvec, fileno($sock), 1) = 0;
                    $evec = $rvec | $wvec;
                } elsif (vec($rovec, fileno($sock), 1)) {
                    # готов для чтения
                    syswrite STDOUT, "reading reply...\n";
                    my $buf;
                    while (my $bytesread = sysread $sock, $buf, 512) {
                        print $buf;
                    }
                    syswrite STDOUT, "read\n";
                    
                    vec($rvec, fileno($sock), 1) = 0;
                    vec($wvec, fileno($sock), 1) = 0;
                    $evec = $rvec | $wvec;
                } else {
                    # ошибочка
                    syswrite STDOUT, "socket error\n";
                }
            }
            syswrite STDOUT, "select timeout or error\n";
        } else {
            syswrite STDOUT, "cannot create socket\n";
        }


сдается мне, я неверно понял логику работы select, и, собственно, надеюсь на вашу помощь
повторюсь, сокеты неблокирующие (Blocking => 0)

===========

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

Итак, решение проблемы:
нужно было перед каждым ридом/врайтом сокета проверять getsockopt($sock, SOL_SOCKET, SO_ERROR)

кому интересно, вот финальный код:
Код

            while (select($rovec=$rvec, $wovec=$wvec, $eovec=$evec, $config->{timeout})) {
                if (vec($wovec, fileno($sock), 1)) {
                    # готов для записи
                    my $serr = getsockopt($sock, SOL_SOCKET, SO_ERROR);
                    if ($serr ne "\0\0\0\0") { 
                        .... - с сокетом что-то случилось, писать нельзя
                    } else {
                        ... - тут спокойно пишем
                    }                    
                    vec($rvec, fileno($sock), 1) = 1;
                    vec($wvec, fileno($sock), 1) = 0;
                    $evec = $rvec | $wvec;
                } elsif (vec($rovec, fileno($sock), 1)) {
                    # готов для чтения
                    my $serr = getsockopt($sock, SOL_SOCKET, SO_ERROR);
                    if ($serr ne "\0\0\0\0") { 
                        .... - с сокетом что-то случилось, читать нельзя
                    } else {
                        ... - тут спокойно читаем
                    }                    
                    
                    vec($rvec, fileno($sock), 1) = 0;
                    vec($wvec, fileno($sock), 1) = 0;
                    $evec = $rvec | $wvec;
                }
            }


всем спасибо и доброе утро =)
плодотворная ночка выдалась

Это сообщение отредактировал(а) e7x - 12.6.2007, 04:27
PM MAIL   Вверх
nitr
Дата 11.6.2007, 22:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник Клуба
Сообщений: 2543
Регистрация: 10.2.2006
Где: Россия :)

Репутация: 37
Всего: 84



Посоветую вам использовать и прочесть IO::Select
perldoc IO::Select , существенно облегчит вам жизнь.

Добавлено через 2 минуты и 16 секунд
и у вас некое запутанное понимаение select, даже по доке иначе:
Цитата

select
Returns the currently selected filehandle. Sets the current default filehandle for output, if FILEHANDLE is supplied. This has two effects: first, a write or a print without a filehandle will default to this FILEHANDLE. Second, references to variables related to output will refer to this output channel. For example, if you have to set the top of form format for more than one output channel, you might do the following: 
    select(REPORT1);
    $^ = 'report1_top';
    select(REPORT2);
    $^ = 'report2_top';

FILEHANDLE may be an expression whose value gives the name of the actual filehandle. Thus:
    $oldfh = select(STDERR); $| = 1; select($oldfh);

Some programmers may prefer to think of filehandles as objects with methods, preferring to write the last example as:
    use IO::Handle;
    STDERR->autoflush(1);



--------------------
PM   Вверх
e7x
Дата 11.6.2007, 22:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 24.4.2007

Репутация: нет
Всего: нет



nitr, селекта в перле две штуки ;) 
первая - описанная вами
вторая - та, что использую я 

спасибо, сейчас IO::Select подергаю

Добавлено через 10 минут и 59 секунд
ой, IO::Select не получится использовать. метод can_read возвращает массив хендлов, а метод select 3 ссылки на массив хендлов. мне же не просто хендлы нужны, мне еще нужно знать какой адрес успешно присоединился smile 

Это сообщение отредактировал(а) e7x - 11.6.2007, 22:24
PM MAIL   Вверх
e7x
Дата 12.6.2007, 04:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 18
Регистрация: 24.4.2007

Репутация: нет
Всего: нет



проблема решена, см. первый пост
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Perl"
korob2001
sharq
  • В этом разделе обсуждаются общие вопросы по языку Perl
  • Если ваш вопрос относится к системному программированию, задавайте его здесь
  • Если ваш вопрос относится к CGI программированию, задавайте его здесь
  • Интерпретатор Perl можно скачать здесь ActiveState, O'REILLY, The source for Perl
  • Справочное руководство "Установка perl-модулей", можно скачать здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0672 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.