B
Boerni
Hi all
I'm playing around with IO::Socket and try to build a small Client/Server
App.
The Serverpart is working as it's supposed to, but I have some problems with
the Clientpart.
So I have a couple of Questions:
1. How can a Client react to a Servermessage (Server prints to Socket), when
it's not expecting a Servermessage (For example another client connects to
the server and kicks the first one or the server is beeing shutdown). If I
use the IO::Select approach like in the Serverpart, the Client is blocked
and the User can't interact with it anymore.
2. Why does $socket->connected still return the peer-address, eventhough the
server is shutdown?
I'm sure there is a solution for this (probably by using IO::Select), but I
can't find any examples of Clientcode using this.
Here's what I have (simplified... the "real" Client is using Tk):
------ Star Serverpart -------
#!perl -w
use strict;
use IO::Socket;
use IO::Select;
use Data:umper;
our $socket;
my %users;
my $port = 9901;
#Socket erstellen
my $main_socket = IO::Socket::INET->new(LocalPort => $port,
Type => SOCK_STREAM,
Reuse => 1,
Listen => 1) or die "Kann kein
TCP-Server an Port $port sein: @!\n";
my $lesbar = new IO::Select();
$lesbar->add($main_socket);
#Pruefen ob ein Client connectet
while(1) {
my ($neu_lesbare) = IO::Select->select($lesbar, undef, undef, undef);
foreach $socket(@{$neu_lesbare}) {
if ($socket == $main_socket) {
#Neue Verbindung kommt rein...
my $neues_socket = $socket->accept();
$lesbar->add($neues_socket);
}
else {
# Hier drin passiert Zeug mit dem Client
my $buf = <$socket>;
if ($buf) {
chomp($buf);
my @args = split(',', $buf);
if ($args[0] eq "AUTH") {
auth($args[1], $args[2]);
}
else {
print "Nicht unterstuetzter Command\n";
}
}
else {
# print "Client hat Socket geschlossen\n";
$lesbar->remove($socket);
close ($socket);
foreach (keys %users) {
if ($socket eq $users{$_}{socket}) {
print localtime().": User [$_] disconnected\n";
delete $users{$_};
}
}
}
}
}
}
#---- Subroutinen ---#
sub write2socket {
my $socket = shift;
my $text = shift;
my $length = sprintf("%04d", length($text));
my $newstring = $length.$text;
print $socket "$newstring";
}
sub auth {
my $usr = shift;
my $pass = shift;
#Na wer ists denn...
my $iaddr = inet_ntoa($socket->peeraddr());
my $rem_host = gethostbyaddr($socket->peeraddr(), AF_INET);
my $rem_port = $socket->peerport();
print localtime().": Neue Verbindung von Host: $rem_host
[$iaddr:$rem_port]\n";
if (($usr eq "boerni") or ($usr eq "admin")) {
if ($users{$usr}) {
write2socket ($socket,"User $usr ist bereits verbunden
($users{$usr}{host}:$users{$usr}{port})");
}
else {
write2socket ($socket,"Verbindung mit User $usr akzeptiert");
$users{$usr}{socket} = $socket;
$users{$usr}{host} = $rem_host;
$users{$usr}{port} = $rem_port;
}
}
else {
write2socket ($socket, "Verbindung abgelehnt");
$lesbar->remove($socket);
$socket->shutdown(2);
close ($socket);
}
#print Dumper \%users;
#print Dumper \%sockets;
foreach (keys %users) {
my $handle = $users{$_}{socket};
write2socket($handle, "User $usr hat sich verbunden");
}
}
------ End Serverpart -------
------ Star Clientpart -------
#!perl -w
use strict;
use IO::Socket;
use IO::Select;
my $socket;
my $usr = "admin";
my $pw = "pass";
my $remote_host = 'localhost';
my $remote_port = 9901;
my $svrmsg;
my $lesbar = new IO::Select();
$lesbar->add($socket);
while (<>) {
chomp;
if ($_ eq "connect") {
connect2server();
}
elsif ($_ eq "man_move") {
man_move("up");
}
elsif ($_ eq "check") {
check_status();
}
else {
print "Nicht unterstuetzt\n";
}
}
#---- Subroutinen ----#
sub connect2server {
#---- Socket aufbauen ----#
$socket = IO::Socket::INET->new(PeerAddr => $remote_host,
PeerPort => $remote_port,
Proto => "tcp",
Type => SOCK_STREAM)
or die "Konnte Verbindung zu $remote_host:$remote_port nicht herstellen:
@!\n";
print $socket "AUTH,$usr,$pw\n";
$svrmsg = read_from_sock($socket);
print "FROM SERVER: [$svrmsg]\n";
}
sub man_move {
return if ! $socket;
my $direction = shift;
print $socket "man_move,$direction\n";
$svrmsg = read_from_sock($socket);
print "FROM SERVER: $svrmsg\n";
}
sub read_from_sock {
my $socket = shift;
my $length = 0;
my $data;
$socket->read($length, 4);
$socket->read($data,$length);
return $data;
}
sub check_status {
if (! $socket) {
print "CHECK: No socket\n";
}
elsif ($socket->connected()) {
print "CHECK: Connected with ".inet_ntoa($socket->peeraddr())."\n";
}
else {
print "CHECK: Not connected";
}
}
------ End Clientpart -------
Thanks a lot
I'm playing around with IO::Socket and try to build a small Client/Server
App.
The Serverpart is working as it's supposed to, but I have some problems with
the Clientpart.
So I have a couple of Questions:
1. How can a Client react to a Servermessage (Server prints to Socket), when
it's not expecting a Servermessage (For example another client connects to
the server and kicks the first one or the server is beeing shutdown). If I
use the IO::Select approach like in the Serverpart, the Client is blocked
and the User can't interact with it anymore.
2. Why does $socket->connected still return the peer-address, eventhough the
server is shutdown?
I'm sure there is a solution for this (probably by using IO::Select), but I
can't find any examples of Clientcode using this.
Here's what I have (simplified... the "real" Client is using Tk):
------ Star Serverpart -------
#!perl -w
use strict;
use IO::Socket;
use IO::Select;
use Data:umper;
our $socket;
my %users;
my $port = 9901;
#Socket erstellen
my $main_socket = IO::Socket::INET->new(LocalPort => $port,
Type => SOCK_STREAM,
Reuse => 1,
Listen => 1) or die "Kann kein
TCP-Server an Port $port sein: @!\n";
my $lesbar = new IO::Select();
$lesbar->add($main_socket);
#Pruefen ob ein Client connectet
while(1) {
my ($neu_lesbare) = IO::Select->select($lesbar, undef, undef, undef);
foreach $socket(@{$neu_lesbare}) {
if ($socket == $main_socket) {
#Neue Verbindung kommt rein...
my $neues_socket = $socket->accept();
$lesbar->add($neues_socket);
}
else {
# Hier drin passiert Zeug mit dem Client
my $buf = <$socket>;
if ($buf) {
chomp($buf);
my @args = split(',', $buf);
if ($args[0] eq "AUTH") {
auth($args[1], $args[2]);
}
else {
print "Nicht unterstuetzter Command\n";
}
}
else {
# print "Client hat Socket geschlossen\n";
$lesbar->remove($socket);
close ($socket);
foreach (keys %users) {
if ($socket eq $users{$_}{socket}) {
print localtime().": User [$_] disconnected\n";
delete $users{$_};
}
}
}
}
}
}
#---- Subroutinen ---#
sub write2socket {
my $socket = shift;
my $text = shift;
my $length = sprintf("%04d", length($text));
my $newstring = $length.$text;
print $socket "$newstring";
}
sub auth {
my $usr = shift;
my $pass = shift;
#Na wer ists denn...
my $iaddr = inet_ntoa($socket->peeraddr());
my $rem_host = gethostbyaddr($socket->peeraddr(), AF_INET);
my $rem_port = $socket->peerport();
print localtime().": Neue Verbindung von Host: $rem_host
[$iaddr:$rem_port]\n";
if (($usr eq "boerni") or ($usr eq "admin")) {
if ($users{$usr}) {
write2socket ($socket,"User $usr ist bereits verbunden
($users{$usr}{host}:$users{$usr}{port})");
}
else {
write2socket ($socket,"Verbindung mit User $usr akzeptiert");
$users{$usr}{socket} = $socket;
$users{$usr}{host} = $rem_host;
$users{$usr}{port} = $rem_port;
}
}
else {
write2socket ($socket, "Verbindung abgelehnt");
$lesbar->remove($socket);
$socket->shutdown(2);
close ($socket);
}
#print Dumper \%users;
#print Dumper \%sockets;
foreach (keys %users) {
my $handle = $users{$_}{socket};
write2socket($handle, "User $usr hat sich verbunden");
}
}
------ End Serverpart -------
------ Star Clientpart -------
#!perl -w
use strict;
use IO::Socket;
use IO::Select;
my $socket;
my $usr = "admin";
my $pw = "pass";
my $remote_host = 'localhost';
my $remote_port = 9901;
my $svrmsg;
my $lesbar = new IO::Select();
$lesbar->add($socket);
while (<>) {
chomp;
if ($_ eq "connect") {
connect2server();
}
elsif ($_ eq "man_move") {
man_move("up");
}
elsif ($_ eq "check") {
check_status();
}
else {
print "Nicht unterstuetzt\n";
}
}
#---- Subroutinen ----#
sub connect2server {
#---- Socket aufbauen ----#
$socket = IO::Socket::INET->new(PeerAddr => $remote_host,
PeerPort => $remote_port,
Proto => "tcp",
Type => SOCK_STREAM)
or die "Konnte Verbindung zu $remote_host:$remote_port nicht herstellen:
@!\n";
print $socket "AUTH,$usr,$pw\n";
$svrmsg = read_from_sock($socket);
print "FROM SERVER: [$svrmsg]\n";
}
sub man_move {
return if ! $socket;
my $direction = shift;
print $socket "man_move,$direction\n";
$svrmsg = read_from_sock($socket);
print "FROM SERVER: $svrmsg\n";
}
sub read_from_sock {
my $socket = shift;
my $length = 0;
my $data;
$socket->read($length, 4);
$socket->read($data,$length);
return $data;
}
sub check_status {
if (! $socket) {
print "CHECK: No socket\n";
}
elsif ($socket->connected()) {
print "CHECK: Connected with ".inet_ntoa($socket->peeraddr())."\n";
}
else {
print "CHECK: Not connected";
}
}
------ End Clientpart -------
Thanks a lot