|
|
|
xnet_util
- XDR Networking UtilitiesThe XNET utilities provide a high-level interface to the Sun XDR routines that perform record-oriented communications across a network connection. The XNET package is layered on top of the lower-level TCP_UTIL functions. Network connections can be established between clients and servers and XDR streams are built on these connections. The read and write functions make it easy to send ASCII text records back and forth between processes.
A simple server process that reads and displays the ASCII text messages it receives could be as brief as the following program:
#include <stdio.h> -- Standard I/O definitions. #include "tcp_util.h" -- TCP/IP networking utilities. #include "xnet_util.h" -- XNET definitions. int main (int argc, char *argv[]) { char *message ; TcpEndpoint client, server ; XnetStream stream ; tcpListen (argv[1], 99, &server) ; -- Create listening endpoint. for ( ; ; ) { -- Answer next client. tcpAnswer (server, -1.0, &client) ; xnetCreate (client, NULL, &stream) ; for ( ; ; ) { -- Service connected client. if (xnetRead (stream, -1.0, &message)) break ; printf ("Message: %s\n", message) ; } xnetDestroy (stream) ; -- Lost client. } }
The server's name is specified as the first argument on the command line
(i.e., argv[1]
). If a client connection is broken, the server
loops back to wait for another client.
A simple client process that reads its user's input and forwards it to the server process would look as follows:
#include <stdio.h> -- Standard I/O definitions. #include "tcp_util.h" -- TCP/IP networking utilities. #include "xnet_util.h" -- XNET definitions. int main (int argc, char *argv[]) { char buffer[128] ; TcpEndpoint connection ; XnetStream stream ; -- Call server. tcpCall (argv[1], -1.0, -1.0, &connection) ; xnetCreate (connection, NULL, &stream) ; for ( ; ; ) { -- Forward input to server. if (gets (buffer) == NULL) break ; xnetWrite (stream, -1.0, "%s", buffer) ; } xnetDestroy (stream) ; -- Lost user! }
Although the XNET functions are especially suited to exchanging ASCII
messages between processes, an application can still access the lower-level
XDR routines. xnetHandle()
returns the address of the XDR
stream structure that is needed for the system XDR calls. The following
server periodically sends its client the current time (in a record
containing a UNIX timeval
structure):
#include <stdio.h> -- Standard I/O definitions. #include <rpc/rpc.h> -- RPC/XDR definitions. #include <sys/time.h> -- System time definitions. #include "tcp_util.h" -- TCP/IP networking utilities. #include "xnet_util.h" -- XNET definitions. int main (int argc, char *argv[]) { struct timeval currentTime ; TcpEndpoint client, server ; XDR *xdrStream ; XnetStream stream ; tcpListen (argv[1], 99, &server) ; -- Create listening endpoint. for ( ; ; ) { -- Answer next client. tcpAnswer (server, -1.0, &client) ; xnetCreate (client, NULL, &stream) ; xdrStream = xnetHandle (stream) ; for ( ; ; ) { -- Service connected client. gettimeofday (¤tTime, NULL) ; if (!xdr_timeval (xdrStream, ¤tTime) || xnetEndRecord (stream)) break ; sleep (1) ; } xnetDestroy (stream) ; -- Lost client. } }
After manually constructing an output record using low-level XDR functions,
the program must terminate the record with a call to
xnetEndRecord()
, as the example above shows. Likewise, after
decoding an input record using low-level XDR functions, the program must
"close" the current record and advance to the beginning of the next record
with a single call to xnetNextRecord()
.
[xnetWrite()
and xnetRead()
, respectively, call
these functions automatically.]
In event-driven applications (e.g., those based on the X Toolkit or the
IOX dispatcher), the socket connection
underlying the XDR stream, returned by xnetFd()
, can be
monitored for input by your event dispatcher. Because input is buffered by
the XDR library, the input callback must continue to read XDR records while
xnetIsReadable()
is true. When reading string records, calls
to xnetRead()
can simply be interleaved with calls to
xnetIsReadable()
:
while (xnetIsReadable (stream)) { if (xnetRead (stream, -1.0, &message)) break ; ... process message ... }
When manually decoding input records, xnetIsReadable()
should
only be checked in between records, not in the middle of a record:
while (xnetIsReadable (stream)) { if (!xdr_int (xdrStream, &value1) || !xdr_int (xdrStream, &value2) || xnetEndRecord (stream)) break ; ... process values ... }
xnetCreate()
- creates an XDR-based network stream.
xnetDestroy()
- deletes an XDR-based network stream.
xnetEndRecord()
- outputs the contents of the current
output record to an XDR stream and begins a new record.
xnetFd()
- returns an XNET stream's socket number.
xnetFlush()
- flushes any queued output to the XNET stream's
socket.
xnetHandle()
- returns an XNET stream's XDR handle.
xnetIsReadable()
- checks if input is waiting to be read
from a stream.
xnetIsUp()
- checks if an XNET stream is up.
xnetIsWriteable()
- checks if data can be written to a stream.
xnetNextRecord()
- positions to the beginning of the next
input record.
xnetRead()
- reads a record containing an XDR string from
an XNET stream.
xnetSetTimeout()
- sets the I/O timeout on an XNET stream.
xnetWrite()
- writes a record containing an XDR string to
an XNET stream.
xnet_util.c
xnet_util.h
(See libnet
for the
complete source, including support routines and build files.)