Sharing a socket between instances

Discussion in 'Perl Misc' started by Derek Basch, Jul 31, 2006.

  1. Derek Basch

    Derek Basch Guest

    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
    Derek Basch, Jul 31, 2006
    #1
    1. Advertising

  2. Derek Basch

    Guest

    "Derek Basch" <> wrote:
    > 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

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
    , Jul 31, 2006
    #2
    1. Advertising

  3. Derek Basch

    Derek Basch Guest

    > 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.");

    <---------------------------------------------------------------------->
    Derek Basch, Jul 31, 2006
    #3
  4. Derek Basch

    Guest

    "Derek Basch" <> wrote:
    >
    > 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

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
    , Jul 31, 2006
    #4
  5. Derek Basch

    Derek Basch Guest

    > > 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?


    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.

    > > #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.


    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)?

    > > <---------------------------------------------------------------------->
    > > #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.


    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
    Derek Basch, Jul 31, 2006
    #5
  6. Derek Basch

    Guest

    "Derek Basch" <> wrote:

    > > > #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.

    >
    > 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

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
    , Jul 31, 2006
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    0
    Views:
    404
  2. John Wohlbier
    Replies:
    2
    Views:
    358
    Josiah Carlson
    Feb 22, 2004
  3. Mike
    Replies:
    3
    Views:
    290
  4. Replies:
    8
    Views:
    447
    James Stroud
    Jan 29, 2009
  5. Leon Bogaert
    Replies:
    6
    Views:
    140
    ara.t.howard
    May 11, 2008
Loading...

Share This Page