Bruce32903 has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I am trying to get started with IO::Multiplex. I have done some Internet searches and found an example in a Perl book and I think I understand it well enough to get started with some sample code (the same sample code most web sites copy and reuse).

My Chat Server code is here
#!/usr/bin/perl -w # FILE: chatserver_02.pl # FROM: http://manpages.ubuntu.com/manpages/maverick/man3/IO::Multiple +x.3pm.html use IO::Socket; use IO::Multiplex; my $mux = new IO::Multiplex; # Create a listening socket my $sock = new IO::Socket::INET(Proto => 'tcp', LocalPort => shift || 2300, Listen => 4) or die "socket: $@"; # We use the listen method instead of the add method. $mux->listen($sock); $mux->set_callback_object(__PACKAGE__); $mux->loop; sub mux_input { my $package = shift; my $mux = shift; my $fh = shift; my $input = shift; # The handles method returns a list of references to handles which # we have registered, except for listen sockets. foreach $c ($mux->handles) { print $c $$input; } $$input = ''; }


My Chat Client Code is here:
#!/usr/bin/perl -w # FILE: chatclient_02.pl # FROM: http://manpages.ubuntu.com/manpages/maverick/man3/IO::Multiple +x.3pm.html use IO::Socket; use IO::Multiplex; # Create a multiplex object my $mux = new IO::Multiplex; # Connect to the host/port specified on the command line, # or localhost:23 my $sock = new IO::Socket::INET(Proto => 'tcp', PeerAddr => shift || 'local +host', PeerPort => shift || 23) or die "socket: $@"; # add the relevant file handles to the mux $mux->add($sock); $mux->add(\*STDIN); # We want to buffer output to the terminal. This prevents +the program # from blocking if the user hits CTRL-S for example. $mux->add(\*STDOUT); # We're not object oriented, so just request callbacks to t +he # current package $mux->set_callback_object(__PACKAGE__); # Enter the main mux loop. $mux->loop; # mux_input is called when input is available on one of # the descriptors. sub mux_input { my $package = shift; my $mux = shift; my $fh = shift; my $input = shift; # Figure out whence the input came, and send it on to t +he # other place. if ($fh == $sock) { print STDOUT $$input; } else { print $sock $$input; } # Remove the input from the input buffer. $$input = ''; } # This gets called if the other end closes the connection. sub mux_close { print STDERR "Connection Closed\n"; exit; }
When I run the server followed by the client the client gets a "Connection Refused" error message. Here a a few notes I made.

Started server. No packets posted on WireShark. Server window does not post any messages and just sits there as expected (no command prompt).

Start client. Get 2 WireShark packets and one error message in the client window. Server terminal window is still just sitting there with no messages and no new command prompt (as expected). Client window returned to a command prompt.

The client error message is: socket: IO::Socket::INET: connect: Connection refused at ./chatclient_02.pl line 11.

When I looked at the port numbers I thought it was odd that one was 23 and the other was 2300. Since I am just getting started I don't know if the client and server communicate back and forth on the same port or if one port is used in one direction and another port is used in the other direction.

Looking at the Perl Cookbook (Bighorn Sheep) I found a IO::Multiplex example where the server and client both used address localhost:6901. Thus I modified my code to use 6901 in both programs and I failed in a different way. My notes are here.

After making both ports 6901:

Start server. No packets posted on WireShark. Server window does not post any messages and just sits there as expected (no command prompt).

Start client. Get 3 WireShark packets and 4 error messages in the client terminal window. Server terminal window is still just sitting there with no messages and no new command prompt (as expected).

The four client error messages are:
Use of uninitialized value in unpack at /usr/share/perl5/IO/Multiplex.pm line 352.
Use of uninitialized value in numeric eq (==) at /usr/share/perl5/IO/Multiplex.pm line 352.
Use of uninitialized value in unpack at /usr/share/perl5/IO/Multiplex.pm line 352.
Use of uninitialized value in numeric eq (==) at /usr/share/perl5/IO/Multiplex.pm line 352.

I typed the word "client" several times in the client window, hit return and got 4 packets posted in WireShark. The first packet was from port 55474 (where did this come from?) to port 6901 and it contained the word "client". The next two were from 6901 to 55474 and the second of these contained the word "client". The last of these four was from 55474 to 6901.

I typed the word "SERVER" several times in the server window. The words appeared in the server window but there were no packets reported by WireShark and the client window did not change.

Thus I am stuck. I don't know if the port number should be the same (as in the book) or different (as in the Internet example). I don't know if the problem is in my code or if one of the attempts had good code but something in my Linux box is blocking the port.

Does anyone have any suggestions?

Thanks,
Bruce

Replies are listed 'Best First'.
Re: Trying to get started with IO::Multiplex
by zentara (Cardinal) on Jan 16, 2011 at 15:49 UTC
    When I looked at the port numbers I thought it was odd that one was 23 and the other was 2300

    You answered your own question. They must be the same.

    Sockets are bidirectional, but if the programs setup additional sockets, it should be invisible to you, the end user. See Simple bi-directional forking commandline client. What is usually done, is a forked or threaded client is used, one fork for reading the socket, the other for writing.

    Why are you using IO::Multiplex? IO::Select is not hard. See Problem with IO::Select for example.

    Also see perl socket examples for a basic intro to how it all works without IO::Multiplex. Look at IO Multiplexing server

    Those examples explain the details, but it is often easier to use modules like IO::Select and IO::Socket instead of the raw Perl functions, and you can google for many code snippets previously posted.

    Good luck.


    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh
      Thank you for your reply.

      I was typing my follow-up while you added your reply. I was not ignoring your reply.

      My main reason for using IO::Multiplex was that someone told me that it was a much easier way to go. For my first attempt easy sounded good. Except for the four client error messages I now have my first attempt under my belt. Thus, it is a good time (after a little mandatory yard work) to review your comments, review what I have done, review the postings I have used and try to gain a little wisdom as a person with one small program under my belt.

      Having something that works makes it easier for me to go through Perl documentation/examples and learn more about Perl and WireShark one issue at a time. Previously, having nothing working made it hard to zero in on anything.

      Thanks for your suggestions.

      Still looking for suggestions/comments on the error messages.

      Bruce
Re: Trying to get started with IO::Multiplex
by Bruce32903 (Scribe) on Jan 16, 2011 at 15:56 UTC
    After sleeping on this problem I have made quite a bit of progress. Having yet another sample program from the Internet that didn't work was frustrating and I got a bit of tunnel vision. Here is what I have figured out and where I am at now:

    1) The port number listed in the server and client code needs to be the same.

    2) The server binds to the port and listens on it.

    3) The client binds to a port that is random appearing to me. The client will send to the port listed in the code and listen on the random appearing port number.

    4) I misunderstood what the code should do and got a case of tunnel vision. I didn't pay attention to the easy parts of the code. I thought that the server and the client would chat with each other (like sample code from my past). This code does not do that. This code has the server echo out everything to all clients. Thus, with multiple clients running in multiple terminal windows I have clients chatting with each other.

    5) I still don't understand why I get the four client error messages as listed in my initial posting. They are all in the Multiplex.pm module. Later I can try to look at the module code but I suspect that it is well above beginner level.

    Any ideas on the error messages?

    Thanks,
    Bruce
      The four client error messages are: Use of uninitialized value in unpack at /usr/share/perl5/IO/Multiplex. +pm line 352. Use of uninitialized value in numeric eq (==) at /usr/share/perl5/IO/M +ultiplex.pm line 352. Use of uninitialized value in unpack at /usr/share/perl5/IO/Multiplex. +pm line 352. Use of uninitialized value in numeric eq (==) at /usr/share/perl5/IO/M +ultiplex.pm line 352.
      Any ideas on the error messages?

      It sounds like your problem is in the module at line 352. :-)

      So use a local copy of the module,( or even edit the module as root for testing), and see what is getting handed off at line 352.

      My ESP guesses the Multiplex module expects an array and is only getting a single value? You have to dig in and see.

      OR.... go for a more standard solution using IO::Select or forked/threaded servers. Google for many previously posted code examples or visit the tutorials here at Perlmonks.


      I'm not really a human, but I play one on earth.
      Old Perl Programmer Haiku ................... flash japh
        I will take a look at line 352 but I suspect that IO::Select will look better now that I have something working. So far my only push toward IO::Multiplex was "THEY SAID" that it was easier. I have been around long enough to know that I should be careful with any quote of Mr./Mrs. They.

        Thank you,
        Bruce