Several days ago I was presented with a new problem at work that required socket communication, and I realised I had zero experience with sockets up until then.

So, off I went to perlipc and had a good read.

Looks easy enough, I thought. Pulled out the "interactive client" scripts and put them to work. The server script appears to have worked fine but...

Problem:

After the client script has finished 'initialising', it gets stuck in a deadlock.

It appears to be the client script that causes the lock, as any form of 'read' on the socket seems to block (even the twin thread for sending data) if there isn't anything there to read...

ioctl

So, reading around a bit more (I think) I found something similar to what I was experiencing. Various MS articles say/imply that INET Sockets are created in blocking mode by default, and what I'm trying to do should be done using non-blocking sockets. (Or am I way off base...?)

Well, I had a look at the method, Blocking  => 1 provided by  IO::Socket::INET however on ActivePerl 5.8.8 it dies with the error "Bad file descriptor"... (Incidentally, I tried this on ActivePerl 5.10.1 and it doesn't die, however the behaviour I'm seeing is still the same...)

So I tried $num = ioctl($handle, 0x8004667e, 1); which is returning undef... and hasn't altered the blocking behaviour... so maybe this is another problem altogether...

I may well have missed something very simple, however I am at my wits end for getting this to work reliably. Any insights and assistance would be much appreciated on how to create a simple pair of scripts for interactive client<->server communication.

(Thus far, my efforts have focused on IO::Socket::INET. I am having a go currently with Socket.pm in the interim incase I have better luck...)

The scripts in their current form (after numerous changes) are below in the ReadMore...

Client:

#!C:/perl/bin/perl -w use strict; use warnings; my $cvs_version = sprintf "%d.%03d", q$Revision: 1.4 $ =~ /(\d+)\.(\d+ +)/; use IO::Socket; my ($host, $port, $kidpid, $handle, $line); unless (@ARGV == 2) { die "usage: $0 host port" } ($host, $port) = @ARGV; $handle = IO::Socket::INET->new( Proto => "tcp", PeerAddr => $host, PeerPort => $port, Timeout => .1, # this seems to have no improvement on my + problem... #Blocking => 1, # if this is enabled Perl dies with "Bad +file descriptor" ) or die "can't connect to port $port on $host: $!"; my $num = 'a'; #just proving that ioctl has infact changed this to un +def after running... $num = ioctl($handle, 0x8004667e, 1); print "ioctl return code was [$num]\n"; #with or without the ioctl statement, reading from the socket... #... eventually blocks if nothing is there to be read... $handle->autoflush(1); print STDERR "[Connected to $host:$port]\n"; die "can't fork: $!" unless defined($kidpid = fork()); if ($kidpid) { # parent copies the socket to standard output $| = 1; #set STDOUT to non-buffered to demonstrate that two way... + # ...communication is possible up until there is nothing l +eft to read. my $buff; while (1){ my $num = sysread($handle, $buff, 4); #if there are zero byt +es waiting, the sysread appears ... if ($num >= 4) { #... to block, and eve +n blocks the child thread from writing to $handle... print $buff; } else { print "buffer is [$num] bytes big\n"; } sleep 1; } warn "Read from buffer stopped...\n"; kill("TERM" => $kidpid); } else { # child copies standard input to the socket while (defined ($line = <STDIN>)) { chomp $line; warn "echo before send: [$line]\n"; print $handle "$line\n"; warn "echo after send: [$line]\n"; } } exit;


Server:

#!C:/perl/bin/perl -w use strict; use warnings; my $cvs_version = sprintf "%d.%03d", q$Revision: 1.4 $ =~ /(\d+)\.(\d+ +)/; $| = 1; use IO::Socket; use Net::hostent; my $PORT = 9001; my $server = IO::Socket::INET->new( Proto => 'tcp', LocalPort => $PORT, Listen => 1, ReuseAddr => 1, ); die "can't setup server... $!... $@..." unless $server; print "[Server $0 accepting clients]\n"; my $num = 'a'; $num = ioctl($server, 0x8004667e, 1); print "ioctl return code was [$num]\n"; #returns undef sleep 1; while (my $client = $server->accept()) { $client->autoflush(1); $num = 'a'; $num = ioctl($server, 0x8004667e, 1); print "ioctl return code was [$num]\n"; #returns undef print $client "Welcome to $0; type help for command list.\n"; my $hostinfo = gethostbyaddr($client->peeraddr); printf "[Connect from %s]\n", $hostinfo ? $hostinfo->name : $client +->peerhost; print $client "Command? \n"; sleep 1; while (defined ($_ = <$client>) ){ print STDOUT $_; next unless /\S/; # blank line if (/quit|exit/i) { last; + } elsif (/date|time/i) { printf $client "%s\n", scalar localtime +; } elsif (/hello/i ) { print $client "G'day there\n"; + } else { print $client "Commands: quit date hello\n"; } } continue { print $client "Command? \n"; } close $client; }

In reply to Sockets, ioctl and non-blocking reading on ActivePerl by desemondo

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.