[Ns-developers] [ns3] socket API
craigdo@ee.washington.edu
craigdo at ee.washington.edu
Thu Apr 17 16:00:39 PDT 2008
This is, of course, a complicated situation to which there is no one simple
answer. Many of you probably already know what I'm going to say, but that
never stopped me before. IMO there are a few things to keep in mind.
When a new user walks up to the ns-3 system, he or she is most likely going
to have a previously established conceptual model of how the system is
expected to work. When we are talking about sockets, the model is obvious.
If we try to call an interface a sockets interface, and it does not meet the
expectations a new or naive user has, his or her experience will be
difficult and unpleasant and so will ours. I think that any synchronous API
that we advertise as a sockets interface should work just like any other BSD
sockets interface -- it should be completely consistent with their
expectations. This makes it familiar to users and allows for easy porting
of foreign apps to ns-3. You should be able to type in any one of zillions
of example programs from a favorite textbook and have it "just work."
Now, we do have an asynchronous system so there's going to be a fundamental
impedance mismatch *somewhere* between the "real" sockets API and the
simulator. I think we also want a high-performance low-level interface
providing *socket-like* functionality that is aligned with the ns-3 way of
doing things, so we are talking about at least two APIs and an "impedance
matching network."
The big question is, how to we export/access this functionality. I believe
it's important to keep things as familiar as possible for new users. We
need conceptual handles to give to someone learning the system to make it as
easy as possible. There do exist asynchronous sockets library, but I don't
believe there is any standard, OS independent way to do this and I don't
relish the idea of adding signals, for example, to get SIGIO to implement an
asynchronous socket callback. Plus, I don't think this is common knowledge
in the real world. So, if there's no common, obvious model for how to do an
asynchronous sockets implementation at the low level, I think it's okay
(best) to build one using concepts more oriented to ns-3 users instead of to
sockets programmers. For example, I think it's okay for Ptr<Packet>,
MakeCallback, etc., to appear there. In order to make things somewhat
familiar, I think its important for sockets-like concepts to appear here as
well, but it's probably good that the API is obviously different.
The principle of least astonishment applies here as well from a sockets
perspective and from an ns-3 perspective at the same time. There is a
balance we have to make. On one hand, we are talking about a fundamentally
different thing than sockets, so Mathieu's comments regarding the
differences are right on. The danger is that we make a system that looks
enough like sockets that we lull the user into believing that this is
sockets -- he or she will soon be astonished that something very odd is
going on when it suddenly and unexpectedly works like ns-3 (with sockets
disappearing when they go out of context due to reference counting, etc., or
a program not compiling when one tries to send a byte buffer instead of a
packet).
On the other hand, we need to design a system that is understandable by mere
mortals in polynomial time ;-) There should be enough familiar terrain that
a new user can understand and navigate what is going on without having to
stop at each turn. We also need to make a low-level interface that aligns
with the models of the simulator and meets design requirements. There
should be a consistent model for how one uses the low-level API just like
there is a model for sockets, but I don't think they need to, or should be,
forced into alignment.
On the gripping hand, we also need to pay attention to where it is most
efficient to do certain things. This probably means adding support for the
synchronous "real" model down in the lower-level ns-3 interface. We do need
to make sure that if there are support functions not really part of the
mainline low-level interface that this is obvious as well. Perhaps the glue
should be somewhere else (QI for glue?).
I think we're seeing all of these viewpoints playing out in the current
discussion. It's not an easy, obvious thing; and I think we need to keep in
mind that there are different goals and requirements in different places
including where the socket-like-ness is important.
For example, I would think it would be inconsistent to export a socket send
interface at the synchronous API that took something called a Ptr<Packet>,
but I think it would be perfectly fine to do so at the low-level. I think
it would be fine to have a synchronous call to read data at the synchronous
API and I think it would be fine to have methods to support such a call in
an obvious glue section of the low-level API. I think it's fine to have a
low-level interface that doesn't take a data buffer or Ptr<Packet> but just
has a count of fake bytes, however, I think that having such a thing in the
mainline synchronous API would be inconsistent and surprising (we could
*add* a new API for that which takes no data buffer).
So I encourage thinking about this not as just "the socket API," but as a
friendly synchronous sockets API, a fast native asynchronous low-level ns-3
API and impedance matching glue. The friendly synchronous socket API should
offer no surprises to the user that expects BSD sockets. The fast native
asynchronous low-level ns-3 API should work in the ns-3 model, but be
advertized as *different* and implemented in that elusive, hard-to-define
way that makes it easy to understand what is going on if you understand
sockets and ns-3, but plainly obvious that "it ain't sockets." The glue
code is whatever is required to efficiently match the two different models
and is not really public API.
So if we're, for example, thinking about how one would send don't-care data
in sockets, IMO we should keep a faithful sockets implementation in the
high-level synchronous case. This might mean that the user would not
initialize data, but would send random stack contents. We would still copy
those random bytes. Now, if we need to be super-efficient, we could allow
this in our low-level API, perhaps with a method that didn't even take a
buffer to make it extremely obvious what is happening. If we want to extend
this behavior to the synchronous API, we could add *extensions* to existing
sockets API to describe dont-care data.
My $.04 (twice as much as needed :-)
-- Craig
More information about the Ns-developers
mailing list