![]() |
Модераторы: korob2001, ginnie |
![]() ![]() ![]() |
|
zerg13new |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 25.3.2010 Репутация: нет Всего: нет |
народ, ОЧЕНЬ нужна помощь, так как я уже устал и не понимаю совсем ничего
пишу в linux на perl и цель программы такова: создать сервер, кот принимал бы соединения от клиентов и мог посылать любому выбранном на сервере клиенту сообщение. пишу под консоль, итак код той части что не получается: # my server 2 # 2010.03.05 3 4 #!/usr/bin/perl -w 5 6 use strict; 7 use IO::Socket; 8 #use Thread; 9 use threads; 10 use threads::shared; 11 #use POSIX 'WNOHANG'; # for SIGNAL 12 use constant BUFSIZE => 1024; 13 14 15 my %clients :shared; 16 my( $addr, $port ); 17 18 19 $addr = &get_ip(); # get IP from interface 20 21 # get port 22 print "enter port: "; 23 while( <STDIN> ) { 24 chomp($_); 25 $port = $_; 26 if ( /[0-9]{4,5}/ && $_ > 1024 ) { last; } 27 print "either wrong value or port is deny, enter new value: "; 28 } 29 30 my $server = IO::Socket::INET -> new( LocalAddr => $addr, 31 LocalPort => $port, 32 Listen => 255, 33 Type => SOCK_STREAM, 34 Proto => 'tcp', 35 Reuse => 1 ); 36 die "can't create, bind or listen: $!\n" unless $server ; 37 print "socket OK\n bind OK\n listen OK\n Server started at $addr:$port\n"; 38 warn "Server ready. Waiting for connections... \n"; 39 40 threads -> create( \&to_client ) || die "$! \n"; # STDIN 41 42 # start threads to treat querys 43 while( my $client = $server -> accept ) { 44 my $client_ip = $client -> peerhost(); 45 my $client_port = $client -> peerport(); 46 my $tmp = "$client_ip:$client_port"; 47 48 %clients = { %clients , "$client_ip:$client_port" => $client } ; # add new socket to %client ИМЕННО ЗДЕСЬ # здесь никакого кода, просто пустота 56 syswrite( $clients{ "$client_ip:$client_port" }, "hi, how are you??") || die ":$! _ $@"; 57 #foreach my $q ( keys %clients ) { print "debug0: $q\n"; } 58 print "got a connection from: $client_ip:$client_port $client\n"; 59 $client -> autoflush; 60 61 threads -> create( \&from_client, $client, $client_ip, $client_port ) || die "$! \n"; #STDOUT 62 63 } 64 exit 0; 65 В итоге я получу ошибку "Invalid value for shared scalar at server.pl line 48, <STDIN> line 1." Хотелось бы прочитать совет спецов, показывающий наглядно как положить мне хэндл сокета $client в расшареный хэш %clients и как потом его оттуда правильно извлечь, чтобы он считался хэндлом. Если не сложно, то не отказался бы и от обьяснений где и почем же я балбес. Я честно пробывал множество всевозможных ссылок, разыменований, читал документацию типо ссылка на документацию по shared но ничего толкового не получилось. Это сообщение отредактировал(а) zerg13new - 25.3.2010, 16:48 |
|||
|
||||
Pfailed |
|
||||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 933 Регистрация: 19.7.2009 Репутация: 22 Всего: 39 |
Это что-то странное. Попробуйте проще:
|
||||
|
|||||
zerg13new |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 25.3.2010 Репутация: нет Всего: нет |
пробывал и так, всё равно будет ошибка при выполнении программы. Вообще как я заметил, ошибка появляется как только хэш %clients становится глобальным. То есть я делал массив хэндлов и запихивал в них хэндлы push_ом без проблем, но как только обьявлял массив shared, то тут же появлялась эта ошибка |
|||
|
||||
DurRandir |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 335 Регистрация: 27.9.2009 Репутация: 14 Всего: 17 |
>use threads;
>use threads::shared; О нет, нет, нет |
|||
|
||||
zerg13new |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 25.3.2010 Репутация: нет Всего: нет |
как насчёт обьяснить чего не нравится или есть ли какие предложения дельные ?? рассмотрю с удовольствием, а то я уже ![]() |
|||
|
||||
mvsgt |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 209 Регистрация: 27.3.2009 Репутация: 1 Всего: 1 |
"нет нет нет" работает нормально, только очень тормозит если злоупотреблять.
Почему бы не сделать простой форкающий сервер - модулей для *daemon* много. Добавлено через 3 минуты и 30 секунд
это непонятно что. и, кажется, с shared хэшами нельзя так рабоать вообще - только поэлементно. в инструкции про это что-то есть. |
|||
|
||||
zerg13new |
|
||||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 25.3.2010 Репутация: нет Всего: нет |
mvsgt,
извиняюсь, не заметил, но исправил в теме, этого конечно у меня в коде нет, это какой-то бред ) у меня так: %clients = { %clients , "$client_ip:$client_port" => $client } ; переписывание на $clients{"$client_ip:$client_port"} = $client ;
в оригинале я должен запустить этот сервер под Win, а с fork() у меня возникли какие-то проблемы с блокировками или буферизацией(только по очереди обменивались клиент и сервер) . думаешь с fork() оно будет работать лучше ?? Я не знаю разделение переменных между потоками и процессами в perl разные вещи ли !? и всё равно у меня вопрос будет " а как сделать глобальный хэш с дескрипторами!?" или вообще что-то глобальное, откуда любой процесс/поток может забрать нужный ему десриптор !? |
||||
|
|||||
mvsgt |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 209 Регистрация: 27.3.2009 Репутация: 1 Всего: 1 |
никак нельзя, я думаю. дескрипторы так не распространяются. А вот под windows как раз может и получиться - там форки тредами эмулируются. Но всё равно это муторно и ненадёжно. Надо ещё раз задачу обдумать. Может вообще нужно что-то типа comet.
|
|||
|
||||
DurRandir |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 335 Регистрация: 27.9.2009 Репутация: 14 Всего: 17 |
Основная проблема с потоками - вам _кажется_, что всё очевидно. А это не так. Вот вы помянули некие блокировки (для форка) - а для потоков они вам, видимо, и не нужны? Ну, флаг в руки. Для эффективного использования сетевого I/O - посмотрите на AnyEvent/EV - последние версии вполне собираются под strawberry perl.
|
|||
|
||||
zerg13new |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 25.3.2010 Репутация: нет Всего: нет |
DurRandir,
пока что я исхожу из того, что: 1. я могу передать в поток хэндл сокета как аргумент (вначале я просто передавал аргументом потоку именно хэндл $client и поток с ним нормально работал, следовательно в поток передать хэндл можно и он будет действительный и с ним работает ) 2. я могу создать расшаренный для потоков хэш (я указывал хэндл для хэша как "$client" и он его спокойно записывал, и поток читал из хэша, но хэндлом уже не считал(вдать изменяет контекст из-за кавычек), а потому преполагаю пункт 1) ТО наверное можно как-то совместить: создав что-то глоабльное для всех потоков, откуда потоки смогут спокойно читать, к примеру попытать хэш. И только из-за этих 2х пунктов я верю, что я просто чего-то недопонимаю и потому никак не могу записать нормально хэндл в хэш, и жду от вас победы над моей проблемой ![]() |
|||
|
||||
mvsgt |
|
|||
Бывалый ![]() Профиль Группа: Участник Сообщений: 209 Регистрация: 27.3.2009 Репутация: 1 Всего: 1 |
в линуксовом перле потоки вообще есть?
|
|||
|
||||
ginnie |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1287 Регистрация: 6.1.2008 Где: Москва Репутация: 38 Всего: 49 |
zerg13new, быстрым поиском нашел тему на PerlMonks о доступе к сокетам из потоков. Посмотрите, может найдете что-нибудь полезное. Сам я подобными задачами не занимался, так что конкретно ничем помочь не могу.
Это сообщение отредактировал(а) ginnie - 25.3.2010, 18:49 -------------------- Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг) |
|||
|
||||
zerg13new |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 25.3.2010 Репутация: нет Всего: нет |
mvsgt,
безусловно, как и в виндовой версии strawberry perl ginnie, спасибо, прочёл, попробуем обмозговать.. А вообще этот блог читается на одном дыхании как художественная книжка, здорово и эмоционально написано )) кстати вот попробывал ещё такой вариант: $clients{ "$client_ip:$client_port" } = *client; # add new socket to %client print ref($client) . "++ $client\n"; 49(номер строки) syswrite( *{$clients{"$client_ip:$client_port"}}{IO}, "hi, how are you??") || die ":$! _ $@"; вывод: IO::Socket::INET++ IO::Socket::INET=GLOB(0x8a399d8) Can't use string ("*main::client") as a symbol ref while "strict refs" in use at server.pl line 49, <STDIN> line 1. |
|||
|
||||
gcc |
|
||||
![]() Агент алкомафии ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2691 Регистрация: 25.4.2008 Где: %&й Репутация: 1 Всего: 17 |
может хэш сделать:
http://perldoc.perl.org/perlref.html#Making-References
Это сообщение отредактировал(а) gcc - 25.3.2010, 19:54 |
||||
|
|||||
zerg13new |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 25.3.2010 Репутация: нет Всего: нет |
gcc,
спасибо, сделал уже так: $clients{ "$client_ip:$client_port" } = *client{IO}; # add new socket to %client да вот только не знаю как же извлечь то хэндл (не тот либо неопределно значние либо ещё что-нибудь) для syswrite( (вот уж как здесь не изголяюсь с обзыванием), "hi, how are you??") || die ":$! _ $@"; есть идеи как излечь из хэша ?? а то он не хочет... |
|||
|
||||
gcc |
|
|||
![]() Агент алкомафии ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 2691 Регистрация: 25.4.2008 Где: %&й Репутация: 1 Всего: 17 |
может надо посмотреть... дайте вывод |
|||
|
||||
ginnie |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1287 Регистрация: 6.1.2008 Где: Москва Репутация: 38 Всего: 49 |
zerg13new, *client{IO} у Вас undef потому, что для сокета Вы используете лексическую переменную, а указанная конструкция работает только с динамическими (т.е. глобальными переменными).
-------------------- Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг) |
|||
|
||||
ramus |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 53 Регистрация: 21.2.2008 Репутация: 1 Всего: 1 |
Вы не читали книгу "Разработка сетевых программ на PERL" Линкольн Д.Штайн ?
В этой книге подробно рассматриваются все аспекты написания сервера (включая неблокирующийся ввод-вывод и демонизацию). Очень рекомендую. Почерпнете очень многое. Она у меня есть как в бумажном виде так и в электронном. Весит 20МБ. Могу выслать куда нибудь... |
|||
|
||||
zerg13new |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 25.3.2010 Репутация: нет Всего: нет |
пока кода ввода в маси и вывода выглядит так
$clients{ "$client_ip:$client_port" } = *client{IO}; # add new socket to %client syswrite( $clients{"$client_ip:$client_port"}, "hi, how are you??") || die ":$! _ $@"; gcc, Can't use an undefined value as a symbol reference at server.pl line 50, <STDIN> line 1. HASH(0x8a923f8)Perl exited with active threads: ginnie, я на сайтах читал, что так получают. примеры были таковы $scalarref = *s{SCALAR}; # Ссылка на скалярную переменную $arrayref = *s{ARRAY}; # Ссылка на массив скаляров $hashref = *s{HASH}; # Ссылка на ассоциативный массив $coderef = *s{CODE}; # Ссылка на подпрограмму $ioref = *s{IO}; # Ссылка на дескриптор файла, сокета $globref = *s{GLOB}; # Ссылка на все запись не спорю что я могу неправильно потом их вытаскивать, но я уже как только не пробую ![]() ramus, вот с неё то и начинал, причём примеры те кот он приводит с глоабыльными переменными уже не работают,потому как с версии 5.6 или более поздней глобальные переменные не разделяются просто так, для этого нужны спец модули... вот потому пришлось отказаться от этой книги, хотя как основу я её прочёл одну из первых для сетевого взаимодействия так же я прочёл/пролистал: Ellie Quigley - Perl by Example Lincoln D Stein - network programming with Perl Холзнер - Perl Специальный справочник 2001 |
|||
|
||||
ginnie |
|
||||||||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1287 Регистрация: 6.1.2008 Где: Москва Репутация: 38 Всего: 49 |
zerg13new, поясню свою мысль:
правильно работает для глобальной переменной $s
У Вас в коде используется лексическая переменная $client
а здесь уже используется глобальная переменная $client (угадайте, что записано в таблице символов для client в файловом дескрипторе - undef)
Теперь я понятно объяснил (сомневаюсь :о)? -------------------- Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг) |
||||||||
|
|||||||||
ginnie |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 1287 Регистрация: 6.1.2008 Где: Москва Репутация: 38 Всего: 49 |
По поводу конкретных советов: наиболее верным мне видится вариант из первого сообщения, похоже проблема в том, что неявный файловый дескриптор $client неразделяемый (not shared). Можно попробовать сделать его разделяемым при помощи share($client). Сработает такой вариант или нет - не знаю, особенно учитывая что в описании ни слова о indirect filehandles
Других вариантов с разделением между потоками набора неявных файловых дескрипторов я пока придумать не смог. Это сообщение отредактировал(а) ginnie - 26.3.2010, 13:35 -------------------- Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг) |
|||
|
||||
DurRandir |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 335 Регистрация: 27.9.2009 Репутация: 14 Всего: 17 |
А, мне тут пришла в голову идея. Раз уже вам очень-очень хочется это сделать на потоках, то передавайте в поток fileno($handle), а в принимающем потоке воссоздавайте объект через new_from_fd (метод из IO::Handle). Но если это под win - то надо проверять работоспособность.
Это сообщение отредактировал(а) DurRandir - 26.3.2010, 13:58 |
|||
|
||||
zerg13new |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 25.3.2010 Репутация: нет Всего: нет |
ginnie,
спасибо, всё ясно о чём вы ![]() DurRandir, почитаем о реализации такой идеи и если ничего не выйдет с более вышестоящим советом, то обязательно попробуем, спасибо |
|||
|
||||
zerg13new |
|
|||
Новичок Профиль Группа: Участник Сообщений: 11 Регистрация: 25.3.2010 Репутация: нет Всего: нет |
Проблема решена, но лично у меня только в Linux (debian ) на perl v 5.10.0:
Первоисточник, где я общался по поводу проблемы, как использовать массив хэндлов между потоками в сервере по обмена сообщениями из консоли здесь: решение проблемы на perlmonks.org В кратце суть решения проблемы такова оказалась: ## В ОСНОВНОМ потоке вот так записываем хэндлы в хэш while( my $client = $server -> accept ) { ## $clients{ "$client_ip:$client_port" } = fileno( $client ); ## здесь кладём в хэш хэндл сокета (точнее некий его заменитель, число) ## } В ДОЧЕРНЕМ потоке, которому надо работать с этими хэндлами из этого хэша: my $client; my $fileno = $clients{$clnt_ip_port}; open $client, "+<&$fileno" || die "$!\n ВСЁ народ, всем ОГРОМНОЕ спасибо за то что живо отреагировали на мои проблемы и дали дельные советы. Вы мне помогли очень-очень. Именно за такие сообщества я и обожаю инет ![]() Это сообщение отредактировал(а) zerg13new - 3.4.2010, 17:22 |
|||
|
||||
![]() ![]() ![]() |
Правила форума "Perl" | |
|
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Perl: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |