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

Hi - I'm testing some socket receive/send scripts for hl7 messages, and am at my wit's end... I'm hoping someone can help.
The receiver script is running on a linux box. I have the same sender script on both the linux box and an XP machine. I start the listener, and send a long-ish file/message via the sender script on the linux box. I get the expected number of bytes. I send the same file using the same sender script running on the XP box, and it says it only receives 1260 bytes. The files I'm sending consist of text segments strung together with carriage returns (\015) in between. The sender envelopes the file with a vertical tab (\013), then the message, then file sep (\034) and CR (\015).
There is not a carriage return at the place where the windows sender (or maybe the receiver) is truncating. It's just text. I tried (per the chatterbox) using binmode on the windows side, but either I'm not doing it right, or it made no difference. I just cannot get a long block of text to go through from the XP box.
I hope someone can help ??!
Thanks in advance, Chris Hawkins codelady7
Here are the send/receive scripts:
# a simple client using IO:Socket #---------------- use strict; use IO::Socket; my $infile = @ARGV[0]; my $sock; my $HL7 = <>; my $wbytes; my $rbytes = 5120; my $ackback = "no ack received."; open LOGFILE, ">>hl7.log"; my $sock = new IO::Socket::INET (PeerAddr => '192.168.1.210', PeerPort + => 10500, Proto => 'tcp'); $sock or die "no socket :$!"; #print "socket created...\n"; $wbytes = send ($sock, "\013".$HL7."\034\015", 0); recv ($sock, $ackback, $rbytes, 0); print LOGFILE ("File sent: " . $infile . ".\n"); print LOGFILE ("Bytes sent: " . $wbytes . ".\n"); print LOGFILE ("Received ack: " . $ackback . ".\n"); close LOGFILE; close ($sock); ********************************************** # server using IO::Socket #--------------------- use strict; use IO::Socket; open MSGFILE, ">>msgs.dat"; my $sock = new IO::Socket::INET( LocalHost => '192.168.1.210', LocalPort => 10500, Proto => 'tcp', Listen => SOMAXCONN, Reuse => 1); $sock or die "no socket :$!"; my($new_sock, $c_addr, $buf); print "listening...\n"; while (($new_sock, $c_addr) = $sock->accept()) { my ($client_port, $c_ip) =sockaddr_in($c_addr); my $client_ipnum = inet_ntoa($c_ip); my $client_host =gethostbyaddr($c_ip, AF_INET); print "got a connection from: $client_host"," [$client_ipnum] "; my $bytesin = 5120; recv($new_sock, $buf, $bytesin, 0); print "length is: ". length($buf). "\n"; print "bytes in is: $bytesin\n"; $buf = substr($buf,1,-2).chr(10); syswrite (MSGFILE, $buf, length($buf)); send ($new_sock, "got it, thanks. \n", 0); } close MSGFILE; close $sock;

Edited by planetscape - added readmore tags

Replies are listed 'Best First'.
Re: long text message problem
by Thelonius (Priest) on Mar 11, 2006 at 03:01 UTC
    It is intrinsic in the nature of TCP that long packets may be broken up and small packets may be combined. The bytes will eventually arrive in the same order, but you can't count on the grouping. You may send 800 bytes and another 800 bytes and the 1600 bytes may arrive as packets of 100, 900, and 600. A typical transmission unit over Ethernet is 1500 bytes. (You may have some control over this via socket options such as MTU, but any router the packets flow through can change the divisions.)

    The recv call returns when any data is available; the LENGTH parameter is a maximum, not a minimum. So, either you have to loop, or you use a method that implicitly loops, like readline, also known as <>. If your data always ends with a CR and there's no CR in the data, you can:

    $/ = "\r"; $buf = <$new_sock>;
    You don't have to use binmode on sockets. They use bytes by default.
      Don't use \r in portable applications, especially in use for communication with other systems. \r is LF (\x0A) on the Mac, and CR (\x0D) on other ASCII platforms. \x0D is always CR.
        \r is LF (\x0A) on the Mac, ...
        Huh? Where does this assertion come from, and how exactly would it apply to macosx? Could it be obsolete residue from the bad old os9/mac-perl days? It doesn't seem to hold true on the macosx(10.4.5) that I'm using at the moment:
        $ perl -e 'print "\r"' | od -t xC -a 0000000 0d + cr
        update: Just to make sure there wasn't some asymmetry:
        $ perl -e 'print "\r"' | perl -e '$_=<>; print "got CR\n" if (/\r/)' | + od -t xC -a 0000000 67 6f 74 20 43 52 0a g o t sp C R nl
        (this is perl 5.8.6, btw; presumably, running the latter script on a windows box would yield 8 bytes of output)
Re: long text message problem
by Corion (Patriarch) on Mar 11, 2006 at 00:01 UTC

    I don't see in your code where you applied binmode. I think you will need to binmode both, the handle you're reading from and the handle you're writing to:

    binmode ARGV; # <> reads from ARGV implicitly my $HL7 = <>; ... my $sock = ...; binmode $sock;