I'm writing a UDP (yes, UDP) server (in Perl) and would like to make the core code invariant: that is, the server just listens and spawns handlers -- or simply handles jobs serially. So far, so good.

What I've got is clients who send what amount to remote procedure calls to the server: a command and a bunch of arguments. So far, so good.

Now, I'd like to put the logic for each 'procedure call' in its own file. One file for 'getFoo' called 'getFoo.pm', one file for 'getBar' called 'getBar.pm' or something like that. The reason I want to do this is that I think it separates the server-side logic admirably, and makes it easy to 'drop in' new 'procedures' without having to change the server much (or at all). I think. Maybe.

Is this more trouble than its worth? Am I going to hit serious runtime delays as my server searches for new code? Is there a module on CPAN that does this already? Am I better off using LWP and essentially going the Webservices route?

Thanks y'all.

Rob

Update. Here's my server. Nothing groundbreaking about it, stolen from stuff found on Perlmonks and in the Cookbook. But I suspect that pg's suggestion may be quite productive.

#!/usr/bin/perl -w $|++; use strict; use IO::Socket; use Sys::Hostname; use DBI; use TolDatabase; my $HOST = 'localhost'; my $db = new TolDatabase(); $db->connect( 'db' => 'test', 'host' => $HOST, 'port' => '', 'socket' => '', 'usr' => '', 'passwd' => '' ); print "Starting server.\n"; my $SERVERPORT = 2001; #my $REPLYPORT = 2000; my $DATAGRAM_SIZE = 4000; my $server = IO::Socket::INET->new(LocalPort => $SERVERPORT, Proto => "udp", Reuse => 1 ) or die "Can't create server: $@"; $server->blocking(0); print "Listening on port $SERVERPORT.\n"; my ($datagram,$flags); my ($omo,$od) = ('',''); while( my $client = $server->recv($datagram,$DATAGRAM_SIZE,$flags) ) { chomp( $datagram ); my ($func, @args) = split ' ', $datagram; next unless $func; my $msg; if ( $func eq 'distance' ) { $msg = distance( @args ); } else { $msg = $db->process( $func, @args ); } my $ipaddr = $server->peerhost; my $port = $server->peerport; my ($s,$m,$h,$d,$mo,$yr) = localtime(time); $mo++; if ( $omo ne $mo || $od ne $d ) { print "\n$mo/$d\n\n"; $omo = $mo; $od = $d; } printf( "%02s:%02s:%02s $ipaddr $datagram\n", $h, $m, $s); $server->send( $msg ); # my $response = IO::Socket::INET->new(Proto=>"udp",PeerHost=>$ipadd +r, PeerPort=>$REPLYPORT); # $response->send( $msg ); } # # Middleware commands to implement: # # breakout ship-id # buyFuel player-id ship-id cash-left # buyShip player-id ship-id cash-left # dock ship-id dock-id # getPlanetData planet-id # getShipData ship-id # getSystemData system-id # jump ship-id # land ship-id landing-field-id # land ship-id planet-surface-id # launch ship-id # load cargo-id ship-id # load passenger-id ship-id # login user name # look location-id # move object-id destination-id # orbit ship-id orbit-id # setJump ship-id destination-id distance # unload cargo-id destination-id # unload passenger-id destination-id # # # Operational rules to automate: # # 1. Update registry for all movement, including freight loading/un +loading and entering jumpspace. # 2. Reset a ship's location and ETA parameters when breaking out of + jump. # 3. Make bank transaction, move ship to landing field, and transfer + ownership when buying a ship. # 4. Set destination and distance, and add route, when filing flight + plans. # 5. Subtract fuel and set ETA when entering jumpspace. # 6. Update free space when loading passengers, freight. # 7. Subtract price when buying fuel. # 8. Unload automatically upon docking/landing. # # # lr-scan system-id range-in-parsecs # sub longRangeScan { my $sysid = shift; my $range = shift; my $sys = "select h.ring,h.ray from starsystem s,hex h where s.hexi +d=h.id and s.id=$sysid"; my $sref = $db->getRows( $sys )->fetchrow_href(); my $ring = $sref->{ring}; my $ray = $sref->{ray}; print "ring/ray: $ring/$ray\n"; my $sql = "select s.*,h.ring,h.ray from starsystem s join hex h on +(s.hexid=h.id)" . " where h.ring > " . ($ring-$range-1) . " and h.ring < " . ($ring+$range+1) . " and h.ray > " . ($ray-$range-1) . " and h.ray < " . ($ray+$range+1) . " and not (h.ring=$ring and h.ray=$ray)"; my $sth = $db->getRows( $sql ); my $href; my $out = ''; while( $href = $sth->fetchrow_hashref() ) { if ( &distance( $ring, $ray, $href->{ring}, $href->{ray} ) <= $r +ange ) { $out .= $db->materializeRow( $href ); } } return $out; } sub distance { my $ring1 = shift; my $ray1 = shift; my $ring2 = shift; my $ray2 = shift; my $a1 = $ring1 + int((1+$ray1)/2); my $a2 = $ring2 + int((1+$ray2)/2); my $d1 = abs( $a1 - $a2 ); my $d2 = abs( $ray1 - $ray2 ); my $d3 = abs( $a1 - $ray1 - $a2 + $ray2 ); my @d = sort ($d1, $d2, $d3); return $d[2]; }

In reply to RPC-like behavior in a UDP server by rje

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.