in reply to sharing a socket between two threads (win32)
Whether it's a limitation of Win32 sockets or Perl or sockets in general, attempting to send to a socket whilst simultaneously in attempting to read from it doesn't work. It's not a limitation of threads, though without threads simultaneously reading and writing is a bit harder :)
To alleviate the problem, it's necessary to set the socket into non-blocking mode and use sysread rather than the buffered IO primitives.
This code does pretty much what you've ask for, but don't take it as being a good example of anything :) Just a starting point:
#! perl -slw use strict; package threads::SimpleServer; use threads; use Thread::Queue; use IO::Socket qw(:DEFAULT :crlf); use Time::HiRes qw( usleep ); our @ISA = 'Thread::Queue'; our $die:shared = 0; sub listener { my( $in, $out, $port ) = @_; my $sock = new IO::Socket::INET ( LocalAddr => "localhost", LocalPort => $port, Proto => 'tcp', Listen => 1, Reuse => 1 ); my $client = $sock->accept; async { ioctl( $client, 0x8004667e, pack( 'V', 1 ) ) or die $^E; my( $buffer, $p ) = ( '', 0 ); while( not $die ) { local $\ = CRLF; print $client $out->dequeue while $out->pending; my $bytes = sysread( $client, $buffer, 1024, length( $buff +er ) ); last unless defined $bytes or 0+$^E == 10035; sleep 1 and next unless $p = 1+index( $buffer, CRLF ); $in->enqueue( substr( $buffer, 0, $p+1, '' ) ) while $p = 1+index( $buffer, CRLF ); } }->detach; } sub new { my( $class, %args ) = @_; my( $in, $out ) = map{ bless Thread::Queue->new(), $class } 1 .. 2 +; threads->create( \&listener, $in, $out, $args{ port } || 1000 )->d +etach; return $in, $out; } 1; package main; use threads; #use threads::SimpleServer; my( $in, $out ) = threads::SimpleServer->new( port => 1000 ); async{ my $reportNo; $out->enqueue( 'report:' . ++$reportNo ) while sleep 1; }->detach; while( my $cmd = $in->dequeue ) { warn "got:'$cmd'"; $out->enqueue( ( rand > 0.5 ) ? 'OK' : '?' ); } END{ our $die = 1; sleep 1 }
|
|---|