How to send struct data over socket?

P

poohc1234

Hi Perl Experts,
I am trying to send a data structure over the IO::Socket, but I think I
may have simplied things and I don't know how to work it out.

server.pl side I print the struct data:

print $sock "$SocketData\n";

hoping that the client would pick up.
Well, I don't know how to handle the incoming ARRAY(0x224fb4) so I can
retrieve the data fields of the struct.

Please advise.
Thanks,
Jiac
 
R

Ruey-Cheng Chen

Actually your code would send out a reference of ARRAY, which is
definitely not what you're been expected. All you have to do is to
'stringify' your data on one end and reform it on the other end.

See if this module, Data::Serializer, could do any help.
 
D

dw

server.pl side I print the struct data:
print $sock "$SocketData\n";
You may also want to consider YAML serialisation, ie:

use YAML;
.....
print $sock YAML::Dump($SocketData);
 
P

poohc1234

Hi,
Thanks for the reply. I have used Data::Dumper to stringify the
structure into a long string, but the part that still confuses is once
the long string is transmitted over the socket, how do I refill the
data fields of the struct?

Please tell me.
Thanks,
jiac
 
P

Paul Lalli

Hi,
Thanks for the reply. I have used Data::Dumper to stringify the
structure into a long string, but the part that still confuses is once
the long string is transmitted over the socket, how do I refill the
data fields of the struct?

Did you actually read the documentation that was suggested to you in
the previous replies?
From `perldoc Data::Dumper` :
Given a list of scalars or reference variables, writes out
their contents in perl syntax. The references can also be
objects. The contents of each variable is output in a
single Perl statement. Handles self-referential structures
correctly.

The return value can be "eval"ed to get back an identical
copy of the original reference structure.

So, if you have

my $saved = Dumper(\%ReallyBigStruct);

and you've sent $saved through your socket, you can get back to your
data by doing:

my $restored = eval $saved;
my %CopyOfReallyBigStruct = %$restored;

(Or, if you want to skip the temp variable...)

my %CopyOfReallyBigStruct = %{eval $saved};

HTH,
Paul Lalli
 
F

Fabian Pilkowski

Thanks for the reply. I have used Data::Dumper to stringify the
structure into a long string, but the part that still confuses is once
the long string is transmitted over the socket, how do I refill the
data fields of the struct?

Just eval() it. Try out:

my $data = eval $string;

Have you really read the docs of Data::Dumper? The second sentence in
paragraph "Description" is:

The return value can be "eval"ed to get back an identical copy of
the original reference structure.

Moreover, the given examples show you exactly this way.

But be aware that you should eval strings only when you know where they
are from. If a string could contain evil code this is IMHO not the best
approach.

regards,
fabian
 
P

poohc1234

Thanks for the reply.
Yes I have glanced over the links. Data::Serializer was not available
for me. I have tried to do the followning:
my $DataBack = eval(Dumper($SocketData));

Note: $SocketData is the struct I define.

but I got confused with the following error.
Global symbol "$VAR1" requires explicit package name at (eval 5) line
1.
...propagated at Server.pl line 21.

Thanks,
Jiac
 
T

Thomas Kratz

Thanks for the reply.
Yes I have glanced over the links. Data::Serializer was not available
for me. I have tried to do the followning:
my $DataBack = eval(Dumper($SocketData));

This will not work. Have a look at the string returned from
Dumper($SocketData). You will find that it is something like

$VAR1 = { ...

If you try to eval this it will try to create a package variable $VAR1 in
the current package (most likely 'main').
Note: $SocketData is the struct I define.

but I got confused with the following error.
Global symbol "$VAR1" requires explicit package name at (eval 5) line
1.
...propagated at Server.pl line 21.

And because you seem to be using strict, perl throws an exception.

Either declare the variable beforehand with:

my $VAR1;

or better read the docs to Data::Dumper, especially the docs for the
Dump() method, which allows you to specify the name of the used variable.
Note: you'd have to declare that, too.

Or better still: use Storable and you don't have to use eval.

Thomas

--
$/=$,,$_=<DATA>,s,(.*),$1,see;__END__
s,^(.*\043),,mg,@_=map{[split'']}split;{#>J~.>_an~>>e~......>r~
$_=$_[$%][$"];y,<~>^,-++-,?{$/=--$|?'"':#..u.t.^.o.P.r.>ha~.e..
'%',s,(.),\$$/$1=1,,$;=$_}:/\w/?{y,_, ,,#..>s^~ht<._..._..c....
print}:y,.,,||last,,,,,,$_=$;;eval,redo}#.....>.e.r^.>l^..>k^.-
 
P

Paul Lalli

Thanks for the reply.
Yes I have glanced over the links. Data::Serializer was not available
for me. I have tried to do the followning:
my $DataBack = eval(Dumper($SocketData));

Note: $SocketData is the struct I define.

but I got confused with the following error.
Global symbol "$VAR1" requires explicit package name at (eval 5) line
1.
...propagated at Server.pl line 21.

Oops. I forgot to enable 'strict' on my testing code before I posted.
Sorry about that.

There are a couple ways to over come this. One would be to explicitly
declare $VAR1 beforehand:
my $VAR1;
my $DataBack = eval(Dumper($SocketData));

Another would be to turn off strict's checking for variables just for
this instance:

my $DataBack;
{
no strict 'vars';
$DataBack = eval(Dumper($SocketData));
}

A third would be to use the Dump() method instead of the Dumper()
function, which allows you to choose the name of your stored data:

my $saved = Data::Dumper->Dump([$SocketData], ['DataBack']);
#send $saved through the socket...
my $DataBack;
eval $saved;


Paul Lalli
 
P

poohc1234

Thanks all, and your time and patience.

I took the shortcut and just defined my $VAR1 for now. I will read
about Storable later. I tried to google about it earlier but couldn't
find as many examples as Dumper...

So, I have a struct $SocketData that I used Dumper to stringify it,
then I replaced '\n' with '--' to perserve data integrity. (If you have
a way better than this, please let me know.) So I have a huge string
with '--' everywhere that I transmit over TCP. Then I replaced '--'
back with '\n' and I do Dumper($buf) to get back the struct.

The strange part is when I tried to print it, there is always
back-slash. Why? Can I get rid of it or how to do so?


BACK $VAR1 = '$VAR1 = bless( [
undef,
[
\'AAA\',
\'BBB\',
\'CCC\'
],
undef,
undef,
\'NoDataReport\',
\'itemA\',
undef,
undef,
400,
[],
undef,
undef,
{},
undef
], \'SocketData\' );

';
 
X

xhoster

Thanks all, and your time and patience.

I took the shortcut and just defined my $VAR1 for now. I will read
about Storable later.

After you waste your (and our) time figuring out how to make Data::Dumper
work for you, you will read about a module which have made it much easier
from the start? Strange priorities you have there.

I tried to google about it earlier but couldn't
find as many examples as Dumper...

So, I have a struct $SocketData that I used Dumper to stringify it,
then I replaced '\n' with '--' to perserve data integrity.

I like it it. A combination of "preserve" or "pervert".
(If you have
a way better than this, please let me know.)

How about just setting Indent to 0?
So I have a huge string
with '--' everywhere that I transmit over TCP. Then I replaced '--'
back with '\n' and I do Dumper($buf) to get back the struct.

You need to un-dump it, not re-dump it.
The strange part is when I tried to print it, there is always
back-slash. Why?

Because that is how one escapes quote marks when one want them to appear
as literals rather than be interpreted as end-quotes.
Can I get rid of it or how to do so?

BACK $VAR1 = '$VAR1 = bless( [
undef,
[
\'AAA\',
....


Xho
 
F

Fabian Pilkowski

I took the shortcut and just defined my $VAR1 for now. I will read
about Storable later. I tried to google about it earlier but couldn't
find as many examples as Dumper...

So, I have a struct $SocketData that I used Dumper to stringify it,
then I replaced '\n' with '--' to perserve data integrity. (If you have
a way better than this, please let me know.) So I have a huge string
with '--' everywhere that I transmit over TCP. Then I replaced '--'
back with '\n' and I do Dumper($buf) to get back the struct.

Try out:

use Data::Dumper;
$Data::Dumper::Indent = 0;
my $string = Dumper( $data );
print $string; # transmit over TCP ...

This is already described in the docs.
The strange part is when I tried to print it, there is always
back-slash. Why? Can I get rid of it or how to do so?

BACK $VAR1 = '$VAR1 = bless( [
undef,
[
\'AAA\',
\'BBB\',
\'CCC\'
],

[...]

This looks like you have dumped your dumped string again, did you? Or
you have used "eval BLOCK" instead of "eval STRING". Generally it's
enough to call

my $data = eval $string;

to get the data back, but since you use strict (sure, you should to so
always) you have to do one of the following:

# de-activate strict for a small block
my $data = do { no strict 'vars'; eval $string };

# declare the vars explicitly
my $data = do { my $VAR1; eval $string };

regards,
fabian
 
P

poohc1234

Hi all,
Thank you for your replies and help. I realized the part I should use
eval first instead of re-dumping the string I received on the client
side. I have tried with your suggestion and through printout I see I
can get the data on the client side with

$SocketData = do { my $VAR1; eval $buf };
$Temp = Dumper ($SocketData);
print "DATA $Temp\n"; #This prints out all the data received from the
server

but the part I still need your help on, perhaps this is what
(e-mail address removed) meant by going about it the long/wrong way, is how to
do I get the individual fields filled up? I can't do
$SocketData->ItemName on the client side, this generates

Can't call method "ItemName" on an undefined value at Client.pl line
39, <GEN1> line 1.

Is it to use storable?
server does:
store(\%color, 'mycolors') or die "Can't store %a in mycolors!\n";
and send mycolors to client

client does:
$colref = retrieve('mycolors');

PS: Fabian, I don't usually use eval because it doesn't make much sense
to me. So no, I am not using either eval STRING or eval BLOCK.

Thank you,
jiac
 
F

Fabian Pilkowski

Thank you for your replies and help. I realized the part I should use
eval first instead of re-dumping the string I received on the client
side. I have tried with your suggestion and through printout I see I
can get the data on the client side with

$SocketData = do { my $VAR1; eval $buf };
$Temp = Dumper ($SocketData);
print "DATA $Temp\n"; #This prints out all the data received from the
server

but the part I still need your help on, perhaps this is what
(e-mail address removed) meant by going about it the long/wrong way, is how to
do I get the individual fields filled up? I can't do
$SocketData->ItemName on the client side, this generates

Can't call method "ItemName" on an undefined value at Client.pl line
39, <GEN1> line 1.

I'm not able to reproduce this message. When this message appears you
have called the method "ItemName" on an undefined value. Accordingly,
your var $SocketData must be undefined. Please check this again.

If I stringify an object with Data::Dumper and get it back with eval() I
haven't such a problem. I could call its methods afterwards. Have a look
at the following example.


#!/usr/bin/perl -w
use strict;
use warnings;
use Data::Dumper;

{
package MyTest;
sub new { bless { key => 42 }, shift }
sub getKey { $_[0]->{key} }
}

# create object
my $data = new MyTest;
print $data->getKey, "\n";

# stringify object
$Data::Dumper::Indent = 0;
my $string = Dumper( $data );
print $string, "\n";

# create new object from the stringified one
my $newdata = do { my $VAR1; eval $string };
warn $@ if $@;

# test new object
print Dumper( $newdata ), "\n";
print $newdata->getKey;
__END__
42
$VAR1 = bless( {'key' => 42}, 'MyTest' );
$VAR1 = bless( {'key' => 42}, 'MyTest' );
42


Could you adjust this example to your situation to reproduce your error
message? I don't know what you're trying to do this.

Just an idea: Is your module "SocketData" available (and loaded) at
client side?

regards,
fabian
 
T

Thomas Kratz

Is it to use storable?
server does:
store(\%color, 'mycolors') or die "Can't store %a in mycolors!\n";
and send mycolors to client

No, you want to send data over a socket so you use

print { $sock } nfreeze(\%color);
client does:
$colref = retrieve('mycolors');

my $colref = thaw($data_read_from_socket)

Please read the docs for Storable. Completely! Not only the beginning of
the Synopsis.

Thomas

--
$/=$,,$_=<DATA>,s,(.*),$1,see;__END__
s,^(.*\043),,mg,@_=map{[split'']}split;{#>J~.>_an~>>e~......>r~
$_=$_[$%][$"];y,<~>^,-++-,?{$/=--$|?'"':#..u.t.^.o.P.r.>ha~.e..
'%',s,(.),\$$/$1=1,,$;=$_}:/\w/?{y,_, ,,#..>s^~ht<._..._..c....
print}:y,.,,||last,,,,,,$_=$;;eval,redo}#.....>.e.r^.>l^..>k^.-
 

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
474,174
Messages
2,570,941
Members
47,476
Latest member
blackwatermelon

Latest Threads

Top