Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #10627 > unrolled thread

Method that only one other class type may access

Started byChristopher <cpisz@austin.rr.com>
First post2011-10-01 13:32 -0700
Last post2011-10-05 00:02 -0700
Articles 18 — 8 participants

Back to article view | Back to comp.lang.c++


Contents

  Method that only one other class type may access Christopher <cpisz@austin.rr.com> - 2011-10-01 13:32 -0700
    Re: Method that only one other class type may access Christopher <cpisz@austin.rr.com> - 2011-10-01 13:50 -0700
      Re: Method that only one other class type may access Noah Roberts <roberts.noah@gmail.com> - 2011-10-02 11:13 -0700
    Re: Method that only one other class type may access Marcel Müller <news.5.maazl@spamgourmet.com> - 2011-10-01 23:38 +0200
      Re: Method that only one other class type may access Christopher <cpisz@austin.rr.com> - 2011-10-01 15:34 -0700
        Re: Method that only one other class type may access Marcel Müller <news.5.maazl@spamgourmet.com> - 2011-10-02 15:27 +0200
    Re: Method that only one other class type may access Noah Roberts <roberts.noah@gmail.com> - 2011-10-02 11:06 -0700
    Re: Method that only one other class type may access Paul N <gw7rib@aol.com> - 2011-10-03 11:48 -0700
    Re: Method that only one other class type may access Ian Collins <ian-news@hotmail.com> - 2011-10-04 08:10 +1300
      Re: Method that only one other class type may access Jorgen Grahn <grahn+nntp@snipabacken.se> - 2011-10-03 20:49 +0000
        Re: Method that only one other class type may access Ian Collins <ian-news@hotmail.com> - 2011-10-04 15:01 +1300
          Re: Method that only one other class type may access Christopher <cpisz@austin.rr.com> - 2011-10-04 14:21 -0700
            Re: Method that only one other class type may access Ian Collins <ian-news@hotmail.com> - 2011-10-05 10:29 +1300
              Re: Method that only one other class type may access Jorgen Grahn <grahn+nntp@snipabacken.se> - 2011-10-05 08:19 +0000
                Re: Method that only one other class type may access Ian Collins <ian-news@hotmail.com> - 2011-10-05 21:39 +1300
                  Re: Method that only one other class type may access Miles Bader <miles@gnu.org> - 2011-10-05 18:09 +0900
                  Re: Method that only one other class type may access Jorgen Grahn <grahn+nntp@snipabacken.se> - 2011-10-05 18:30 +0000
    Re: Method that only one other class type may access Werner <werasm@gmail.com> - 2011-10-05 00:02 -0700

#10627 — Method that only one other class type may access

FromChristopher <cpisz@austin.rr.com>
Date2011-10-01 13:32 -0700
SubjectMethod that only one other class type may access
Message-ID<bcec6bc0-d419-48b4-a17a-58efec51260e@j19g2000yqc.googlegroups.com>
I know I need some sort of friend, but I don't want to friend the
entire class.

I've got a TcpConnection class and it has a state member.
I've got a TcpListener class that accepts connections and creates a
TcpConnectionClass.

The TcpListener class needs to be able to change the state member of
the TcpConnection class, but I don't want anyone else to be able to.
How do I go about that?

[toc] | [next] | [standalone]


#10628

FromChristopher <cpisz@austin.rr.com>
Date2011-10-01 13:50 -0700
Message-ID<c5f9ad3c-9ae2-4ef8-ad99-e667ed6ceb97@e9g2000vby.googlegroups.com>
In reply to#10627
On Oct 1, 3:32 pm, Christopher <cp...@austin.rr.com> wrote:
> I know I need some sort of friend, but I don't want to friend the
> entire class.
>
> I've got a TcpConnection class and it has a state member.
> I've got a TcpListener class that accepts connections and creates a
> TcpConnectionClass.
>
> The TcpListener class needs to be able to change the state member of
> the TcpConnection class, but I don't want anyone else to be able to.
> How do I go about that?

Problem 1 is that the first class needs to be aware of the second, so
when I use friend function I have a circular dependency problem when
keeping seperate headers.

Problem 2 is that the function I want to friend is virtual. I cannot
find whether or not making it a friend also makes its derived type
implementations of that function a friend also.

Problem 3 is that I will also derive from the class I am allowing
access to.
          So, I want class B and all its derived types to have access
to the data in class A and all its derived types.

[toc] | [prev] | [next] | [standalone]


#10637

FromNoah Roberts <roberts.noah@gmail.com>
Date2011-10-02 11:13 -0700
Message-ID<00053ccf-0c1e-4b9b-8652-4c83214f789d@dd6g2000vbb.googlegroups.com>
In reply to#10628
On Oct 1, 1:50 pm, Christopher <cp...@austin.rr.com> wrote:
> On Oct 1, 3:32 pm, Christopher <cp...@austin.rr.com> wrote:
>
> > I know I need some sort of friend, but I don't want to friend the
> > entire class.
>
> > I've got a TcpConnection class and it has a state member.
> > I've got a TcpListener class that accepts connections and creates a
> > TcpConnectionClass.
>
> > The TcpListener class needs to be able to change the state member of
> > the TcpConnection class, but I don't want anyone else to be able to.
> > How do I go about that?
>
> Problem 1 is that the first class needs to be aware of the second, so
> when I use friend function I have a circular dependency problem when
> keeping seperate headers.

No you don't, because you're going to forward declare your classes
only in headers and only include stuff you are USING in that file.
>
> Problem 2 is that the function I want to friend is virtual. I cannot
> find whether or not making it a friend also makes its derived type
> implementations of that function a friend also.

Have the functor I described in my last post call a protected virtual
function.
>
> Problem 3 is that I will also derive from the class I am allowing
> access to.
>           So, I want class B and all its derived types to have access
> to the data in class A and all its derived types.

Have a protected function in the base Listener that can be called by
derived functions.  Do your friendly access here.  Your derived
objects won't be able to access the class that friended the base
directly.

Of course, as others have said this is probably a bad design.  It is
certainly more than just a little coupled.  But if you really need to,
that's one way it could be done.

[toc] | [prev] | [next] | [standalone]


#10629

FromMarcel Müller <news.5.maazl@spamgourmet.com>
Date2011-10-01 23:38 +0200
Message-ID<4e87885e$0$6626$9b4e6d93@newsspool2.arcor-online.net>
In reply to#10627
On 01.10.2011 22:32, Christopher wrote:
> I know I need some sort of friend, but I don't want to friend the
> entire class.
>
> I've got a TcpConnection class and it has a state member.
> I've got a TcpListener class that accepts connections and creates a
> TcpConnectionClass.
>
> The TcpListener class needs to be able to change the state member of
> the TcpConnection class, but I don't want anyone else to be able to.
> How do I go about that?

Most likely you have a design problem. A listener should not change any 
other state than its own. A listener is a listener and a connection is a 
connection. Why should a listener manipulate the connection state. What 
about race conditions?

There are ways to do so, but I am in doubt whether this is a good 
advise. You could create a base class of your connection to isolate the 
state member and make the listener a friend of this base class.


Marcel

[toc] | [prev] | [next] | [standalone]


#10630

FromChristopher <cpisz@austin.rr.com>
Date2011-10-01 15:34 -0700
Message-ID<353d98b1-8852-4e2f-bdd0-8707882aae0c@x16g2000yql.googlegroups.com>
In reply to#10629
On Oct 1, 4:38 pm, Marcel Müller <news.5.ma...@spamgourmet.com> wrote:
> On 01.10.2011 22:32, Christopher wrote:
>
> > I know I need some sort of friend, but I don't want to friend the
> > entire class.
>
> > I've got a TcpConnection class and it has a state member.
> > I've got a TcpListener class that accepts connections and creates a
> > TcpConnectionClass.
>
> > The TcpListener class needs to be able to change the state member of
> > the TcpConnection class, but I don't want anyone else to be able to.
> > How do I go about that?
>
> Most likely you have a design problem. A listener should not change any
> other state than its own. A listener is a listener and a connection is a
> connection. Why should a listener manipulate the connection state. What
> about race conditions?
>
> There are ways to do so, but I am in doubt whether this is a good
> advise. You could create a base class of your connection to isolate the
> state member and make the listener a friend of this base class.
>
> Marcel

Well, the listener accepts connections right?
So, it creates a connection in the NOT_CONNECTED state.
It queues it up for an accept via boost::asio
When the accept completes the listener is notified via boost::asio
  the listener has to be notified, so it can add the connection to its
collection of clients
Now we have a connected connection in a NOT_CONNECTED state = bad.

I was fiddling with the boost::binds that the boost::asio example uses
and was thinking maybe:
I could have the listener post the accept request with a callback to
the connection itself
Have the connection itself, in its callback, call a callback on the
listener.

I don't want to turn things in to spaghetti though.

[toc] | [prev] | [next] | [standalone]


#10634

FromMarcel Müller <news.5.maazl@spamgourmet.com>
Date2011-10-02 15:27 +0200
Message-ID<4e8866c9$0$7612$9b4e6d93@newsspool1.arcor-online.net>
In reply to#10630
On 02.10.2011 00:34, Christopher wrote:
>> Most likely you have a design problem. A listener should not change any
>> other state than its own. A listener is a listener and a connection is a
>> connection. Why should a listener manipulate the connection state. What
>> about race conditions?
>>
>> There are ways to do so, but I am in doubt whether this is a good
>> advise. You could create a base class of your connection to isolate the
>> state member and make the listener a friend of this base class.
>
> Well, the listener accepts connections right?
> So, it creates a connection in the NOT_CONNECTED state.
> It queues it up for an accept via boost::asio
> When the accept completes the listener is notified via boost::asio
>    the listener has to be notified, so it can add the connection to its
> collection of clients
> Now we have a connected connection in a NOT_CONNECTED state = bad.

Move the connection pool to the connection class (or a separate 
connection pool class) and provide a public factory function that 
initiates a connected connection.


> I was fiddling with the boost::binds that the boost::asio example uses
> and was thinking maybe:
> I could have the listener post the accept request with a callback to
> the connection itself
> Have the connection itself, in its callback, call a callback on the
> listener.

Sorry, I didn't catch what you mean.


Marcel

[toc] | [prev] | [next] | [standalone]


#10636

FromNoah Roberts <roberts.noah@gmail.com>
Date2011-10-02 11:06 -0700
Message-ID<ca3d455e-8f14-4cdc-baa1-89145d0e4e35@g33g2000yqc.googlegroups.com>
In reply to#10627
On Oct 1, 1:32 pm, Christopher <cp...@austin.rr.com> wrote:
> I know I need some sort of friend, but I don't want to friend the
> entire class.
>
> I've got a TcpConnection class and it has a state member.
> I've got a TcpListener class that accepts connections and creates a
> TcpConnectionClass.
>
> The TcpListener class needs to be able to change the state member of
> the TcpConnection class, but I don't want anyone else to be able to.
> How do I go about that?

I think you could do this with a function object.  Something like this
untested bit:

struct TcpListener;

struct TcpConnection
{
  struct funky_operator
  {
    friend class TcpListener;
    funky_operator(TcpConnection * c) : conn(c) {}
  private:
    void operator() (??) { ?? }
    TcpConnection * conn;
  };
  friend class funky_operator;
  funky_operator op;

  TcpConnection() : op(this) {}
};

Now, everyone can see "op" but only TcpListener can call it.

[toc] | [prev] | [next] | [standalone]


#10647

FromPaul N <gw7rib@aol.com>
Date2011-10-03 11:48 -0700
Message-ID<15da48a1-e9fc-4eb5-8e95-503207d99da6@de2g2000vbb.googlegroups.com>
In reply to#10627
On Oct 1, 9:32 pm, Christopher <cp...@austin.rr.com> wrote:
> I know I need some sort of friend, but I don't want to friend the
> entire class.
>
> I've got a TcpConnection class and it has a state member.
> I've got a TcpListener class that accepts connections and creates a
> TcpConnectionClass.
>
> The TcpListener class needs to be able to change the state member of
> the TcpConnection class, but I don't want anyone else to be able to.
> How do I go about that?

As a very low tech solution - but which may be sufficient for you...

Why not provide a suitable access function to do what needs to be
done, but give it a long name that includes the name of the class/
function that you want to give access to? Any other programmers will
see that the function exists but will realise that they're not meant
to use it.

Paul.

[toc] | [prev] | [next] | [standalone]


#10649

FromIan Collins <ian-news@hotmail.com>
Date2011-10-04 08:10 +1300
Message-ID<9eufl3F5kfU7@mid.individual.net>
In reply to#10627
On 10/ 2/11 09:32 AM, Christopher wrote:
> I know I need some sort of friend, but I don't want to friend the
> entire class.
>
> I've got a TcpConnection class and it has a state member.
> I've got a TcpListener class that accepts connections and creates a
> TcpConnectionClass.
>
> The TcpListener class needs to be able to change the state member of
> the TcpConnection class, but I don't want anyone else to be able to.
> How do I go about that?

If a design doesn't fit the problem, the design is flawed.  It looks to 
me like you are over engineering what is a very simple (and common) 
task.  Don't fret though, I see this all the time!  Socket related 
activities simply don't fit well within an OO approach.

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#10650

FromJorgen Grahn <grahn+nntp@snipabacken.se>
Date2011-10-03 20:49 +0000
Message-ID<slrnj8k7uc.1bk.grahn+nntp@frailea.sa.invalid>
In reply to#10649
On Mon, 2011-10-03, Ian Collins wrote:
> On 10/ 2/11 09:32 AM, Christopher wrote:
>> I know I need some sort of friend, but I don't want to friend the
>> entire class.
>>
>> I've got a TcpConnection class and it has a state member.
>> I've got a TcpListener class that accepts connections and creates a
>> TcpConnectionClass.
>>
>> The TcpListener class needs to be able to change the state member of
>> the TcpConnection class, but I don't want anyone else to be able to.
>> How do I go about that?
>
> If a design doesn't fit the problem, the design is flawed.  It looks to 
> me like you are over engineering what is a very simple (and common) 
> task.  Don't fret though, I see this all the time!  Socket related 
> activities simply don't fit well within an OO approach.

It is not clear to me what you mean with that last sentence, but I was
going to say something similar:

I see no great benefits of wrapping the BSD socket API in lots of stuff.
If you wrap them a bit to get:

- file descriptors which aren't convertible to and from ints
- RAII

then the API is pretty usable as it is. Bonus: anyone who knows the
API doesn't have to relearn another one.

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .

[toc] | [prev] | [next] | [standalone]


#10654

FromIan Collins <ian-news@hotmail.com>
Date2011-10-04 15:01 +1300
Message-ID<9ev7noFdlfU1@mid.individual.net>
In reply to#10650
On 10/ 4/11 09:49 AM, Jorgen Grahn wrote:
> On Mon, 2011-10-03, Ian Collins wrote:
>> On 10/ 2/11 09:32 AM, Christopher wrote:
>>> I know I need some sort of friend, but I don't want to friend the
>>> entire class.
>>>
>>> I've got a TcpConnection class and it has a state member.
>>> I've got a TcpListener class that accepts connections and creates a
>>> TcpConnectionClass.
>>>
>>> The TcpListener class needs to be able to change the state member of
>>> the TcpConnection class, but I don't want anyone else to be able to.
>>> How do I go about that?
>>
>> If a design doesn't fit the problem, the design is flawed.  It looks to
>> me like you are over engineering what is a very simple (and common)
>> task.  Don't fret though, I see this all the time!  Socket related
>> activities simply don't fit well within an OO approach.
>
> It is not clear to me what you mean with that last sentence, but I was
> going to say something similar:

Trying to use things like connection and listener classes!

> I see no great benefits of wrapping the BSD socket API in lots of stuff.
> If you wrap them a bit to get:
>
> - file descriptors which aren't convertible to and from ints
> - RAII
>
> then the API is pretty usable as it is. Bonus: anyone who knows the
> API doesn't have to relearn another one.

Agreed.

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#10670

FromChristopher <cpisz@austin.rr.com>
Date2011-10-04 14:21 -0700
Message-ID<840429b4-ebb0-41ae-ab28-0934af8b91e9@m15g2000vbk.googlegroups.com>
In reply to#10654
On Oct 3, 9:01 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> On 10/ 4/11 09:49 AM, Jorgen Grahn wrote:
>
>
>
>
>
> > On Mon, 2011-10-03, Ian Collins wrote:
> >> On 10/ 2/11 09:32 AM, Christopher wrote:
> >>> I know I need some sort of friend, but I don't want to friend the
> >>> entire class.
>
> >>> I've got a TcpConnection class and it has a state member.
> >>> I've got a TcpListener class that accepts connections and creates a
> >>> TcpConnectionClass.
>
> >>> The TcpListener class needs to be able to change the state member of
> >>> the TcpConnection class, but I don't want anyone else to be able to.
> >>> How do I go about that?
>
> >> If a design doesn't fit the problem, the design is flawed.  It looks to
> >> me like you are over engineering what is a very simple (and common)
> >> task.  Don't fret though, I see this all the time!  Socket related
> >> activities simply don't fit well within an OO approach.
>
> > It is not clear to me what you mean with that last sentence, but I was
> > going to say something similar:
>
> Trying to use things like connection and listener classes!
>
> > I see no great benefits of wrapping the BSD socket API in lots of stuff.
> > If you wrap them a bit to get:
>
> > - file descriptors which aren't convertible to and from ints
> > - RAII
>
> > then the API is pretty usable as it is. Bonus: anyone who knows the
> > API doesn't have to relearn another one.
>
> Agreed.
>
> --
> Ian Collins- Hide quoted text -
>
> - Show quoted text -

Yes, I am coming to realize the sockets just don't fit OO.
The concept that a listener creates an accepted connection, but the
accepted connection does the communicating is a pain in my butt.
I've done many socket implementations before and didn't have such a
problem with this, the added restrictions of how boost::asio::ip::tcp
works is really adding headaches.

Any operation gets posted for completion and calls back a given method
when it completes. that is enforced by boost::asio::ip::tcp
asynchronous calls.

Well Ok, so the listener gets notified when an accept has occured.
boo.
Now the state of the new connection needs to change and do the things
it does when it gets connected!
So, either
1) The listener has to tell the accepted connection, "you are alive
now" or
2) We change the callback to the connection itself, who has to tell
the listener, "Hey, I'm alive now, do stuff with me or hand me off to
someone"

Either way there is a circular dependancy.
----
Forward declarations to get rid of this circular dependency do not
seem to work, because of another restriction that is a side effect
from using boost::asio::ip::tcp.

I must make sure that every object in my inheritance tree that will
post an operation for io-completion, gets instantiated as a
shared_ptr, such that the object is guarenteed to stay alive between
the times of posting an operation and the time it completes.

So, when it comes into the code:

class Listener;

Connection::Accepted(/*stuff*/)
{
   // Snip
   listenerPtr->OnAccepted(shared_from_this());
}

The compiler has to see the declaration of Listener::OnAccepted, the
Listener::SmartPtr, etc.
----------

So what I've decided to do....and I hate doing it...it deriving a
ServerSideConnection class that has the accept, onaccept methods, etc.
and takes, upon its construction, a whole bunch of boost::functions
that can be called back. Then when the connection gets notified of
something, it in turn notifies the listener...This is ugly because
I've got callback everywhere, its debugging hell, and I've got quite a
number of connection implementations that do nothing but get notified
and notify the listener...yuck!

I don't see a way around it.
---------

I suppose when I get time, I'll try and write up a visible and
simplified example explaining my problems on my website and then point
people to it for comment. It might just be too big and complex of a
thing...and off topic...to get into the details here.
















[toc] | [prev] | [next] | [standalone]


#10671

FromIan Collins <ian-news@hotmail.com>
Date2011-10-05 10:29 +1300
Message-ID<9f1c51F4qnU1@mid.individual.net>
In reply to#10670
On 10/ 5/11 10:21 AM, Christopher wrote:
>
> So what I've decided to do....and I hate doing it...it deriving a
> ServerSideConnection class that has the accept, onaccept methods, etc.
> and takes, upon its construction, a whole bunch of boost::functions
> that can be called back. Then when the connection gets notified of
> something, it in turn notifies the listener...This is ugly because
> I've got callback everywhere, its debugging hell, and I've got quite a
> number of connection implementations that do nothing but get notified
> and notify the listener...yuck!
>
> I don't see a way around it.

Just use the native interface.  On one of my projects we had a long 
discussion about this topic and that was our conclusion: KISS!

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#10674

FromJorgen Grahn <grahn+nntp@snipabacken.se>
Date2011-10-05 08:19 +0000
Message-ID<slrnj8o4ns.1bk.grahn+nntp@frailea.sa.invalid>
In reply to#10671
On Tue, 2011-10-04, Ian Collins wrote:
> On 10/ 5/11 10:21 AM, Christopher wrote:
>>
>> So what I've decided to do....and I hate doing it...it deriving a
>> ServerSideConnection class that has the accept, onaccept methods, etc.
>> and takes, upon its construction, a whole bunch of boost::functions
>> that can be called back. Then when the connection gets notified of
>> something, it in turn notifies the listener...This is ugly because
>> I've got callback everywhere, its debugging hell, and I've got quite a
>> number of connection implementations that do nothing but get notified
>> and notify the listener...yuck!
>>
>> I don't see a way around it.
>
> Just use the native interface.  On one of my projects we had a long 
> discussion about this topic and that was our conclusion: KISS!

I'm repeating myself, but an anecdote:

A few years back I decided to write The One True C++ Wrapper For BSD
Sockets. I wanted type safety: distinct types for UDP sockets, TCP
listening sockets, "normal" TCP sockets ... with the type system
preventing mistakes such as doing listen() on an UDP socket or setting
UDP-specific socket options on a TCP socket. But at the same time I
didn't want to invent a brand new interface to learn.

After a while I realized that (a) this was hard work and (b) it was
for the most part not useful work. Any half-decent design in your
application makes most of the mistakes I wanted to eliminate
- unlikely to happen, because you tend to keep different kinds of
  sockets apart
- likely to be found quickly if they /did/ happen

So I threw most of it away. I just kept some read/write buffering code
which had proven useful in real life.

(Disclaimer: I have no experience with Boost.asio; perhaps it forces you
in another direction.)

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .

[toc] | [prev] | [next] | [standalone]


#10675

FromIan Collins <ian-news@hotmail.com>
Date2011-10-05 21:39 +1300
Message-ID<9f2jekFaemU2@mid.individual.net>
In reply to#10674
On 10/ 5/11 09:19 PM, Jorgen Grahn wrote:
> On Tue, 2011-10-04, Ian Collins wrote:
>>
>> Just use the native interface.  On one of my projects we had a long
>> discussion about this topic and that was our conclusion: KISS!
>
> I'm repeating myself, but an anecdote:
>
> A few years back I decided to write The One True C++ Wrapper For BSD
> Sockets. I wanted type safety: distinct types for UDP sockets, TCP
> listening sockets, "normal" TCP sockets ... with the type system
> preventing mistakes such as doing listen() on an UDP socket or setting
> UDP-specific socket options on a TCP socket. But at the same time I
> didn't want to invent a brand new interface to learn.
>
> After a while I realized that (a) this was hard work and (b) it was
> for the most part not useful work. Any half-decent design in your
> application makes most of the mistakes I wanted to eliminate
> - unlikely to happen, because you tend to keep different kinds of
>    sockets apart
> - likely to be found quickly if they /did/ happen
>
> So I threw most of it away. I just kept some read/write buffering code
> which had proven useful in real life.

At least you had the good sense to give up after only one attempt.  I 
had three goes, over 15 years before realising the error of my ways.

> (Disclaimer: I have no experience with Boost.asio; perhaps it forces you
> in another direction.)

I've only ever seen it end in tears.

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#10677

FromMiles Bader <miles@gnu.org>
Date2011-10-05 18:09 +0900
Message-ID<buoehyrls8r.fsf@dhlpc061.dev.necel.com>
In reply to#10675
Ian Collins <ian-news@hotmail.com> writes:
>> So I threw most of it away. I just kept some read/write buffering code
>> which had proven useful in real life.
>
> At least you had the good sense to give up after only one attempt.  I
> had three goes, over 15 years before realising the error of my ways.

Ah well, such things tend to be a learning experience, at least ...

-miles

-- 
"Whatever you do will be insignificant, but it is very important that
 you do it."  Mahatma Gandhi

[toc] | [prev] | [next] | [standalone]


#10685

FromJorgen Grahn <grahn+nntp@snipabacken.se>
Date2011-10-05 18:30 +0000
Message-ID<slrnj8p8h6.1bk.grahn+nntp@frailea.sa.invalid>
In reply to#10675
On Wed, 2011-10-05, Ian Collins wrote:
> On 10/ 5/11 09:19 PM, Jorgen Grahn wrote:
...
>> So I threw most of it away. I just kept some read/write buffering code
>> which had proven useful in real life.
>
> At least you had the good sense to give up after only one attempt.  I 
> had three goes, over 15 years before realising the error of my ways.

Well, ask me again 15 years from now ;-)

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .

[toc] | [prev] | [next] | [standalone]


#10673

FromWerner <werasm@gmail.com>
Date2011-10-05 00:02 -0700
Message-ID<e35470e2-387a-4742-8d98-9160cd4bcb94@d17g2000yqa.googlegroups.com>
In reply to#10627
On Oct 1, 10:32 pm, Christopher <cp...@austin.rr.com> wrote:
> I know I need some sort of friend, but I don't want to friend the
> entire class.
>
> I've got a TcpConnection class and it has a state member.
> I've got a TcpListener class that accepts connections and creates a
> TcpConnectionClass.
>
> The TcpListener class needs to be able to change the state member of
> the TcpConnection class, but I don't want anyone else to be able to.
> How do I go about that?

This is how I did it:


TcpSvrConnectionListener:

    void subscribeForConnections( IfToSvr& ifToSvr );
    void unsubscribeForConnections( IfToSvr& ifToSvr );

IfToSvr was nested...
class TcpSvrConnectionListener::IfToSvr
{
  public:
    virtual void connectedEvt( SOCKET acceptDescriptor ) = 0;
    unsigned getPortNum() const{ return portNum_; }
    const std::string& getIpAddr() const { return ipAddr_; }

  protected: //Operations
    //Derivitives to specify the port number
    IfToSvr(): portNum_( 0 ), ipAddr_( "" ){ }
    IfToSvr( unsigned portNum, const std::string& ipAddr )
      : portNum_( portNum ), ipAddr_( ipAddr )
    {
    }

    //won't be deleted through this interface
    virtual ~IfToSvr(){}
    void setPortNum( unsigned portNum ){ portNum_ = portNum; }
    void setIpAddr( const std::string& ipAddr ){ ipAddr_ = ipAddr; }

  private:
    unsigned portNum_;
    std::string ipAddr_;
};

TcpSvrConnectionListener ran in it's own thread (listening),
and subscription routines had to be synchronized, as well
as connectedEvt...

The server itself, well, it just needs to implement the
interface and subscribe. Turned out that I separated
the actual server from connections. The server was, on
connectedEvt, responsible for realizing the actual
connection. The server then used the subject observer
pattern to dispatch the connection to all sockets
interested. The first socket accepting the connection
would take ownership of it, and on it being accepted,
the server would relinquish ownership of the connection.

Connections not accepted within a certain amount of time
was destroyed.

All reading was done by a service class (similar
to what boost does) that monitors for data in a
single thread and dispatches data to the applicable
registrant associated with the socket on which the data
was received (also via interface, the TcpSvrConnection
deriving from it...).

Contrary to what Ian Collins says, in my opinion especially
using blocking sockets complicate user code. KISS, but not
at the expense of usage. I haven't looked at boost sockets
much yet, but I've looked at their usage of IO Completion
Ports, and I like the idea of having a "service" responsible
for listening and connecting(for clients), a "service"
responsible for reading, as not having such a service
complicates user code IMHO. Obviously the service class
will be more complicated, but it has a well defined
responsibility and usage is simple, if not opaque.

You (as user) just create a server, associate a socket. Hookup the
appropriate callbacks to receive data (sending is synchronous), and
wholla. In our implementation, the service class has to exist
prior to this, but enabling of the service classes are done
from a central location. One could instantiate the service classes
when needed. We kept that part simple :-) and opted for explicit
creation upfront.

We've created interfaces to break dependencies and to communicate
responsibilities of classes in terms of each other.

Good luck :-),

Kind regards,

Werner




































[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c++


csiph-web