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

Why does the following not work? (errors reported after code, sorry for the huge code dump)
package MyProg; use strict; use IO::Socket; use IO::Select; use Tie::RefHash; sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = {}; bless $self, $class; $self->initialize(); return $self; } sub initialize { my $self = shift; $self->{main_socket} = new IO::Socket::INET( LocalAddr => '127.0.0.1', LocalPort => 8096, Listen => 5, Proto => 'tcp', Reuse => 1); die "Couldn't create main_socket: $!\n" unless $self->{main_socket +}; $self->{readable_handles} = new IO::Select(); $self->{readable_handles}->add($self->{main_socket}); $self->{players}={}; tie %{$self->{players}}, 'Tie::RefHash'; } sub cycle { my $self = shift; my (@new_readable) = $self->{readable_handles}->can_read(.1); foreach my $socket (@new_readable) { if ($socket == $self->{main_socket}){ #new connection my $new_socket = $socket->accept(); #Make it non-blocking #fcntl($new_socket, F_SETFL(), O_NONBLOCK()); $self->{players}->{$new_socket} = { read => 0, message => '' }; $self->{readable_handles}->add($new_socket); print "Added new connection\n"; #added to list of connections #may not have data yet } else { #check for connection closure if (not eof($socket)){ my $message = ''; my $read_count; #Read from socket #First, get size #1) Does this always work? #2) How can we get rid of the hardcoded sizeof(int)? $read_count = sysread($socket, $message, 4); if($read_count < 4) { print "Nope, can't guarantee getting message_lengt +h\n"; } else { #store length of incoming #Note that we'll have to use pack/unpack to make i +nt $self->{players}->{$socket}->{read} = unpack("l",$ +message); $self->{players}->{$socket}->{message}=""; print "Got incoming length: $message\n"; $read_count = sysread($socket, $message, $self->{p +layers}-> if($read_count < $self->{players}->{$socket}->{rea +d}){ print "Only got $read_count of $self->{players +}->{$sock } else { print "Got message: $message\n"; $self->{players}->{$socket}->{read}=0; } } } else { #closed socket, remove from list $self->{readable_handles}->remove($socket); print "Another closed socket\n"; } #end checking for socket closure } #end checking for main/non-main handle } #end foreach } 1; # THis is the server program: #!/usr/bin/perl -w use strict; use MyProg; $|=1; my $server = MyProg->new(); my $count=0; while(1) { $count++; print "Ping\n" if $count > 10; $count=0 if $count > 10; $server->cycle(); } #THis is the client program #!/usr/bin/perl -w use strict; use IO::Socket; use IO::Select; my $main_socket = new IO::Socket::INET ( PeerAddr => '127.0.0.1', PeerPort => 8096, Proto => 'tcp' ); die "Can't open client main_socket: $!\n" unless $main_socket; my $bytes_sent; my $message = pack("l","9"); print "Sending message (",unpack("L",$message),") length of ",length($ +message), $bytes_sent = syswrite( $main_socket, $message, length($message), 0); if($bytes_sent != length($message)){ warn "Problem sending message length\n"; } else { $message="Connect!!"; $bytes_sent = syswrite( $main_socket, $message, length($messag +e), 0); if($bytes_sent != length($message)){ warn "Problem sending whole message\n"; } } my $line; while ($line = <STDIN>){ if ($line=~/quit/i){ close($main_socket); last; } } #This is the server output: Ping Ping Added new connection Got incoming length: Conn Out of memory! #crashed and exited to shell #This is the client: Sending message (9) length of 4 #hangs
It appears that my length message does not get read by the server, but I'm at a lost to explain why. I've fought with it all weekend, but I've only been able to create different crash/hang conditions :(

Thanks in advance!

Replies are listed 'Best First'.
Why it didn't work
by swiftone (Curate) on Sep 11, 2000 at 22:37 UTC
    After more rummaging, I discovered the answer in perlfunc:sysread. The section is:

    It bypasses stdio, so mixing this with other kinds of reads, `print', `write', `seek', `tell', or `eof' can cause confusion because stdio usually buffers data.... There is no syseof() function, which is ok, since eof() doesn't work very well on device files (like ttys) anyway. Use sysread() and check for a return value for 0 to decide whether you're done.

    So I simply removed the "if(not eof($socket))" section, and moved the "Another closed socket" else case into the if($read_count < 4) section. Voila!

    Perldoc. It's your friend.

Re: More sockets (sob!)
by tye (Sage) on Sep 11, 2000 at 19:52 UTC

    Got incoming length: Conn

    Take a look at this:

    print unpack"l","Conn";

    I get 1852731203. Trying to allocate a buffer of that many bytes is surely the cause of your "Out of memory" error.

    You aren't writing the length of the message. Something like:

    $message="Connect!!"; my $len= pack("l",length($message)); $bytes_sent = syswrite( $main_socket, $len.$message );
            - tye (but my friends call me "Tye")
      This all sounds plausible, but my client does:
      my $message = pack("l",9); print "Sending message (",unpack("l",$message),") length of ",length($ +message), "\n"; $bytes_sent = syswrite( $main_socket, $message, length($message), 0); $message="Connect!!"; $bytes_sent = syswrite( $main_socket, $message, length($message), 0);
      So I don't see why the server is seeing "Connect!!" where it's supposed to see 9.

        Sorry I missed that part of your code. I tried to look into it further but you code is truncated and won't compile.

                - tye (but my friends call me "Tye")