server:
#! /usr/bin/perl
use warnings;
use strict;
use IO::Socket;
use POE qw /Wheel::ListenAccept Wheel::ReadWrite/;
# 创建监听Socket及处理Session
POE::Session->create
( inline_states =>
{ _start => \&start_server,
new_connected => \&new_connected,
client_input => \&client_input,
}
);
POE::Kernel->run;
sub start_server {
my ($kernel, $heap) = @_[KERNEL, HEAP];
my $server = IO::Socket::INET->new
( LocalPort => 8000,
Listen => 16,
Reuse => "yes",
) or die "can't make server socket: $@\n";
$heap->{server} = POE::Wheel::ListenAccept->new
( Handle => $server,
AcceptEvent => 'new_connected',
);
}
sub new_connected {
my ($heap, $client) = @_[HEAP, ARG0];
my $wheel = POE::Wheel::ReadWrite->new
( Handle => $client,
InputEvent => 'client_input',
);
# 系统中每个wheel的ID是唯一的
$heap->{client}->{ $wheel->ID } = $wheel;
}
sub client_input {
my ($heap, $input, $wid) = @_[HEAP, ARG0, ARG1];
print $input;
# 广播数据。如果愿意,可以屏蔽掉$wid,即发送消息的客户端
map { $heap->{client}->{$_}->put( $input ) } keys %{$heap->{client}};
}
client:
#! /usr/bin/perl
use warnings;
use strict;
use IO::Socket;
use POE qw /Wheel::SocketFactory Wheel::ReadWrite Wheel::ReadLine/;
POE::Session->create
( inline_states =>
{ _start => \&start_chat,
connected => \&connected,
connect_fail => \&connect_fail,
server_input => \&server_input,
user_input => \&user_input,
}
);
POE::Kernel->run;
sub start_chat {
my $wheel = POE::Wheel::SocketFactory->new
( RemoteAddress => 'localhost',
RemotePort => 8000,
SuccessEvent => "connected",
FailureEvent => "connect_fail",
);
$_[HEAP]->{server} = $wheel;
}
sub connected {
my ($kernel, $heap, $socket) = @_[KERNEL, HEAP, ARG0];
my $wheel = POE::Wheel::ReadWrite->new
( Handle => $socket,
InputEvent => "server_input",
ErrorEvent => "error_happened",
);
$heap->{server} = $wheel;
my $console = POE::Wheel::ReadLine->new
( InputEvent => 'user_input'
);
# 告诉ReadLine监控终端
$console->get( 'input your message, bye to quit: ');
$heap->{console} = $console;
}
sub connect_fail {
delete $_[HEAP]->{server};
}
sub server_input {
my ($heap, $input) = @_[HEAP, ARG0];
# 如果使用print "$input\n"会搞乱终端
$heap->{console}->put( $input );
}
sub user_input {
my ($heap, $input) = @_[HEAP, ARG0];
if ($input =~ /(quit)|(exit)|(bye)/i) {
delete $heap->{server};
delete $heap->{console};
return;
}
# 发送到服务端
$heap->{server}->put( $input );
# 继续监控终端
$heap->{console}->get( 'input your message, bye to quit: ');
}