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

ok so im reading from lincoln d stein book
network programming in perl
chapter 5 shows an example of a tcp echo server-client app.
im on ubuntu.
im tryin to test it.
here are the sources to it
http://www.modperl.com/perl_networking/source/ch5/
its expected behaviour is simple

client-->message-->server
server gets message,inverts it-->new_message-->client
client prints message on screen


ok now if i try the application with appropriate parameters
for client 127.0.0.1 and 2007 and for server with
2007 it doesnt want to work.i put in input...but it
never seems to come back on the screen inverted.
on the other hand if i replace the client with
telnet and give it same params ,SURPRISE !IT WORKS !!
now in chapter 4 there's an exact replica of this
server-client app only its using somewhat different
functions and that works totally OK.
my question is whats happening and how am i supposed
to get it right ?
thank you

Replies are listed 'Best First'.
Re: socket gone crazy
by jettero (Monsignor) on May 23, 2007 at 12:19 UTC

    "...but it never seems to come back on the screen inverted."

    At first glance, I'd guess the problem is the $/ = CRLF, which is done in the server, but not the client. It might just work if you were to comment that out... You'd have to do that on both ends if you were going to do it at all.

    $/ is documented on the perlvar page.

    -Paul

Re: socket gone crazy
by almut (Canon) on May 23, 2007 at 14:12 UTC

    jettero identified the problem correctly. However, setting $/ = CRLF on the client side won't help, as it's the input record separator, yet the \r\n (CRLF) needs to be sent on output, i.e. at the end of the $msg_out string in the statement print $socket $msg_out; .

    Anyway, the easiest way to get this demo to work is to remove the $/ = CRLF; in the server code. Alternatively, you could add $msg_out =~ s/\n/\r\n/; right before the print $socket $msg_out; . (On unix, the string returned by STDIN->getline will be terminated by just \n, not \r\n.)

    With this modification, you should see (assuming the server is running):

    $ ./tcp_echo_cli2.pl localhost 2007 foobar raboof

    BTW, a good way to debug things like these yourself is to insert simple print ... statements to find out exactly where things are not working as expected. (In this case, you'd have seen that it doesn't get past the while (<$session>) { line in the server...)

      I'm also under the impression that changing $/ might not ever help with this since the \n is converted on the way in from a file handle. The thing I don't know is if it converts "\x0d\x0a" to a \n for sockets. I suspect it does not.

      -Paul

        ... changing $/ might not ever help with this since the \n is converted on the way in from a file handle.

        Automatic line ending translations would happen if the crlf PerlIO layer were in effect. On Windows, this layer is by default pushed on the PerlIO layer stack for every filehandle (and, I suppose, for sockets, too — not 100% sure, though1).  However, as the OP is trying this on Ubuntu, there is no crlf layer (unless explicitly requested), and thus no CR/LF translations.

        ___

        1 ...sorry, can't verify without rebooting into Windows, which would be too much fuss at the moment :)

        Maybe someone else is willing to just run the example on Windows, and put a

        print join(" ", PerlIO::get_layers($session)), "\n";

        right after the my $session = $sock->accept; in the server code. This would show which layers are in effect.

Re: socket gone crazy
by halley (Prior) on May 23, 2007 at 19:59 UTC
    There's a perl of wisdom, "be lenient in what you accept, rigorous in what you produce."

    Try to work your network programs so that they will continue to work if the client has the wrong line terminator, but always send "\r\n" as your own line terminator. This is pretty typical of the network ASCII protocols including HTTP.

    This means that you probably want to strip any returns with tr/\r//d or such, in both your clients and your servers, before doing any other fussy parsing work (even just reversing the characters in the meat of the string).

    You can play with $/ if you want to make chomp() smarter, for example, but it seems more flexible to specifically and explicitly work with newlines handling in your own code.

    --
    [ e d @ h a l l e y . c c ]