Sharing a socket between instances

D

Derek Basch

I can only imagine what kind of problems would occur if I were to share
a socket between several instances of the Gps object. Short of threads,
forks or locking what would be the proper way to do something similar?

package Gps;
use base qw(Class::Accessor);
use IO::Socket;
use Error qw:)try);

# Declare class variables.
my $gpsclientport = 1409;
my $remote_port = 6635;
my $peer_addr = 'gps.spanky.com';

try {
$gps_socket = IO::Socket::INET->new(PeerAddr => $peer_addr,
PeerPort => $remote_port,
Proto => 'tcp',
Type => SOCK_STREAM) or throw Error::Simple("Can't bind socket\n");
}
catch Error with {
$E = shift;
print STDERR "File ", $E->{'-file'}, $E->{'-text'}, " \n";
};

Meanwhile back at the ranch!!
use GPS;
$a = Gps->new();
$b = Gps->new();
Do some socket client stuff......

Thanks everyone,
Derek Basch
 
X

xhoster

Derek Basch said:
I can only imagine what kind of problems would occur if I were to share
a socket between several instances of the Gps object.

Without more information, I can't even do that. :) Well, I mean I can, but
then there is no reason to think my imaginings would be at all relevent
to anything you care about.
Short of threads,
forks or locking what would be the proper way to do something similar?

It is not clear what you are trying to do, so I don't know what would be
similar to it (or why you would expect threads or forks to make things
better rather than worse; or why locking on a socket would be necessary in
the absense of forking or threads.)
package Gps;
use base qw(Class::Accessor);
use IO::Socket;
use Error qw:)try);

# Declare class variables.
my $gpsclientport = 1409;
my $remote_port = 6635;
my $peer_addr = 'gps.spanky.com';

Isn't $gps_socket a class variable? Why isn't it declared?
try {
$gps_socket = IO::Socket::INET->new(PeerAddr => $peer_addr,
PeerPort => $remote_port,
Proto => 'tcp',
Type => SOCK_STREAM) or throw Error::Simple("Can't bind socket\n");
}
catch Error with {
$E = shift;
print STDERR "File ", $E->{'-file'}, $E->{'-text'}, " \n";
};

Since this doesn't seem to be fatal, I take it that the socket is only
incidental to the operation of your program and not central to it?

Meanwhile back at the ranch!!
use GPS;
$a = Gps->new();
$b = Gps->new();
Do some socket client stuff......

Presumable the problem arises when you use your socket. But you haven't
shown us anything that uses the socket. Is this a write-only socket?
How are messages delimited?

Xho
 
D

Derek Basch

It is not clear what you are trying to do, so I don't know what would be
similar to it (or why you would expect threads or forks to make things
better rather than worse; or why locking on a socket would be necessary in
the absense of forking or threads.)
Presumable the problem arises when you use your socket. But you haven't
shown us anything that uses the socket. Is this a write-only socket?
How are messages delimited?

Sorry, I was trying to keep my example concise but I guess I made it to
concise.

I am attempting to create a 'Member' object that represents a member of
a club. Lets say a gardening club. Members have attributes that are
stored on a telnet server called Gps and I am using an overridden
Class::Accessor object to get/set those attributes. The telnet server
requires that the Members numeric ID attribute be set prior to
getting/setting a Members attribute (address for example).

So, if I have 30,000 'Member' instances all sharing a single socket I
am afraid that the 'member_id' state of the socket will be changed by
another 'Member' instance ($b) before the 'address' attribute of the
first instance ($a) is set. Is this a valid concern?

<---------------------------------------------------------------------->
package Gps;
use base qw(Class::Accessor);
use IO::Socket;
use Error qw:)try);

# Declare class variables.
my $gpsclientport = 1409;
my $remote_port = 6635;
my $peer_addr = 'gps.spanky.com';
my $gps_socket;

try {
$gps_socket = IO::Socket::INET->new(PeerAddr => $peer_addr,
PeerPort => $remote_port,
Proto => 'tcp',
Type => SOCK_STREAM) or throw Error::Simple("Can't bind socket\n");
}

catch Error with {
$E = shift;
print STDERR "File ", $E->{'-file'}, $E->{'-text'}, " \n";

}

sub get {
my ($self, $key) = @_;
# get the desired value by key
@response = $self->_doCommand("get $key");
$value = join("", grep(!/^$key:/, @response));
return $value;
}

sub set {
my ($self, $key, $value) = splice(@_, 0, 3);
# set the desired value by key/value
@response = $self->_doCommand("set $key $value");
$value = join("", grep(!/^$key:/, @response));
return $value;
}

sub _doCommand {
($self, $command) = @_;

my @response;
try {
# Check that the socket is available
$gps_socket or throw Error::Simple("Can't bind : $gps_socket\n");

# set the user by user_id
print $gps_socket "ID $self->user_id", "\r\n";

#member_id state could be changed here by another Member instance
#calling the socket at the same time??????????

# print to the GPS socket
print $gps_socket $command, "\r\n";

while (<$gps_socket>) {
chop;
last if /^###/;
push (@response, $_);
}
throw Error::Simple("@response") if (grep(/Error/i, @response));
}
catch Error with {
$E = shift;
print STDERR "$E->{-text}\n";
}
finally {
return @response;
};
}

1;
<---------------------------------------------------------------------->

package Member;
use Gps;

sub new {
my $class = shift;
my $self = {};
$self->{'Gps'} = Gps->new;
bless ($self, $class);
return $self;
}

1;

<---------------------------------------------------------------------->
#Meanwhile in some other code

use Member;
$a = Member->new;

$a->{'Gps'}->user_id(323775);
$a->{'Gps'}->address("1234 Fake St.");


<---------------------------------------------------------------------->
#Meanwhile in some other code

use Member;
$b = Member->new;

$b->{'Gps'}->user_id(323776);
$b->{'Gps'}->address("666 Devil St.");

<---------------------------------------------------------------------->
 
X

xhoster

Derek Basch said:
I am attempting to create a 'Member' object that represents a member of
a club. Lets say a gardening club. Members have attributes that are
stored on a telnet server called Gps and I am using an overridden
Class::Accessor object to get/set those attributes. The telnet server
requires that the Members numeric ID attribute be set prior to
getting/setting a Members attribute (address for example).

So, if I have 30,000 'Member' instances all sharing a single socket I
am afraid that the 'member_id' state of the socket will be changed by
another 'Member' instance ($b) before the 'address' attribute of the
first instance ($a) is set. Is this a valid concern? .....

sub _doCommand {
($self, $command) = @_;

my @response;
try {
# Check that the socket is available
$gps_socket or throw Error::Simple("Can't bind : $gps_socket\n");

# set the user by user_id
print $gps_socket "ID $self->user_id", "\r\n";

This doesn't print you think it prints. Method calls are not interpolated
into double-quotes. And if it did do that, then this would be the start of
an infinite recursion, would it not?
#member_id state could be changed here by another Member instance
#calling the socket at the same time??????????

# print to the GPS socket
print $gps_socket $command, "\r\n";

while (<$gps_socket>) {
chop;
last if /^###/;
push (@response, $_);
}
throw Error::Simple("@response") if (grep(/Error/i, @response));

In the absence of threads or fork (and the infinite recursion previously
mentioned), no _doCommand method serving a different Member instance can
seize control of the program during this code, so there should be no
problem with the state being changed.
<---------------------------------------------------------------------->
#Meanwhile in some other code

use Member;
$a = Member->new;

Shouldn't setting the user_id be part of the new()? Since it doesn't
make sense to do anything (including setting the user_id) on a Member with
an unset user_id.
$a->{'Gps'}->user_id(323775);
$a->{'Gps'}->address("1234 Fake St.");


Xho
 
D

Derek Basch

sub _doCommand {
This doesn't print you think it prints. Method calls are not interpolated
into double-quotes. And if it did do that, then this would be the start of
an infinite recursion, would it not?

Yes, you are right it would create an infinite recursion. However, once
again, I was trying to be concise and didn't include the overidden
accessor function for user_id:

sub user_id {
my($self) = shift;
my($user_id) = @_;
return $self->_user_id_accessor(@_);
}

This prevents the recursion for reasons that are explained in gory
detail here:
http://search.cpan.org/~kasei/Class...ccessor.pm#Overriding_autogenerated_accessors

I did not know that the return value of methods could not be
interpolated. I guess I would have found out when I tried to run the
code :). I suppose I should use concatenation instead.
In the absence of threads or fork (and the infinite recursion previously
mentioned), no _doCommand method serving a different Member instance can
seize control of the program during this code, so there should be no
problem with the state being changed.

Thanks for the information. Is this idiom documented anywhere? I
couldn't seem to find anything on the subject of order of execution and
locking for class variables. How does Perl know that the class variable
filehandle (file_handle) which is being called by an instance (foo) is
locked because a different instance (foo2) is already using that same
filehandle (file_handle)?
Shouldn't setting the user_id be part of the new()? Since it doesn't
make sense to do anything (including setting the user_id) on a Member with
an unset user_id.

Yes, I was planning on implementing that once I figured out this
problem. So, setting the member_id using a constructor would ensure
that the member_id is available for any instance of 'Member'. However,
it seems that the member_id state would still have to be set prior to
any subsequent attribute gets/sets for that Member instance and my
original "problem" of conflicting filehandle access would still be
valid.

Such as:

# set the user by user_id
# user_id is set as a parameter to the class constructor
print $gps_socket "ID" . $self->user_id . "\r\n";

#member_id state could be changed here by another Member instance
#calling the socket at the same time??????????

# print to the GPS socket
print $gps_socket $command, "\r\n";

while (<$gps_socket>) {
chop;
last if /^###/;
push (@response, $_);
}

Thanks for all the help. I really appreciate it.

Derek Basch
 
X

xhoster

Derek Basch said:
Thanks for the information. Is this idiom documented anywhere?

I don't think so, as I don't think there is anything to document!
I
couldn't seem to find anything on the subject of order of execution and
locking for class variables. How does Perl know that the class variable
filehandle (file_handle) which is being called by an instance (foo) is
locked because a different instance (foo2) is already using that same
filehandle (file_handle)?

It doesn't know that. In a single threaded program, there is only one
thread of execution. There is no need to lock the socket handle (or
a regular variable protecting the socket handle), because there is no one
to lock it against. You have the world all to yourself, you are the only
person driving on the roads. You don't have to install traffic lights,
because there is no one out there to hit. (You still need to be careful
not to run off the road and drive into a tree, or have a rock slide land on
your car, but that is a different matter.)

%SIG handlers should not read or write to the socket handle. But why would
they want to do that? _doCommand needs to not make recursive calls into
itself (either directly or indirectly) during the vulnerable part (between
the first print of the ID through the last read of the response to the
command). But why would it?


Xho
 

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

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top