Sending HASH over TCP

B

Brad

I have been working on this for a few days now, and still feel stuck.
I have a large HASH which I need to send via TCP to a server. I need
to use IO::Socket::INET for the TCP connection. While there is
probably a _better_ way, I have been playing around with Data::Dumper
convert the HASH, then rebuild it on the other end. The problem is I
cannot seem to rebuild the data.

Code:

Client (sending HASH)
---------------------
use Data::Dumper;
use IO::Socket::INET;

$TEST{'test'}{'test1'} = 1;
$TEST{'test2'}{'test3'} = 2;

$socket = IO::Socket::INET->new(PeerAddr => localhost,
PeerPort => 2002,
Proto => "tcp",
Type => SOCK_STREAM)
or die "Couldn't connect to $remote_host:$remote_port : $!\n";

$Data::Dumper::pair = " : "; # specify hash key/value
separator
$Data::Dumper::Indent = 0;
# send something over the socket,
print $socket Dumper(\%TEST);

# and terminate the connection when we're done.
close($socket);
---------------------

Server
---------------------
use Data::Dumper;
use IO::Socket::INET;

$server = IO::Socket::INET->new(LocalPort => 2002,
Type => SOCK_STREAM,
Reuse => 1,
Listen => 10 ) # or SOMAXCONN
or die "Couldn't be a tcp server on port $server_port: $!\n";

while ($client = $server->accept()) {
$data = <$client>;
#print "$data\n";
#$Data::Dumper::pair = " : "; # specify hash key/value
separator
#$Data::Dumper::Indent = 0;
#eval $data;
print Dumper $data;
}

close($server);
---------------------

I have tried other methods of re-building the hash on the server-end.
The answer is probably right in front of me, but I just don't see it
on the module's page (
http://search.cpan.org/~ilyam/Data-Dumper-2.121/Dumper.pm ) or in the
perldoc.

Any help, or any ideas for a better solution, is appreciated.

Thanks,
Brad
 
B

Ben Morrow

I have been working on this for a few days now, and still feel stuck.
I have a large HASH which I need to send via TCP to a server. I need
to use IO::Socket::INET for the TCP connection. While there is
probably a _better_ way, I have been playing around with Data::Dumper
convert the HASH, then rebuild it on the other end. The problem is I
cannot seem to rebuild the data.

Code:

Client (sending HASH)
---------------------
use Data::Dumper;
use IO::Socket::INET;

$TEST{'test'}{'test1'} = 1;
$TEST{'test2'}{'test3'} = 2;

$socket = IO::Socket::INET->new(PeerAddr => localhost,
PeerPort => 2002,
Proto => "tcp",
Type => SOCK_STREAM)
or die "Couldn't connect to $remote_host:$remote_port : $!\n";

$Data::Dumper::pair = " : "; # specify hash key/value
separator

Why? If you want to be able to eval it, you need to leave it as =>.
$Data::Dumper::Indent = 0;
# send something over the socket,
print $socket Dumper(\%TEST);

# and terminate the connection when we're done.
close($socket);
---------------------

Server
---------------------
use Data::Dumper;
use IO::Socket::INET;

$server = IO::Socket::INET->new(LocalPort => 2002,
Type => SOCK_STREAM,
Reuse => 1,
Listen => 10 ) # or SOMAXCONN
or die "Couldn't be a tcp server on port $server_port: $!\n";

while ($client = $server->accept()) {
$data = <$client>;
#print "$data\n";
#$Data::Dumper::pair = " : "; # specify hash key/value
separator
#$Data::Dumper::Indent = 0;
#eval $data;
print Dumper $data;

You don't need to Dumper it *again*... also, ITY realise that as
you've taken out the eval it won't do owt?
}

close($server);

I would strongly recommend using the Storable module, and the
functions nstore_fd and fd_retrieve. I have had success with this in
the past. Each fd_retrieve will get one whole structure, so you can
push several through the socket one after the other and they won't get
mixed up.

Ben
 
C

Chris

Brad said:
I have been working on this for a few days now, and still feel stuck.
I have a large HASH which I need to send via TCP to a server. I need
to use IO::Socket::INET for the TCP connection. While there is
probably a _better_ way, I have been playing around with Data::Dumper
convert the HASH, then rebuild it on the other end. The problem is I
cannot seem to rebuild the data.

Code:

Client (sending HASH)
---------------------
use Data::Dumper;
use IO::Socket::INET;

$TEST{'test'}{'test1'} = 1;
$TEST{'test2'}{'test3'} = 2;

$socket = IO::Socket::INET->new(PeerAddr => localhost,
PeerPort => 2002,
Proto => "tcp",
Type => SOCK_STREAM)
or die "Couldn't connect to $remote_host:$remote_port : $!\n";

$Data::Dumper::pair = " : "; # specify hash key/value
separator
$Data::Dumper::Indent = 0;
# send something over the socket,
print $socket Dumper(\%TEST);

# and terminate the connection when we're done.
close($socket);
---------------------

Server
---------------------
use Data::Dumper;
use IO::Socket::INET;

$server = IO::Socket::INET->new(LocalPort => 2002,
Type => SOCK_STREAM,
Reuse => 1,
Listen => 10 ) # or SOMAXCONN
or die "Couldn't be a tcp server on port $server_port: $!\n";

while ($client = $server->accept()) {
$data = <$client>;
#print "$data\n";
#$Data::Dumper::pair = " : "; # specify hash key/value
separator
#$Data::Dumper::Indent = 0;
#eval $data;
print Dumper $data;
}

close($server);
---------------------

I have tried other methods of re-building the hash on the server-end.
The answer is probably right in front of me, but I just don't see it
on the module's page (
http://search.cpan.org/~ilyam/Data-Dumper-2.121/Dumper.pm ) or in the
perldoc.

Any help, or any ideas for a better solution, is appreciated.

Aside from Ben Morrow's solution (which I wish I had the time to try),
if you are stuck on a "Dumper()" solution, you might get more mileage
out of the XML::Dumper::pl2xml() and xml2pl() routines. Write yourself
a psuedo-web service that passes XML structures back and forth.
pl2xml() and xml2pl() will handle this rightly.

Without digging into your code too much (seeing as it's way past my bed
time) and surmising WHY you might be trying to accomplish this in the
first place, you may even have your wants satisfied by tossing the
structure passing altogether and writing a real web service using
XML-RPC. Check out Frontier::RPC2 for more information. XML-RPC in
Perl is painless to setup and quite powerful (though inherently insecure
I have to admit). You can setup XML-RPC on your port 2002 if you want.

Chris
 
B

Brad Walton

I would strongly recommend using the Storable module, and the
functions nstore_fd and fd_retrieve. I have had success with this in
the past. Each fd_retrieve will get one whole structure, so you can
push several through the socket one after the other and they won't get
mixed up.

Ben

Thanks! This works great, and is very simple to use. I got it working with
the serialize [freeze, thaw] options. Here is what it looks like:

Client
-----------------
use Storable qw(freeze);
use IO::Socket::INET;

$TEST{'test'}{'test1'} = 1;
$TEST{'test2'}{'test3'} = 2;

$socket = IO::Socket::INET->new(PeerAddr => localhost,
PeerPort => 2002,
Proto => "tcp",
Type => SOCK_STREAM)
or die "Couldn't connect to $remote_host:$remote_port : $!\n";

# Serializing to memory
$serialized = freeze \%TEST;
print $socket $serialized;

# and terminate the connection when we're done.
close($socket);



Server

------------------------

use Storable qw(thaw);
use IO::Socket::INET;

$server = IO::Socket::INET->new(LocalPort => 2002,
Type => SOCK_STREAM,
Reuse => 1,
Listen => 10 ) # or SOMAXCONN
or die "Couldn't be a tcp server on port $server_port: $!\n";

while ($client = $server->accept()) {
$data = <$client>;
%TEST = %{ thaw($data) };

foreach my $key (keys %TEST) {
print "\nValues for $key in \%TEST:\n";
foreach my $key2 (keys %{$TEST{$key}}) {
print "\t$key2 => ", ${$TEST{$key}}{$key2}, "\n";
}
}
}

close($server);
 
B

Ben Morrow

I recommended using nstore_fd and fd_retrieve for several reasons:

1. you don't need to create the Storable structure in memory

2. nstore_fd creates a structure in network byte-order, which can be
important if sending data between machines of different endianness
(and does no harm otherwise)

3. fd_retrieve will find the end of the structure for you: as things
stand you are reading one \n-terminated line, which will break if
the frozen representation has "\n" in it, which is not at all
unlikely.
Client
-----------------

use strict;
use warnings;
use Storable qw(freeze);

use Storable qw(nstore_fd);
use IO::Socket::INET;

my %TEST;
$TEST{'test'}{'test1'} = 1;
$TEST{'test2'}{'test3'} = 2;

$socket = IO::Socket::INET->new(PeerAddr => localhost,

my $socket = ...
PeerPort => 2002,
Proto => "tcp",
Type => SOCK_STREAM)
or die "Couldn't connect to $remote_host:$remote_port : $!\n";

# Serializing to memory
$serialized = freeze \%TEST;
print $socket $serialized;

nstore_fd \%TEST, $socket;
# and terminate the connection when we're done.
close($socket);

Server
------------------------

use strict;
use warnings;
use Storable qw(thaw);

use Storable qw(fd_retrieve);
use IO::Socket::INET;

$server = IO::Socket::INET->new(LocalPort => 2002,

my $server = ...
Type => SOCK_STREAM,
Reuse => 1,
Listen => 10 ) # or SOMAXCONN
or die "Couldn't be a tcp server on port $server_port: $!\n";

while ($client = $server->accept()) {

while (my $client = ...
$data = <$client>;
%TEST = %{ thaw($data) };

%TEST = %{ fd_retrieve $client };
foreach my $key (keys %TEST) {
print "\nValues for $key in \%TEST:\n";

Fix your indenting.
foreach my $key2 (keys %{$TEST{$key}}) {
print "\t$key2 => ", ${$TEST{$key}}{$key2}, "\n";
}
}
}

close($server);

Ben
 
M

Mina Naguib

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Aside from Ben Morrow's solution (which I wish I had the time to try),
if you are stuck on a "Dumper()" solution, you might get more mileage
out of the XML::Dumper::pl2xml() and xml2pl() routines. Write yourself
a psuedo-web service that passes XML structures back and forth. pl2xml()
and xml2pl() will handle this rightly.

Another solution is Net::EasyTCP written by yours truly.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFAMCskeS99pGMif6wRAvi7AJ95L78w00hiBJkMTkoMM+xms3NUAwCg5wj2
Pc6N6gtVrw8PnMvh+nmTqs8=
=ne66
-----END PGP SIGNATURE-----
 
B

Brad Walton

I was actually using that up until I had to make this change. Thanks, it is
a very easy-to-use module and made accomplishing my task (at that time) very
simple. Unfortunately, I could not get it to communicate with a new program
that was introduced to my project, which is not written in Perl and required
a TCP connection.

Brad
 
R

Rocco Caputo

I was actually using that up until I had to make this change. Thanks, it is
a very easy-to-use module and made accomplishing my task (at that time) very
simple. Unfortunately, I could not get it to communicate with a new program
that was introduced to my project, which is not written in Perl and required
a TCP connection.

Have you looked at POE, then? It deals well with TCP connections, and
POE::Filter::Reference can serialize Perl data structures in a number of
ways.
 
A

Anno Siegel

Mina Naguib said:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1



Another solution is Net::EasyTCP written by yours truly.

....and a very fine little module it is. It hides what you don't want to be
bothered with and exposes what you want to decide. It's intuitive, so you
can use it immediately. It deserves its name.

Anno
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top