You need to use non-blocking reads and writes with select model servers. You're already using send, but you are using <handle> to read.

If you change this line $buf = <$rh>;

to $rh-recv( $buf, 100 ); your demo code will probably work.

However, that is only the first of the problems you will encounter for your application. The demo will only work because you responding to the inbound requests immediately. Once you start forwarding the queries to the DB, you will need to separate the receiving of the request from the sending of the response, otherwise all your clients will need to wait until the previous transaction completes.

You could issue the query immediately after the receive, and then go back to servicing the listener for a while until the database has the data available, and then send the response; but I'm unaware of any DBI method for polling a statement handle to determine if the data is available yet. POE does it using child processes and another pair of sockets or pipes.

I can see an analogous threads solution. You just make your connection to the DB in a separate thread, queue the inbound queries to it as they arrive, and the send back the response as they become available. By picking the responses off a second return queue, using $Q->pending or $Q->dequeue_nb you avoid blocking the server thread, thus ensuring you stay responsive to new requests.

The DB queries would be effectively serialised through the Q's, but then they would almost certainly be serialised at the DB end in anycase.

Finally, as you mentioned above, you need to coordinate the requests and response. A simple mechanism is to use a hash to relate stringified socket handles to actual socket handles. Eg. (Untested)

sub DBthread { my( $Qin, $Qout ) = @_; my $dbh = DBI->create( ... ); while( my( $tag, $request ) = split ' : ', $Qin->dequeue ) { my $sth = $dbh->prepare( $request ); my $response = $sth->execute; $Qout->enqueue( "$tag : $response ); } } my( $QtoDB, $QfromDB ) = map{ new Thread->Queue } 1 .. 2; my $threadDB = threads->create( \&DBthread, $QtoDB, $QfromDB ); ... my $listener = new IO::Socket( .. ); my $sel = new IO::Select; my $sel->add( $listener ); my %clients; while( 1 ) { ... for my $fh ( $sel->can_read ) { if( $fh == $listener ) { my $client = $listener->accept; $sel->add( $client ); } else { $fh->recv( $buf, 100 ); ... $QtoDB->enqueue( "$fh : select something from somewhere" ) +; $clients{ $fh } = $fh; } while( $QfromDB->pending ) { my( $tag, $response ) = split ' : ', $QfromDB->dequeue; my $clientFH = $clients{ $tag }; $clientFH->send( $response ); $clientFH->shutdown( 2 ); $sel->delete( $clientFH ); } } }

That's pretty much all you would need to stay responsive to new requests, and respond as quickly as the DB can service them. Two threads. No starting or stopping of threads or processes. No extra pipes or sockets to multiplex.

A more sophisticated design might seek to interleave the handling of requests and replies, but that's probably overkill.


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

In reply to Re^5: Perl Sockets by BrowserUk
in thread Perl Sockets by crawfordr

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.