Hi there, I seem to have the same problem. I am pretty new to Perl (not new to programming). I would like to create a TCP server, so I read some stuff at the POE site and decided to use this one (POE: Cookbook - Chat Server) as a skeleton. I added a few things in order to have the sockets stuff right, before I continue developing. Here is my code:
#!/usr/bin/env perl
use warnings;
use strict;
use POE::Kernel { loop => 'POE::XS::Loop::EPoll' };
use POE qw(Component::Server::TCP);
POE::Component::Server::TCP->new(
Alias => "chat_server",
Port => 32080,
InlineStates => {send => \&handle_send},
ClientConnected => \&client_connected,
ClientError => \&client_error,
ClientDisconnected => \&client_disconnected,
ClientInput => \&client_input,
);
$poe_kernel->run();
exit 0;
my %users;
sub broadcast {
my ($sender, $message) = @_;
foreach my $user (keys %users) {
if ($user == $sender) {
$poe_kernel->post($user => send => "You $message");
}
else {
$poe_kernel->post($user => send => "$sender $message");
}
}
}
sub handle_send {
my ($heap, $message) = @_[HEAP, ARG0];
$heap->{client}->put($message);
}
sub client_connected {
my $session_id = $_[SESSION]->ID;
$users{$session_id} = 1;
broadcast($session_id, "connected.");
}
sub client_disconnected {
my $session_id = $_[SESSION]->ID;
delete $users{$session_id};
broadcast($session_id, "disconnected.");
}
sub client_error {
my $session_id = $_[SESSION]->ID;
delete $users{$session_id};
broadcast($session_id, "disconnected.");
$_[KERNEL]->yield("shutdown");
}
sub client_input {
my ($kernel, $session, $input) = @_[KERNEL, SESSION, ARG0];
my $session_id = $session->ID;
if ($input eq "/quit") { # user entered /quit
$poe_kernel->post($session_id => send => "goodbye");
$kernel->yield("shutdown");
return;
}
elsif ($input eq "/shutdown") { # user entered /shutdown
$poe_kernel->post($session_id => send => "don't do that!");
### how to do this, shutdown the server
$kernel->call('chat_server', 'shutdown');
#########################################
return;
}
broadcast($session_id, "said: $input");
}
I added:
- I use POE::XS::Loop::EPoll. I understand that in order to serve many connections, using epoll is a good thing. (How can I check whether the POE kernel is indeed using epoll or not?)
- I added functionality for users to enter commands. With the /quit command a user can leave the server. With /shutdown a user can shutdown the whole program. (Anyone can do a shutdown, security comes later.)
When I use a telnet client to connect, the /shutdown command works, because the "don't do that!" debug message is displayed. The line $kernel->call('chat_server', 'shutdown'); might be wrong because it doesn't shutdown the server program, but there isn't an error message displayed. Can anyone please tell me which instruction to use? I tried several things, like $kernel->yield('chat_server', "shutdown"); and $poe_kernel->post('chat_server, 'shutdown');. The POE::Component::Server::TCP can't help me. | [reply] [d/l] |
elsif ($input eq "/shutdown") { # user entered /shutdown
$poe_kernel->post($session_id => send => "don't do that!");
$kernel->yield("shutdown"); # <<< CLOSE MY SESSION
$kernel->call('chat_server', 'shutdown');
return;
}
That was simple. Of course this should be improved: I should close all sessions, not only mine. After sending them a message informing them about the shutdown, off course. :-)
I am used to the Lua programming language which is similar to Perl (no, I'm not provoking discussion about similarities and differences), and I'm trying to switch to Perl. With Lua and the LuaCopas module, one isn't able to stop sessions without shutting down the program itself, as far as I know. It uses a coroutine for every session. So I wasn't used to that. :-)
To me this case is closed. I'm not sure about jsarrel's problem.
About my epoll question, I'll continue my research... | [reply] [d/l] |
How can I check whether the POE kernel is indeed using epoll or not?
use POE::Kernel;
print POE::Kernel::poe_kernel_loop; # --> POE::Loop::Select
or:
use POE::Kernel { loop => 'POE::XS::Loop::EPoll' };
print POE::Kernel::poe_kernel_loop; # --> POE::XS::Loop::EPoll
and the tricky one:
use POE::Kernel;
use POE::Kernel { loop => 'POE::XS::Loop::EPoll' };
print POE::Kernel::poe_kernel_loop; # --> POE::Loop::Select
| [reply] [d/l] [select] |
Yes, I understand the Disconnected and "shutdown" and that's exactly what I'm trying to use. The problem is I can't get the Component::Client to successfully send a "shutdown" to the Component::Server. I've tried to duplicate different ways used in different examples but with no success. I've even used alias' and was still surprised that it didn't work (using exactly like the alias example in the CPAN pages). The example I have given doesn't shutdown the server, but it does illustrate my problem, I can't send a command from one component to the other (but vice versa it works fine). Perhaps I'm just getting confused with all the different sessions and heaps and trying to do make something work when it's really not even available in that particular scope?
| [reply] |