Newbie needs help with IO::Socket (maybe IO::Select)

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View
Hi all

I'm playing around with IO::Socket and try to build a small Client/Server

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::Dumper;

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();

#Pruefen ob ein Client connectet
while(1) {
 my ($neu_lesbare) = IO::Select->select($lesbar, undef, undef, undef);

 foreach $socket(@) {
  if ($socket == $main_socket) {
   #Neue Verbindung kommt rein...
   my $neues_socket = $socket->accept();
  else {
   # Hier drin passiert Zeug mit dem Client
   my $buf = <$socket>;
   if ($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";
    close ($socket);

    foreach (keys %users) {
     if ($socket eq $users) {
      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

 if (($usr eq "boerni") or ($usr eq "admin")) {
  if ($users) {
   write2socket ($socket,"User $usr ist bereits verbunden
  else {
   write2socket ($socket,"Verbindung mit User $usr akzeptiert");
   $users = $socket;
   $users = $rem_host;
   $users = $rem_port;
 else {
  write2socket ($socket, "Verbindung abgelehnt");
  close ($socket);

 #print Dumper \%users;
 #print Dumper \%sockets;

 foreach (keys %users) {
  my $handle = $users;
  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();

while (<>) {
 if ($_ eq "connect") {
 elsif ($_ eq "man_move") {
 elsif ($_ eq "check") {
 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:

 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);

 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

Re: Newbie needs help with IO::Socket (maybe IO::Select)

Quoted text here. Click to load it

Why would another client connecting to the server kick off the first one?
Wouldn't it be easier to fix this problem than to deal with the

If the server has gone away, the client will realize this next time it
tries to communicate with it.  While I guess it might be nice to know
immediately that the server has gone away, plenty of very good
client-server apps don't detect server failure until the next time it tries
to communicate. I'd need a very compelling reason not to follow this
paradigm for my own clients.

Quoted text here. Click to load it

You need to add STDIN (or whatever you use to communicate with the User)
into the IO::Select, too.  This means you probably have to use sysread,
rather than <>, to read from STDIN.


Quoted text here. Click to load it

You are mixing buffered IO with select.  This is rather dangerous.  If
the client can ever print two (or more) lines into $socket in quick
succession, then this code might cause both of them to be read into the
perl internal buffer, but only one of them to be returned from there
into $buf.  The next line just sits in the internal buffer, where it will
not trigger IO::Select and hence not get read.  The client won't send any
more lines (which would trigger IO::Select) because it is waiting for a
response to the last line it sent, and the server will never respond to
that line because it doesn't know that it is there.  Deadlock.

I think IO::Select (or some subclass thereof) should return readable for
any file handle that has data sitting in the perl internal buffer, in
addition to the handles that have data (or eof) in the system's buffers.  I
haven't quite figured out how to implement that.  All of those globs and
glob refs and PerlIO layers and tied handles and scalar masquerading as
handles are just too much for me.


-------------------- http://NewsReader.Com/ --------------------
The costs of publication of this article were defrayed in part by the
payment of page charges. This article must therefore be hereby marked
advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate
this fact.

Re: Newbie needs help with IO::Socket (maybe IO::Select)

Thank you very much for your answer!

Quoted text here. Click to load it

I bought one of those USB-Missilelaunchers. So what I'm trying to do is,
writing a client/server app, so everyone in my team can use it. But since
I'm the one who bought it, I wan't to be able to kick anyone connected, when
I connect :-)
But I guess it's ok, when they get the message the next time they try to
send any command to the launcher.

Quoted text here. Click to load it

Thanks... I'm going to read up on this...

Site Timeline