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

2 questions. I plan on using IO::Socket::INET for this script.
1. Heres the situation:
There is a server across the way. This server has two ports allocated, A and B. A is port 12345 and its job is to send the telemetry of an aircraft. B is on port 6789 and its job is to send the waypoint locations. I would like to write a script that will connect to BOTH of these ports in one swoop. Since A and B both have the same host address I was hoping this would be possible. The two possibilities I know of are: fork which I have not done before and threads.
2. I would like to make the script as autonomous as possible. That means that when the socket disconnects it would be great if it sleeps for a little while then tries to reconnect to the host. I'm not sure how to go about this and would like a little help (or a reference).

Replies are listed 'Best First'.
Re: Two TCP Connections, one script
by Corion (Patriarch) on Apr 04, 2008 at 06:08 UTC

    Let me recommend a third alternative to fork or threads. Use IO::Select to manage reading from the sockets whenever data is available.

    I guess that handling a disconnected socket is also possible if you detect that you get a timeout while waiting for data.

Re: Two TCP Connections, one script
by BrowserUk (Patriarch) on Apr 04, 2008 at 08:49 UTC

    A working example using threads complete with disconnect recovery:

    #! perl -slw use strict; use threads; use Thread::Queue; use IO::Socket; my $Q = new Thread::Queue; my @threads = map async { while( 1 ) { my $s = IO::Socket::INET->new( $_ ) or die $!; while( my $input = <$s> ) { $Q->enqueue( $input ); } sleep 5; } }, 'localhost:12345', 'localhost:6789'; while( my $input = $Q->dequeue ) { chomp $input; if( $input =~ m[Z:] ) { ## Deal with telemetry print "Got telemetry: '$input'"; } else { ## Deal with waypoint; print "Got waypoint: '$input'"; } }

    A little trace showing reconnect for both servers:

    C:\test>678330.pl Got telemetry: 'X:-77.64038 Y:-153.75366 Z: 15910' Got waypoint: 'X:-171.05713 Y:051.82251' Got telemetry: 'X:-42.74780 Y:028.83911 Z: 28944' Got waypoint: 'X:-38.79272 Y:-104.06250' Got telemetry: 'X:057.34863 Y:-125.10132 Z: 2259' Got waypoint: 'X:-27.70752 Y:073.97095' Got telemetry: 'X:-107.01782 Y:-63.42407 Z: 11333' Got waypoint: 'X:119.52026 Y:122.77222' Got telemetry: 'X:065.73120 Y:076.75049 Z: 7514' Got waypoint: 'X:-101.51367 Y:059.56787' Got waypoint: 'X:077.84912 Y:-00.31860' Got waypoint: 'X:000.24170 Y:-07.85522' Got waypoint: 'X:-179.58252 Y:-50.33936' Got waypoint: 'X:-138.26294 Y:-179.98901' Got waypoint: 'X:-20.14893 Y:062.01782' Got waypoint: 'X:-86.61621 Y:-63.24829' Got waypoint: 'X:-99.17358 Y:-173.48511' Got telemetry: 'X:-122.01416 Y:036.21094 Z: 17707' Got waypoint: 'X:-65.35767 Y:-42.01172' Got telemetry: 'X:-27.78442 Y:123.21167 Z: 11011' Got waypoint: 'X:094.70215 Y:174.35303' Got telemetry: 'X:-57.84302 Y:034.00269 Z: 11311' Got waypoint: 'X:-83.51807 Y:-146.19507' Got telemetry: 'X:-09.01978 Y:035.83740 Z: 6095' Got telemetry: 'X:-14.65576 Y:176.96777 Z: 14657' Got telemetry: 'X:-97.55859 Y:-81.47461 Z: 28815' Got telemetry: 'X:-150.65552 Y:087.11060 Z: 14598' Got telemetry: 'X:-113.20313 Y:-15.20508 Z: 15945' Got telemetry: 'X:-127.38647 Y:098.18481 Z: 1425' Got telemetry: 'X:022.19238 Y:-145.00854 Z: 14309' Got waypoint: 'X:-129.70459 Y:125.38696' Got telemetry: 'X:-101.64551 Y:-58.45825 Z: 15181' Got waypoint: 'X:-14.16138 Y:171.74927' Got telemetry: 'X:-88.86841 Y:-92.66968 Z: 3557' Got waypoint: 'X:-121.08032 Y:002.66968' Got telemetry: 'X:125.14526 Y:-29.19067 Z: 13236' Got waypoint: 'X:155.89600 Y:-78.14575' Got telemetry: 'X:094.61426 Y:-44.34082 Z: 6590' Got waypoint: 'X:-74.31152 Y:110.48950' Terminating on signal SIGINT(2)

    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.
Re: Two TCP Connections, one script
by pc88mxer (Vicar) on Apr 04, 2008 at 07:48 UTC
    I agree - it seems that IO::Select is a good candidate for this task. I'll just explore a few of the other issues involved.

    Presumably you want the data from both of these connections to be in the same memory space so you can combine the data in some way. This requirement would preclude the use of fork since data read by one process is not accessible by another process. On the other hand, if you don't need to combine the data from these two connections, then a fork solution is possible and could be simpler than an IO::Select solution. If you tell us more about what your program is going to do with the data is receives from the two connections, we can advise you on whether or not a fork solution is possible.

    Here's a fragment of code which illustrates the use of IO::Select. It assumes that the data read from the input handles $h1 and $h2 is line oriented data, and when a complete line is received the appropriate handler is called:

    The above fragment of code is generically useful in the following sense: we can accomplish most of what you want to do using the netcat command with the above handling code:

    open(my $h1, "nc server.com 12345|"); open(my $h2, "nc server.com 6789|"); # now call the above I/O handler loop

    In fact, we can also get graceful reconnects with a simple shell script:

    open(my $h1, "while true; do nc server.com 12345; sleep 10; done|"); # ditto for $h2
    This approach may have to be tweaked if you need to send data to the server, but it illustrates a potential way of decomposing the problem.
Re: Two TCP Connections, one script
by Fletch (Bishop) on Apr 04, 2008 at 13:55 UTC

    An alternative to doing the select-ery yourself would be to use POE and let it do the work.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

      Thanks for the responses, looks like the answers give me some things to try. I have a few questions about the code posted:
      #! perl -slw use strict; use threads; use Thread::Queue; use IO::Socket; my $Q = new Thread::Queue; my @threads = map async { while( 1 ) { my $s = IO::Socket::INET->new( $_ ) or die $!; while( my $input = <$s> ) { $Q->enqueue( $input ); } sleep 5; } }, 'localhost:12345', 'localhost:6789'; while( my $input = $Q->dequeue ) { chomp $input; if( $input =~ m[Z:] ) { ## Deal with telemetry print "Got telemetry: '$input'"; } else { ## Deal with waypoint; print "Got waypoint: '$input'"; } }
      port 12345 will only receive the telemetry in XML format and port 6789 will only send the waypoint XML file. My question would be how can I separate these processes?

        I'm confused. Mostly because you are too I think.

        1. In your OP you said:
          There is a server across the way. This server has two ports allocated, A and B.
          A is port 12345 and its job is to send the telemetry of an aircraft.
          B is port 6789 and its job is to send the waypoint locations.
        2. But in the above post you say:
          port 12345 will only receive the telemetry in XML format and
          port 6789 will only send the waypoint XML file.

        Which is it?

        You'll need to clarify whether the script you want, needs to act

        • as a client to both ports?

          If so, is it reading from both or writing to one of them?

        • or as a client to one and as a server to the other?

        And finally:

        My question would be how can I separate these processes?

        What do you mean by this?

        In the code you reposted, there is an if statement. In one half of it you would be dealing with telemetry data. In the other, waypoint data.

        What problem are you seeing with that?


        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.