http://www.perlmonks.org?node_id=104273

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

So there I was, happily working my way through Lincoln Stein's new book, when something decided not to work as advertised. I've played with it for quite some time now, and as the book's web site is down, I thought I'd come here and ask for advice.

Stein gives code, which I followed fairly closely, for echo clients and servers, each implemented once with Socket and once with IO::Socket. The Socket implementations worked fine. Then I tried the IO::Socket client implementation, which worked fine against the Socket server. However, neither client worked against the IO::Socket implementation--it looks like a deadlock condition. Finally, just for grins, I telneted directly to the server, and lost the deadlock--the text came right back.

I'm finding this pretty puzzling--I've tried various things, including explicitly setting autoflush on (yes, I know it's on be default, but wotthehell). I'm not getting any success. Any thoughts? I'm using current versions from ActiveState Build 628 on Windows ME. Code snippets follow:

Here's the Socket server code:
my $protocol = getprotobyname('tcp'); socket(SOCK, AF_INET, SOCK_STREAM, $protocol) or die "No socket: $!"; setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, 1) or die "No SO_REUSEADDR: + $!"; my $my_addr = sockaddr_in($port, INADDR_ANY); bind(SOCK, $my_addr) or die "No bind: $!"; listen(SOCK,SOMAXCONN) or die "No listen: $!"; warn "listening on port $port...\n"; while ( 1 ) { next unless my $remote_addr = accept(SESSION, SOCK); my ($port, $hisaddr) = sockaddr_in($remote_addr); warn "Connection from [",inet_ntoa($hisaddr),",$port]\n"; SESSION->autoflush(1); while(<SESSION>) { $bytes{'in'} += length($_); chomp; my $msg_out = scalar reverse $_ . "\n"; print SESSION $msg_out; $bytes{'out'} += length($msg_out); } warn "Connection from [",inet_ntoa($hisaddr),",$port] finished\n"; close SESSION; } close SOCK;

This works fine. Now, here's the IO::Socket server code:

my $socket = IO::Socket::INET->new( Listen => 20, LocalPort => $port, Timeout => 5, #60 * 60, Reuse => 1) or die "No socket: $!"; warn "listening on port $port...\n"; while ( !$quit ) { next unless my $session = $socket->accept; my $peer = gethostbyaddr($session->peeraddr,AF_INET) || $session->peerhost; my $port = $session->peerport; warn "Connection from [$peer,$port]\n"; while(<$session>) { #BLOCKS HERE $bytes{'in'} += length($_); chomp; my $msg_out = $_ . CRLF; $session->print($msg_out); print $msg_out; $bytes{'out'} += length($msg_out); } warn "Connection from [$peer,$port] finished\n"; close $session; }

Here's some of the client code, Socket version:

my $socket = IO::Socket::INET->new("$host:$port") or die "No connect: +$!"; my $protocol = getprotobyname('tcp'); my $ok = 1; $socket->autoflush(1); while ( defined (my $msg_out = STDIN->getline) ) { last unless $ok; print $socket $msg_out; my $msg_in = <$socket>; print $msg_in; $bytes{'out'} += length($msg_out); $bytes{'in'} += length($msg_in); }

adamsj

They laughed at Joan of Arc, but she went right ahead and built it. --Gracie Allen

Edited 2001-08-12 by Ovid.

Replies are listed 'Best First'.
Re: IO::Socket vs. Socket vs. of-the-shelf telnet
by abstracts (Hermit) on Aug 12, 2001 at 22:56 UTC
    Hello

    Is CRLF defined anywhere in your program? I can see that this is the source of trouble since you are chopping the EOL char and placing CRLF in its place. I tried this and it works as advertized:

    use IO::Socket; use constant CRLF => "\r\n";##### Add This my $quit = 0; my $port = 12345; my $socket = IO::Socket::INET->new( Listen => 20, LocalPort => $port, Timeout => 5, #60 * 60, Reuse => 1) or die "No socket: $!"; warn "listening on port $port...\n"; while ( !$quit ) { next unless my $session = $socket->accept; my $peer = gethostbyaddr($session->peeraddr,AF_INET) || $session->peerhost; my $port = $session->peerport; warn "Connection from [$peer,$port]\n"; while(<$session>) { #BLOCKS HERE $bytes{'in'} += length($_); chomp; my $msg_out = $_ . CRLF; $session->print($msg_out); print $msg_out; $bytes{'out'} += length($msg_out); } warn "Connection from [$peer,$port] finished\n"; close $session; }
    Aziz,,,
      Thanks for your answer. Unfortunately for me, I started the program off with:
      use strict; use IO::Socket qw(:DEFAULT :crlf);

      so I think that's not the answer. Still, I'm going to try setting the constant manually and see what happens...

      <INTERLUDE DURATION=BRIEF>

      Dum-de-dum-de-dum-dum.

      <\INTERLUDE>

      Nope, no such luck. Any more thoughts?

      adamsj

      They laughed at Joan of Arc, but she went right ahead and built it. --Gracie Allen

        Hello again

        There seems to be some inconsistencies between active-state perl and perl-5.6.2 I downloaded and built on my gnu/linux box. The client and server programs worked perfectly here.

        I really don't know what could the problem be.

        Aziz,,,

Re: IO::Socket vs. Socket vs. off-the-shelf telnet
by dga (Hermit) on Aug 13, 2001 at 07:57 UTC

    A friend is running Perl on NT4 and the multiprocess model isn't as multiprocess as the one on say linux. The programs block at places that shouldn't block according to what you would expect normally in a multiprocess system. Since an earlier person said it works ok on their box not running Windows a weird blocking call where you wouldn't expect one may be the problem.

    Telnet would actually get to run under another process and thus would work fine.

    I think that this is related to one program (perl) only gets one real run per user i.e. if you run a browser and open a new window you still have only 1 browser. I think if you fork of another perl you still have 1 perl process and if it blocks all the perl 'processes' get blocked.

      Hello

      Both server implementations are a single process single thread implementations. They handle one connection at a time, waiting for input and echoing it back. Fork-related problems on the Win32 platform should not be the problem since fork is not used.

      The comment about telnet running as another process is totally irrelevant since all programs mentioned were running as independent processes.

      Different perl programs do not share the same process the way some browsers do. Every program is run as an independent process, and just because one perl program is blocking does not mean all perl programs would block.

      Aziz,,,