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

Hello Monks,
I have a problem using the POE TCP components to send the data packets between machines. The file that I used at the sender part has a size of 14kb. But I can only receive about 10kb. It got chunked even though I did specify the buffer size of 65535 at the sender part.

Has anyone run into this problem before? Thanks so much.
Here's the code

use warnings; use strict; use POE qw(Component::Server::TCP); POE::Component::Server::TCP->new( Port => 12345, ClientFilter => "POE::Filter::Stream", ClientConnected => sub { print "got a connection from $_[HEAP]{remote_ip}\n"; my $buffer; open FILE, "file" or die "Couldn't open file: $!"; while (<FILE>){ $buffer .= $_; } close FILE; $_[HEAP]{client}->put($buffer); }, ClientInput => sub { my ($client_input, $heap) = @_[ARG0, HEAP]; push @{ $heap->{banner_buffer} }, $client_input; }, ClientDisconnected => sub { print "client from $_[HEAP]{remote_ip} disconnected\n"; }, InlineStates => { input_display=>sub{ my ($client_input, $heap) = @_[ARG0, HEAP]; foreach ( @{ $heap->{banner_buffer} } ) { print "|| $_"; } } }, ); POE::Kernel->run; exit;


Updated!

use strict; use warnings; use File::Basename; use lib dirname($0) . "/lib"; use POE; use POE::Component::Client::TCP; use POE::Filter::Stream; use Data::Dumper; my $port = "12345" ; my $host = "localhost"; _tcpConnection(); POE::Kernel->run; exit; sub _tcpConnection{ POE::Session->create( inline_states=>{ _start=>sub { $_[KERNEL]->alias_set("Connection"); my ( $kernel, $heap ) = @_[ KERNEL, HEAP ]; POE::Component::Client::TCP->new ( RemoteAddress => $host, RemotePort => $port, Filter => "POE::Filter::Stream", Connected => sub { print "sending request on $host:$port ...\n +"; $_[HEAP]->{server}->put("connect"); # sends + connect $_[HEAP]->{banner_buffer} = []; }, # The connection failed. ConnectError => sub { print "could not connect to $host:$port ...\n" +; }, ServerInput => sub { my ( $kernel, $heap, $input ) = @_[ KERNEL, HE +AP, ARG0 ]; print "input $input\n"; push @{ $heap->{banner_buffer} }, $input; $kernel->delay( input_timeout => 20 ); }, InlineStates => { input_timeout => sub { print "got input timeout from $host:$port +...\n"; print ",----- Banner from $host:$port\n"; foreach ( @{ $heap->{banner_buffer} } ) { print "| $_"; } print "`-----\n"; #$kernel->yield("shutdown"); }, }, ); }, }, ), }


Thanks in advance.

Replies are listed 'Best First'.
Re: sending data over TCP channel using POE::Component::Server::TCP
by jettero (Monsignor) on Jul 30, 2008 at 15:02 UTC

    Are you sure you want to be using sysread? Something about this doesn't feel right.

    ClientConnected => sub { print "got a connection from $_[HEAP]{remote_ip}\n"; open(INFILE,"./file") or die "Open fail"; sysread(INFILE,my $buffer='',65535); $_[HEAP]{client}->put($buffer); },

    Either way, there's an awful lot of code in your post. I couldn't begin to guess where the problem is. Perhaps you could narrow it down to a smaller example?

    I do recall having various problems with the TCP classes. IIRC, I ended up writing a POE::Filter (which you plug in with the ClientFilter keyvar) that encoded unprintable characters and CRFLs into a format that wouldn't mess with line buffering and the problems went away. Technically the filter also encrypted the messages...

    I always expected I was missing something though. I don't think it's line buffered.

    -Paul

      Thanks Paul.
      I hope the code example is better now.
      sysread was the first thing come into my mind when I tried to serialize the content of my file, get a string and send it out. It seems to work just fine before this line $_[HEAP]{client}->put($buffer);
      The problem appears when I send this string to other side. It got chunked somewhere, I didn't receive the whole packet.
      I think the size of the sending data might have been fix at a certain maximum. I'm not sure...
      I don't know if using POE::Filter will fix it. I'll take a look.
Re: sending data over TCP channel using POE::Component::Server::TCP
by rcaputo (Chaplain) on Jul 30, 2008 at 17:18 UTC

    Your client is treating the connection as a stream (by using POE::Filter::Stream to interpret the data). It seems to me that the server should be doing the same.

    Are your sure your sysread() read everything?

    Have you tried printing the length() of what you're sending and receiving? When I do that here, I get:

    % perl perlmonks-701147-server.pl
    got a connection from 127.0.0.1
    sending 21097
    
    and
    % perl perlmonks-701147-client.pl
    sending request on localhost:12345 ...
    input size: 21099
    
    The client receives 2 additional characters: carriage return, and linefeed. The default server-side POE::Filter::Line adds them, and the client-side POE::Filter::Stream doesn't remove them.

    If you're still having problems, maybe you're running an old version of POE? I can't reproduce the error with your test case, so something must be outdated or different between our systems.

      Yes I did.
      I get 14003 for the sending data and 11060 at the receiver.
      my POE version is 0.9989. Which one are you using now?

      Update:
      Please retake a look at the server code again. I made some changes there.
      I tried to update to the latest version version which is 1.002 and run the same program.
      It gives me this error :
      Prototype mismatch: sub POE::Kernel::F_GETFL: none vs () at C:/Perl/site/lib/POE/Resource/FileHandles.pm line 24.
      Prototype mismatch: sub POE::Kernel::F_SETFL: none vs () at C:/Perl/site/lib/POE/Resource/FileHandles.pm line 25.
      I didn't have it with the old one.
        I took a look at the "Prototype mismatch" error you describe here (after upgrading to POE version 1.002), and although I'm not running activestate perl, the version of POE I have running on my Apple Mac, shows the following code:
        .../POE/Kernel.pm BEGIN { ... if ($^O eq 'MSWin32') { *{ __PACKAGE__ . '::RUNNING_IN_HELL' } = sub { 1 }; } else { *{ __PACKAGE__ . '::RUNNING_IN_HELL' } = sub { 0 }; } ... } .../POE/Resource/FileHandles.pm: ### Some portability things. # Provide dummy constants so things at least compile. These constants # aren't used if we're RUNNING_IN_HELL, but Perl needs to see them. BEGIN { if (RUNNING_IN_HELL) { eval '*F_GETFL = sub { 0 };'; eval '*F_SETFL = sub { 0 };'; } }
        I think we'll need to take a peek at your Kernel.pm and FileHandles.pm to see what's going on here. Anybody else have any thoughts on this? In any case, I don't think its part of your original problem (well, not yet anyways).

        One other interesting thing is that this same error shows up in the Activestate build here.

        -Craig

        As a developer of POE, I use whatever's currently in the repository. "Eating my own dog food" is one of the easier methods of quality assurance. The latest CPAN version should be pretty close: I'm releasing earlier and more often than I have been.

        I wasn't able to reproduce the problem on Mac OSX. There may be Windows issues at work. There are very good reasons why it's called "running in hell".