201 lines
8.0 KiB
Plaintext
201 lines
8.0 KiB
Plaintext
@node Sockets APIs
|
|
@chapter Sockets APIs
|
|
|
|
The @uref{http://en.wikipedia.org/wiki/Berkeley_sockets,,sockets API}
|
|
is a long-standing API used by user-space applications to access
|
|
network services in the kernel. A ``socket'' is an abstraction, like
|
|
a Unix file handle, that allows applications to connect to other
|
|
Internet hosts and exchange reliable byte streams and unreliable
|
|
datagrams, among other services.
|
|
|
|
ns-3 provides two types of sockets APIs, and it is important to
|
|
understand the differences between them. The first is a @emph{native}
|
|
ns-3 API, while the second uses the services of the native API to
|
|
provide a @uref{http://en.wikipedia.org/wiki/POSIX,,POSIX-like}
|
|
API as part of an overall application process. Both APIs strive
|
|
to be close to the typical sockets API that application writers
|
|
on Unix systems are accustomed to, but the POSIX variant is much
|
|
closer to a real system's sockets API.
|
|
|
|
@section ns-3 sockets API
|
|
|
|
The native sockets API for ns-3 provides an interface to various
|
|
types of transport protocols (TCP, UDP) as well as to packet sockets
|
|
and, in the future, Netlink-like sockets. However, users are cautioned
|
|
to understand that the semantics are @strong{not} the exact same as
|
|
one finds in a real system (for an API which is very much aligned
|
|
to real systems, see the next section).
|
|
|
|
@code{class ns3::Socket} is defined in @code{src/node/socket.cc,h}.
|
|
Readers will note that many public member functions are aligned
|
|
with real sockets function calls, and all other things being equal,
|
|
we have tried to align with a Posix sockets API. However, note that:
|
|
|
|
@itemize @bullet
|
|
@item ns-3 applications handle a smart pointer to a Socket object, not
|
|
a file descriptor;
|
|
@item there is no notion of synchronous API or a ``blocking'' API;
|
|
in fact, the model for interaction between application and socket is
|
|
one of asynchronous I/O, which is not typically found in real systems
|
|
(more on this below);
|
|
@item the C-style socket address structures are not used;
|
|
@item the API is not a complete sockets API, such as supporting
|
|
all socket options or all function variants;
|
|
@item many calls use @code{ns3::Packet} class to transfer data
|
|
between application and socket. This may seem peculiar to
|
|
pass ``Packets'' across a stream socket API, but think
|
|
of these packets as just fancy byte buffers at this level (more
|
|
on this also below).
|
|
@end itemize
|
|
|
|
@subsection Basic operation and calls
|
|
|
|
@float Figure,fig:sockets-overview
|
|
@caption{Implementation overview of native sockets API}
|
|
@image{figures/sockets-overview, 10cm}
|
|
@end float
|
|
|
|
@subsubsection Creating sockets
|
|
|
|
An application that wants to use sockets must first create one.
|
|
On real systems using a C-based API, this is accomplished by calling socket():
|
|
@verbatim
|
|
int
|
|
socket(int domain, int type, int protocol);
|
|
@end verbatim
|
|
which creates a socket in the system and returns an integer descriptor.
|
|
|
|
In ns-3, we have no equivalent of a system call at the lower layers,
|
|
so we adopt the following model. There are certain @emph{factory}
|
|
objects that can create sockets. Each factory is capable of creating
|
|
one type of socket, and if sockets of a particular type are able to
|
|
be created on a given node, then a factory that can create such sockets
|
|
must be aggregated to the Node.
|
|
@verbatim
|
|
static Ptr<Socket> CreateSocket (Ptr<Node> node, TypeId tid);
|
|
@end verbatim
|
|
Examples of TypeIds to pass to this method are @code{TcpSocketFactory},
|
|
@code{PacketSocketFactory}, and @code{UdpSocketFactory}.
|
|
|
|
This method returns a smart pointer to a Socket object. Here is an
|
|
example:
|
|
@smallformat
|
|
@example
|
|
Ptr<Node> n0;
|
|
// Do some stuff to build up the Node's internet stack
|
|
Ptr<Socket> localSocket = Socket::CreateSocket (n0, TcpSocketFactory::GetTypeId ());
|
|
@end example
|
|
@end smallformat
|
|
|
|
In some ns-3 code, sockets will not be explicitly created by user's
|
|
main programs, if an ns-3 application does it. For instance, for
|
|
@code{class ns3::OnOffApplication}, the function @code{StartApplication()}
|
|
performs the socket creation, and the application holds the socket
|
|
pointer.
|
|
|
|
@subsubsection Using sockets
|
|
|
|
Below is a typical sequence of socket calls for a TCP client in a
|
|
real implementation:
|
|
@itemize @bullet
|
|
@item @code{sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);}
|
|
@item @code{bind(sock, ...);}
|
|
@item @code{connect(sock, ...);}
|
|
@item @code{send(sock, ...);}
|
|
@item @code{recv(sock, ...);}
|
|
@item @code{close(sock);}
|
|
@end itemize
|
|
|
|
There are analogs to all of these calls in ns-3, but we will focus on
|
|
two aspects here. First, most usage of sockets in real systems
|
|
requires a way to manage I/O between the application and kernel.
|
|
These models include @emph{blocking sockets}, @emph{signal-based I/O},
|
|
and @emph{non-blocking sockets} with polling. In ns-3, we make use
|
|
of the callback mechanisms to support a fourth mode, which is
|
|
analogous to POSIX @emph{asynchronous I/O}.
|
|
|
|
In this model, on the sending side, if the @code{send()} call were to
|
|
fail because of insufficient buffers, the application suspends the
|
|
sending of more data until a function registered at the
|
|
@code{SetSendCallback()} callback is invoked. An application can
|
|
also ask the socket how much space is available by calling
|
|
@code{GetTxAvailable ()}. A typical sequence of events for
|
|
sending data (ignoring connection setup) might be:
|
|
|
|
@itemize @bullet
|
|
@item @code{SetSendCallback (MakeCallback(&HandleSendCallback));}
|
|
@item @code{Send ();}
|
|
@item @code{Send ();}
|
|
@item ...
|
|
@item @code{// Send fails because buffer is full}
|
|
@item (wait until HandleSendCallback() is called)
|
|
@item (HandleSendCallback() is called by socket, since space now available)
|
|
@item @code{Send (); // Start sending again}
|
|
@end itemize
|
|
|
|
Similarly, on the receive side, the socket user does not block on
|
|
a call to @code{recv()}. Instead, the application sets a callback
|
|
with @code{SetRecvCallback ()} in which the socket will notify the
|
|
application when (and how much) there is data to be read, and
|
|
the application then calls @code{Recv()} to read the data until
|
|
no more can be read.
|
|
|
|
@subsection Packet vs. buffer variants
|
|
|
|
There are two basic variants of @code{Send()} and @code{Recv()} supported:
|
|
@verbatim
|
|
virtual int Send (Ptr<Packet> p) = 0;
|
|
int Send (const uint8_t* buf, uint32_t size);
|
|
|
|
Ptr<Packet> Recv (void);
|
|
int Recv (uint8_t* buf, uint32_t size);
|
|
@end verbatim
|
|
|
|
The non-Packet variants are provided for legacy API reasons. When calling
|
|
the raw buffer variant of @code{Send()}, the buffer is immediately
|
|
written into a Packet and the @code{Send (Ptr<Packet> p)} is invoked.
|
|
|
|
Users may find it semantically odd to pass a Packet to a stream socket
|
|
such as TCP. However, do not let the name bother you; think of
|
|
@code{ns3::Packet} to be a fancy byte buffer. There are a few reasons why
|
|
the Packet variants are more likely to be preferred in ns-3:
|
|
|
|
@itemize @bullet
|
|
@item Users can use the Tags facility of packets to, for example, encode
|
|
a flow ID or other helper data at the application layer.
|
|
@item Users can exploit the copy-on-write implementation to avoid
|
|
memory copies (on the receive side, the conversion back to a
|
|
@code{uint8_t* buf} may sometimes incur an additional copy).
|
|
@item Use of Packet is more aligned with the rest of the ns-3 API
|
|
@end itemize
|
|
|
|
@subsection Sending dummy data
|
|
|
|
Sometimes, users want the simulator to just pretend that there is an
|
|
actual data payload in the packet (e.g. to calculate transmission delay)
|
|
but do not want to actually produce or consume the data. This is
|
|
straightforward to support in ns-3; have applications call
|
|
@code{Create<Packet> (size);} instead of @code{Create<Packet> (buffer, size);}.
|
|
Similarly, passing in a zero to the pointer argument in the raw buffer
|
|
variants has the same effect. Note that, if some subsequent code tries
|
|
to read the Packet data buffer, the fake buffer will be converted to
|
|
a real (zeroed) buffer on the spot, and the efficiency will be lost there.
|
|
|
|
@subsection Socket options
|
|
|
|
@emph{to be completed}
|
|
|
|
@subsection Socket errno
|
|
|
|
@emph{to be completed}
|
|
|
|
@subsection Example programs
|
|
|
|
@emph{to be completed}
|
|
|
|
@section POSIX-like sockets API
|
|
|
|
@cartouche
|
|
Under development in the http://code.nsnam.org/mathieu/ns-3-simu repository.
|
|
@end cartouche
|