Ram
Ram

Reputation: 822

Perl socket sending hash

I am trying to create a socket client in Perl. The server side is a C program running on the local host.

I have to send a hash over the socket. Here is the piece of code I am using.

sub applyGlobalConfig {
    my ($globalConfig, $ignoreData) = @_;

    my $socket = IO::Socket::INET->new(PeerAddr => $PEER_HOST,
                                       PeerPort => $PEER_PORT,
                                       Proto    => "tcp",
                                       Type     => SOCK_STREAM)
          or die "Couldn't connect to $PEER_HOST:$PEER_PORT : $@\n";

    my $reconfigResult;

    print $socket "$113\n";

    close($socket);

    unless ($reconfigResult) {
        return 0;
    }

    return ERR_NULL;
}

Now, the question I have is, the $globalConfig will contain a hash reference, and I want to send this over a socket. I am unable figure out. I googled and found some reference to Dumper but couldn’t understand much. How do I send the hash over?

Upvotes: 3

Views: 1345

Answers (2)

Galimov Albert
Galimov Albert

Reputation: 7357

I'd prefer to use Storable module for this. Example:

Receive-side:

use strict;
use IO::Socket::INET;
use Storable;
use Data::Dumper;

my   $sock = IO::Socket::INET->new(Listen    => 5, LocalAddr => 'host',
                                 LocalPort => 9000,  Proto     => 'tcp');
while( my $s = $sock->accept ) {
    my $struct = Storable::fd_retrieve($s);
    print Dumper($struct);
}

Send-side:

use strict;
use IO::Socket::INET;
use Storable;

my   $sock = IO::Socket::INET->new(PeerAddr => 'host',  PeerPort => 9000,
                 Type     => SOCK_STREAM, Proto     => 'tcp') || die "Fail: $!";
my $struct = {
    a => 1,
    b => [2,3,4]
};
Storable::nstore_fd($struct, $sock);

Tested by sending from i386 Linux to amd64 FreeBSD.

Also you can use Data::Dumper to make string from hash and then send over network but its dirty and buggy method.

UPD:

But, I am struggling how to convert the values in the hash on perl side to a string separated by space.

Try to use join/map combination:

my $serialized = join("\n", map { "$_ ".$struct->{$_} } keys %$struct)."\n";

Probably on C side its easier to use null-terminated string:

my $keyvalue_count = scalar keys(%$struct);
my $serialized = join("\0", map { "$_\0".$struct->{$_} } keys %$struct)."\0";

In this simple case i'd prefer to use last variant since its native to C.

Upvotes: 1

Jim Garrison
Jim Garrison

Reputation: 86764

To send a data structure over a socket you have to "serialize" it into a byte stream. Then the receiving program has to deserialize it to reassemble the data structure. If the receiving program is expecting the stream to be in a specific form, the sending program must produce the expected format.

If you are writing both sides, then you can choose a serialization format that makes sense for your situation, such as JSON or XML, either of which can represent a Perl hash. However, without knowing much more detail about your specific situation, this is about all that can be provided in the way of an answer.

Upvotes: 6

Related Questions