3

I am doing socket programming. The data ($ data) received from the socket contains 4 bytes of length data + json data. I want to trim the length and only parse the json.

I have completed the code and it works fine. But I wonder if there is a more efficient way (algorithm).

Is there an efficient way to move arrays to variables in perl?

@tmpp = split(//,$data); #data = socket data

my $t1 = sprintf("%02x%02x%02x%02x",ord($tmpp[0]),ord($tmpp[1]),ord($tmpp[2]),ord($tmpp[3])); 
$t1 = hex($t1); #t1 = length 

my $json;
my @tmp = @tmpp[0..-1];
foreach(@tmp){ $json .= $_;}<br>
print $json;

Ok Print ; 
1
  • Are you following standard networking conventions, i.e. the sender converts the 32-bit from local endianess to network endianess before writing it to the socket? Commented Feb 6, 2019 at 16:31

2 Answers 2

2

This is a standard case for pack/unpack. The N/a template will unpack a string of length N (in network byte order):

my( $json ) = unpack 'N/a', $data;
print $json;
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks for letting me know. pack / unpack is the best choice. But it takes $ data as an argument. Is there a way to pack / unpack @data (array)?
@SAnjiHolic You already have $data as a string and keeping it that way is the most efficient approach. If you have an array, @tmpp, then unpack 'L>/a', join '', @tmpp could work and would be relatively fast. Splitting a string into an array and then working on the array is usually a bad approach in Perl.
@SanjiHolic If the answer works for you, please accept it ( stackoverflow.com/help/someone-answers )
@StefanBecker Thanks, N is a much better/clearer template
0

If you have what you say you have, you could simply peel off the length prefix.

my $json = substr($data, 4);

But this would mean that the length prefix is useless, which suggests you have a major bug earlier in your program. Did you properly read from the socket?

sub read_bytes {
   my ($fh, $bytes_to_read) = @_;
   my $buf = '';
   while ($bytes_to_read) {
      my $bytes_read = read($fh, $buf, $bytes_to_read, length($buf))
      die($!) if !defined($bytes_read);
      die("Premature EOF") if !$bytes_read;
      $bytes_to_read -= $bytes_read;
   }

   return $buf;
}

sub read_uint32be { unpack('N', read_bytes($_[0], 4)) }

sub read_string {
   my ($fh) = @_;
   my $len = read_uint32be($fh);
   return read_bytes($fh, $len);
}

my $json = read_string($sock);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.