Re: Network library: What we have until now

Hi Maxim,
Don G wrote:
Personally, I don't think the multiplexing interface is appropriate or necessary.
Rather it's vital.
I agree that it is vital to use such a mechanism internally, but I see no reason (other than preference) to expose the grouping of connections to the user.
None of the calls should block.
But the sync ones _must_ block. All of the logical operations can be invoked sync/async. The non-blocking approach, from my definition<g>, is like this: - try the operation - get back a "would block" state - flag interest in change to "won't block" - wait for the state to arrive - repeat the operation (it won't block) I think this has a place for I/O, but not for connect/accept. These are binary steps whereas I/O can be viewed as a continuous march to completion.
Otherwise you won't be able to build single threaded applications with select/poll/epoll-based loops.
One can write in a single threaded style using what I am proposing, but it is not, IMHO, the way to go for optimal performance. What I am suggesting is that this style can be achieved by not basing the main loop on select/et.al.. Those API's will be used internally. Things like the Windows limit on connections/select and leverage of multiple CPU's would be details. This will not be the solution for _everyone_. But, I believe it will go a lot farther than you might think. []
* There should be an asynchronous design pattern which should be used by all Boost libraries which support asynchronous operations.
I agree completely on this one :)
I hope this won't happen. There are several I/O patterns in use out there.
But, honestly, how many do we need? I think all that we need is a way to achieve concurrent operations in C++. One technique would satisfy this. It would have advantage of allowing different libraries to communicate, as each would not be using an incompatible style.
* On a low level the network library should be close to what is known as Berkeley sockets to many programmers.
I think sockets should be hidden. They are not universally used, for example Mac OS9 doesn't and I just assume others exist. They don't have any magical powers; they are just a C abstraction.
Was not Mac OS Classic been buried long ago?
Hopefully :) It was offered as an existence proof. There is more to the world than Unix and Windows.
IMO, sockets are abstractions out of the scope of any language.
But they are realized as a C artifact. They were born as a C library. They are not sacred :)
Their interfaces can be implemented using any general purpose programming language, but still you'll have to call an underlying OS C API. That's a fact of life and I don't think this is bad - C is the most portable programming language ever.
Yes, C is portable. C++ is also. I will resist the C vs. C++ debate.
A C++ abstraction should replace them.
With this kind of attitude you might end up rewritting the whole world you've been living in <g>
Actually, I believe that is the point. Sometimes (often) these are just C++ facades over C libraries, but C++ offers a different idiom that many find attractive for various reasons. This is especially true when the C interface is as tedious as sockets. Whitness the level of interest in this topic. :)
Here is my two philosophy cents.
You propose another set of concepts over socket concepts just to send/receive a bunch of mere bytes. Geez, another glue layer over sockets that adds nothing but syntax sugar. Aren't we already tired of software bloated from glue layers over glue layers over...?
Not "just". It is to handle life-cycle safely, type safe control flow, non-portable aspects of sockets, to name a few.
You don't just send bytes, rather you execute protocols. Sockets have the right implementation level and complexity to build *efficient* protocols upon.
How hard should it be to write a protocol? How reusable should it be? Have you ever tried to use, say, OpenSSL? Everyone that wants to write a protocol today must grapple with these issues and all they have to begin with is a concrete API for sockets. But that is a bottom-only facility. Just try to expose SSL as a socket to your user! FWIW, openssl exposed their protocol implementation in a generic way so as not to tie one to sockets. That is, they created a C I/O mechanism (BIO's) that are unique to it. A C++ version could be written to use the net::stream I proposed and _be_ a net::stream implementation. Thanks to the BIO interface of OpenSSL, this could also be done using that library.
Protocol is the only glue layer you really always need, the layer that binds your application logic with network transport layer (sockets) providing the right C++ or whatever interface.
So, let's say we have an HTTP library. How do we wait for responses? Expose the socket(s) it uses? I think the async pattern we are talking about is the right answer. Best regards, Don __________________________________ Do you Yahoo!? Yahoo! Small Business - Try our new resources site! http://smallbusiness.yahoo.com/resources/

On Thu, 14 Apr 2005 06:27:06 -0700 (PDT), Don G <dongryphon@yahoo.com> wrote: []
None of the calls should block.
But the sync ones _must_ block. All of the logical operations can be invoked sync/async. The non-blocking approach, from my definition<g>, is like this:
- try the operation - get back a "would block" state - flag interest in change to "won't block" - wait for the state to arrive - repeat the operation (it won't block)
I think this has a place for I/O, but not for connect/accept. These are binary steps whereas I/O can be viewed as a continuous march to completion.
Consider a proxy server for example. It accept a connection and then connects to destination. If accept/connect block, it won't be possible to handle in one thread multiple clients. But AFAIK performance proxy servers are actually single threaded.
Otherwise you won't be able to build single threaded applications with select/poll/epoll-based loops.
One can write in a single threaded style using what I am proposing, but it is not, IMHO, the way to go for optimal performance. What I am suggesting is that this style can be achieved by not basing the main loop on select/et.al.. Those API's will be used internally. Things like the Windows limit on connections/select and leverage of multiple CPU's would be details.
This will not be the solution for _everyone_. But, I believe it will go a lot farther than you might think.
My experience is opposite. One of my previous project was a soft realtime VoIP softswitch. It has only one thread of execution and is capable of handling 1000+ simultaneous calls (2000-4000 sockets). It scales up by just starting additional processes on the same box, no recompilation needed, no locking, simple and immensely powerful. []
I hope this won't happen. There are several I/O patterns in use out there.
But, honestly, how many do we need?
This is the main questions. I doubt we can ever answer this. So, I see no reason in dictating a style. []
A C++ abstraction should replace them.
With this kind of attitude you might end up rewritting the whole world you've been living in <g>
Actually, I believe that is the point. Sometimes (often) these are just C++ facades over C libraries, but C++ offers a different idiom that many find attractive for various reasons.
I see no problem with this. As soon as you cross a compiled library bound it does not matter whether it's C or C++ under the hood. You've got a binary interface and there is only syntax difference between function<void()> and void(*)() + void* callbacks - they both always make you allocate. IMO, there is little difference between C and C++ binary interfaces. []
Not "just". It is to handle life-cycle safely, type safe control flow, non-portable aspects of sockets, to name a few.
I'm pretty much sure I'm in the minority on this, but the the first two things are just noise for me.
You don't just send bytes, rather you execute protocols. Sockets have the right implementation level and complexity to build *efficient* protocols upon.
How hard should it be to write a protocol? How reusable should it be?
Try implementing H.323 family. (Although it dies, but it does not die as fast as I want it to).
Have you ever tried to use, say, OpenSSL? Everyone that wants to write a protocol today must grapple with these issues and all they have to begin with is a concrete API for sockets. But that is a bottom-only facility. Just try to expose SSL as a socket to your user!
FWIW, openssl exposed their protocol implementation in a generic way so as not to tie one to sockets. That is, they created a C I/O mechanism (BIO's) that are unique to it.
A C++ version could be written to use the net::stream I proposed and _be_ a net::stream implementation. Thanks to the BIO interface of OpenSSL, this could also be done using that library.
Yes, I'm familiar with and used OpenSSL a lot. It exposes a good C object model. Would you like to make it expose C++ interface? I doubt that it makes any sense, sinse IMO OpenSSL interface is good enough. The same point of view I have for sockets.
Protocol is the only glue layer you really always need, the layer that binds your application logic with network transport layer (sockets) providing the right C++ or whatever interface.
So, let's say we have an HTTP library. How do we wait for responses? Expose the socket(s) it uses?
No. At application level we operate on PDUs (which are HTTP messages here). No sockets exposed. All the socket manipulation is done inside HTTP protocol library. Here I attached an async protocol layer abstractions I've been using in my current project. -- Maxim Yegorushkin

Hi Maxim, Don G wrote:
None of the calls should block.
But the sync ones _must_ block. All of the logical operations can be invoked sync/async. The non-blocking approach, from my definition<g>, [snip] I think this has a place for I/O, but not for connect/ accept. These are binary steps whereas I/O can be viewed as a continuous march to completion.
Consider a proxy server for example. It accept a connection and then connects to destination. If accept/ connect block, it won't be possible to handle in one thread multiple clients. But AFAIK performance proxy servers are actually single threaded.
They would use async, not blocking calls (in the proposal I made). I reread my post and it sounds as if I am saying that single threaded servers cannot be high performance. Of course, they can. I still believe a multi-threaded server will be higher performance.
One of my previous project was a soft realtime VoIP softswitch. It has only one thread of execution and is capable of handling 1000+ simultaneous calls (2000- 4000 sockets). It scales up by just starting additional processes on the same box, no recompilation needed, no locking, simple and immensely powerful.
I knew we had a definition problem: handling 1000+ simultaneous connections would not be something I would label as "simple"! ;) I have multiple thoughts here. First, I think the only difference our two approaches would yield is that with my approach, one might need locks. I did say "might". No lock is needed if the object managing a connection is basically autonomous, changing only its state is response to I/O completion or requesting further I/O, and/or creating new connections. While the internals of the network implementation are threaded, on a per-connection basis, callbacks are single threaded. Secondly, I don't think a queue of boost::function<> would be found by the profiler as a performance bottle-neck (though I haven't looked inside it at all). This is the approach I have taken to handle lots of async calls from one thread. Not 1000+, but I'm not sure the hardware and OS you used.
I hope this won't happen. There are several I/O patterns in use out there.
But, honestly, how many do we need?
This is the main questions. I doubt we can ever answer this. So, I see no reason in dictating a style.
There are some reasons for picking a small number of styles: 1. Simpler for a user to understand 2. Simpler to document 3. Simpler to test 4. Simpler to write higher level libs (they should have have symmetric styles for their users) 5. Not all styles are portable (w/o undue complexity) 6. Simpler to implement :) I can only think of one advantage of multiple styles: familiarity with existing practice. These practices may or may not be "good"<g> but they are familiar. It is my contention that by supporting too many "familiar idioms" we jeopardize all of the above.
You don't just send bytes, rather you execute protocols. Sockets have the right implementation level and complexity to build *efficient* protocols upon.
How hard should it be to write a protocol? How reusable should it be?
Try implementing H.323 family. (Although it dies, but it does not die as fast as I want it to).
Fortunately, I have not had to tackle H.323. :) See my above list for the intent of this question.
Yes, I'm familiar with and used OpenSSL a lot. It exposes a good C object model. Would you like to make it expose C++ interface? I doubt that it makes any sense, sinse IMO OpenSSL interface is good enough. The same point of view I have for sockets.
Yes, I would like a C++ interface. In fact, it would be basically as I proposed: net::stream. I realize that there are many other aspects to OpenSSL beyond streaming. And, of course, I would like a C++ interface to all of it. Sadly, the openssl folks aren't writing it and I have no desire to do so. If there were an openssl/C++, I would switch (all other things being equal).
So, let's say we have an HTTP library. How do we wait for responses? Expose the socket(s) it uses?
No.
At application level we operate on PDUs (which are HTTP messages here). No sockets exposed. All the socket manipulation is done inside HTTP protocol library.
Here I attached an async protocol layer abstractions I've been using in my current project.
From the code you posted, it appears that you use callbacks using abstract bases not boost::function<> (which is fine and it does avoid any possibility of deep copy under the covers).
So, say I have lots of HTTP connections to process. Would I be getting callbacks for completion? If so, why should this be fundamentally different than the layer below? Also, how does HTTP client code differ from HTTPS client code? One must interact with the SSL library and another with sockets... Best, Don __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com
participants (2)
-
Don G
-
Maxim Yegorushkin