3 <META HTTP-EQUIV=
"Content-Type" CONTENT=
"text/html; charset=iso-8859-1">
4 <META NAME=
"Author" CONTENT=
"Mike Gleason">
5 <META NAME=
"GENERATOR" CONTENT=
"Mozilla/4.03 [en] (WinNT; I) [Netscape]">
6 <TITLE>sio: SocketIO Library
</TITLE>
8 <BODY BGCOLOR=
"#FFFFFF">
11 SocketIO Library Documentation
</H1>
15 <A HREF=
"#Introduction">Introduction
</A></LI>
18 <A HREF=
"#Installation">Installation
</A></LI>
21 <A HREF=
"#Functions">Function Reference
</A></LI>
24 <A HREF=
"#Sample">Sample Code
</A></LI>
26 The purpose of the
<I>SocketIO Library
</I> (
<I>sio
</I> for short) is to
27 provide a safe and consistent wrapper interface to a BSD Sockets implementation.
28 The library also takes steps to protect against a few common pitfalls that
29 plague poorly written BSD Sockets programs.
Specifically, it was
30 designed to do the following:
35 Take care of reading and writing the full operation.
37 <P><FONT SIZE=-
1>For example, a network
<TT>write()
</TT> for
50 bytes may
38 only write
30 bytes;
<I>Sio
</I> would continue writing until all
50 bytes
39 have been sent.
</FONT>
44 Allow operations that would normally block can be set to timeout after
45 a customizable period of time.
<P></LI>
49 Catch the SIGPIPE signal which would cause an unexpecting process to exit.
<P>
51 <P><FONT SIZE=-
1>A frequent source of problems for beginning programmers
52 is the situation where their process is suddenly no longer running because
53 a write to a socket caused a broken pipe. This problem can be difficult
54 to diagnose if the process is running as a daemon process in the background.
</FONT>
60 Resume operation when system calls are interrupted (operations errout
61 with
<TT>EINTR
</TT>).
<P></LI>
65 Cater to the internet socket interface (i.e.
<TT>struct sockaddr_in
</TT>).
<P></LI>
69 Simplified interface to name service.
72 <P><FONT SIZE=-
1>Library routines can take a textual address specification
73 instead of you having to prepare a
<TT>struct sockaddr_in
</TT>.
</FONT>
78 The library was written by Mike Gleason. The first incarnation dates
79 back to some time in
1992. The library may be used and distributed
80 freely, as long as you give due credit.
83 <A NAME=
"Introduction"></A>Introduction
</H3>
84 The reader is assumed to be familiar with BSD Sockets.
An excellent
85 source of information is W. Richard Stevens'
<U>UNIX Network Programming,
86 Volume
1, Second Edition: Networking APIs: Sockets and XTI
</U>, Prentice
87 Hall,
1998, ISBN
0-
13-
490012-X.
90 <A NAME=
"Connection_modes"></A>Connection modes
</H4>
91 A communications exchange between two end-points can be connection-oriented
92 or connectionless.
An connection-oriented exchange is characterized
93 by a connection establishment, a series of messages, and a disconnection.
94 A connectionless exchange is characterized by one or more independent messages.
95 An analogy to a connection-oriented exchange would be a telephone call
96 where one party establishes a connection to another, and a conversation
97 ensues.
A connectionless exchange analogy would be a letter sent
98 via the postal service -- even if a writer sends two letters to the same
99 recipient, each letter is transported independently.
102 <A NAME=
"Message_modes"></A>Message modes
</H4>
103 For the
<I>sio
</I> library, all connection-oriented exchanges are data
104 streams using the
<I>TCP/IP
</I> protocol.
After connection establishment,
105 the conversation consists of one long sequence of data bytes, which is
106 known as a
<I>stream
</I>.
Therefore there is no concept of a record
107 boundary associated with a stream connection at the transport level, although
108 often there is a record associated over the stream at the application level.
109 The important thing here is to realize that there is no flow control associated
110 with the stream, so although the data bytes are guaranteed to arrive in
111 order, there is no guarantee that messages will be read in the same size
112 blocks as they were originally written.
114 <P>For connectionless exchanges,
<I>sio
</I> uses the
<I>UDP/IP
</I> protocol's
115 datagram messages.
There is an implicit definition of a record boundary,
116 because each message is treated as a record. So, three writes results in
117 three separate messages.
119 <P>For example, let's say a sender writes three
50-byte messages.
120 If a receiver does a
20-byte read followed by
100-byte read followed by
121 a
50-byte read, the receiver would get the first
20 bytes of the first
122 message,
50 of
50 bytes of the second message, and
50 of
50 bytes of the
123 third message.
It's important to understand that in the first read
124 that since UDP datagrams are message oriented that the remaining
30 bytes
125 of the first message are lost, and that although the second read is for
126 100 bytes, the read immediately returns as finished even though only
50
127 bytes were actually read.
129 <P>With UDP datagrams, there are also other important implications that
130 affect message ordering, duplication, and overall reliability.
133 <A NAME=
"Creating_and_disposing"></A>Creating and disposing sockets
</H4>
134 A socket is an I/O descriptor that is associated with one side of a communications
135 exchange.
A socket must be either a client or a server, although
136 after communications is established the difference is arbitrary.
137 A server socket is one that waits for contact to be initiated by a client
138 on a mutually agreed upon address and port number.
A client socket
139 initiates the first communication by sending to an existing server socket.
140 Client and server sockets may of course be on different machines, and different
143 <P>A stream server socket is created using
<TT><A HREF=
"#SNewStreamServer">SNewStreamServer()
</A></TT>,
144 which returns a socket file descriptor ready to accept new client connections.
145 After a socket descriptor is obtained, your server program can then use
146 <TT><A HREF=
"#SAccept">SAccept()
</A></TT> to establish a connection with
149 <P>A stream client socket is created using
<TT><A HREF=
"#SNewStreamClient">SNewStreamClient()
</A></TT>.
150 After a socket descriptor is obtained, your client program can use
<TT><A HREF=
"#SConnectByName">SConnectByName()
</A></TT>
151 or
<TT><A HREF=
"#SConnect">SConnect()
</A></TT> to initiate a connection
154 <P>A datagram server socket is created using
<TT><A HREF=
"#SNewDatagramServer">SNewDatagramServer()
</A></TT>.
155 After a socket descriptor is obtained, it is ready to receive messages
156 from clients using
<TT><A HREF=
"#SRecvfrom">SRecvfrom()
</A></TT> and reply
157 back with
<TT><A HREF=
"#SSendto">SSendto()
</A></TT>.
159 <P>A datagram client socket is created using
<TT><A HREF=
"#SNewDatagramClient">SNewDatagramClient()
</A></TT>.
160 After a socket descriptor is obtained, it is ready to communicate with
161 servers using
<TT><A HREF=
"#SSendto">SSendto()
</A></TT> and
<TT><A HREF=
"#SRecvfrom">SRecvfrom()
</A></TT>.
163 <P>All socket descriptors are disposed of with
<TT><A HREF=
"#SClose">SClose()
</A></TT>
164 when communication is finished.
167 <A NAME=
"SocketIO"></A>Socket I/O
</H4>
168 A stream connection uses
<TT><A HREF=
"#SRead">SRead()
</A></TT> to receive
169 data from the stream and
<TT><A HREF=
"#SWrite">SWrite()
</A></TT> to send
170 data.
A datagram socket should use
<TT><A HREF=
"#SRecvfrom">SRecvfrom()
</A></TT>
171 to read a message and
<TT><A HREF=
"#SSendtoByName">SSendtoByName()
</A></TT>
172 or
<TT><A HREF=
"#SSendto">SSendto()
</A></TT> to send a message.
Since
173 each datagram communication is independent, these routines use an address
174 specifier along with each call.
177 <A NAME=
"Installation"></A>Installation
</H3>
178 First, unpack the archive. If the package arrived as a '.tar.gz' or '.tgz'
179 file, you need to run gunzip, and then tar to extract the source files.
180 You can do that in one shot by doing
"<TT>gunzip -c sio.tgz | tar xvf -</TT>".
181 If the package you have is a '.tar' file you can use
"<TT>tar xvf sio.tar</TT>".
182 If the package you have is a '.zip' file you can use
"<TT>unzip sio.zip</TT>"
183 or
"<TT>pkunzip sio.zip</TT>".
185 <P>Now go to the
"<TT>sio</TT>" directory you just made. There is a script
186 you must run which will checks your system for certain features, so that
187 the library can be compiled on a variety of U
<FONT SIZE=-
1>NIX
</FONT> systems.
188 Run this script by typing
"<TT>sh ./configure</TT>" in that directory.
189 After that, you can look at the
<TT>Makefile
</TT> it made if you like,
190 and then you run
"<TT>make</TT>" to create the
"<TT>libsio.a</TT>" library
193 <P>Finally, install the library and headers. You can manually copy the
194 files, or you can run
"<TT>make install</TT>" to copy the files for you.
195 If you choose to
"<TT>make install</TT>" you may want to edit the
<TT>Makefile
</TT>
196 if you do not want to install to the
<TT>/usr/local
</TT> tree.
199 <A NAME=
"Functions"></A>Function Reference
</H3>
204 <td><A HREF=
"#AddrStrToAddr">AddrStrToAddr
</A></td>
205 <td><A HREF=
"#SConnectByName">SConnectByName
</A></td>
206 <td><A HREF=
"#SSendtoByName">SSendtoByName
</A></td>
209 <td><A HREF=
"#AddrToAddrStr">AddrToAddrStr
</A></td>
210 <td><A HREF=
"#SListen">SListen
</A></td>
211 <td><A HREF=
"#SWrite">SWrite
</A></td>
214 <td><A HREF=
"#DisposeSReadlineInfo">DisposeSReadlineInfo
</A></td>
215 <td><A HREF=
"#SNewDatagramClient">SNewDatagramClient
</A></td>
216 <td><A HREF=
"#SelectR">SelectR
</A></td>
219 <td><A HREF=
"#FlushSReadlineInfo">FlushSReadlineInfo
</A></td>
220 <td><A HREF=
"#SNewDatagramServer">SNewDatagramServer
</A></td>
221 <td><A HREF=
"#SelectSetAdd">SelectSetAdd
</A></td>
224 <td><A HREF=
"#GetSocketBufSize">GetSocketBufSize
</A></td>
225 <td><A HREF=
"#SNewStreamClient">SNewStreamClient
</A></td>
226 <td><A HREF=
"#SelectSetInit">SelectSetInit
</A></td>
229 <td><A HREF=
"#GetSocketLinger">GetSocketLinger
</A></td>
230 <td><A HREF=
"#SNewStreamServer">SNewStreamServer
</A></td>
231 <td><A HREF=
"#SelectSetRemove">SelectSetRemove
</A></td>
234 <td><A HREF=
"#GetSocketNagleAlgorithm">GetSocketNagleAlgorithm
</A></td>
235 <td><A HREF=
"#SRead">SRead
</A></td>
236 <td><A HREF=
"#SelectW">SelectW
</A></td>
239 <td><A HREF=
"#InitSReadlineInfo">InitSReadlineInfo
</A></td>
240 <td><A HREF=
"#SReadline">SReadline
</A></td>
241 <td><A HREF=
"#Sendto">Sendto
</A></td>
244 <td><A HREF=
"#SAcceptA">SAcceptA
</A></td>
245 <td><A HREF=
"#SRecv">SRecv
</A></td>
246 <td><A HREF=
"#SendtoByName">SendtoByName
</A></td>
249 <td><A HREF=
"#SAcceptS">SAcceptS
</A></td>
250 <td><A HREF=
"#SRecvfrom">SRecvfrom
</A></td>
251 <td><A HREF=
"#SetSocketBufSize">SetSocketBufSize
</A></td>
254 <td><A HREF=
"#SBind">SBind
</A></td>
255 <td><A HREF=
"#SRecvmsg">SRecvmsg
</A></td>
256 <td><A HREF=
"#SetSocketLinger">SetSocketLinger
</A></td>
259 <td><A HREF=
"#SClose">SClose
</A></td>
260 <td><A HREF=
"#SSend">SSend
</A></td>
261 <td><A HREF=
"#SetSocketNagleAlgorithm">SetSocketNagleAlgorithm
</A></td>
264 <td><A HREF=
"#SConnect">SConnect
</A></td>
265 <td><A HREF=
"#SSendto">SSendto
</A></td>
271 <A NAME=
"AddrStrToAddr"></A>AddrStrToAddr
</H5>
272 <TT>int
</TT> <TT>AddrStrToAddr(const char * const s, struct sockaddr_in
273 * const sa, const int defaultPort);
</TT>
275 <P>This takes a textual internet address specification and converts it
276 to a
<TT>struct sockaddr_in
</TT>.
An address string may be any of
280 <TT>hostname:port
</TT></LI>
283 <TT>service://hostname
</TT></LI>
286 <TT>service://hostname:port
</TT></LI>
289 <TT>service://hostname[/more/junk/which/is/ignored/]
</TT></LI>
292 <TT>port@hostname
</TT></LI>
294 Additionally, the
<I>hostname
</I> may be a name or an IP address string
295 (i.e.
<TT>192.168.1.13</TT>).
297 <P>If the string contains a hostname but a port number does not appear
298 to be present and the
<I>defaultPort
</I> parameter is greater than zero,
299 then the address structure will use
<I>defaultPort
</I> as the port number.
301 <P>The function returns a negative number if the string could not be converted,
302 such as the case where the hostname was not found in the name service.
303 Name service is not used unless there is a name instead of an IP address,
304 so if you don't want to use name service, only use IP addresses.
308 <PRE>struct sockaddr_in addr;
311 result = AddrStrToAddr(
"ftp.probe.net",
&addr,
21);
312 result = AddrStrToAddr(
"ftp.probe.net:21",
&addr,
21);
313 result = AddrStrToAddr(
"206.28.166.234:21",
&addr,
21);
314 result = AddrStrToAddr(
"ftp://ftp.probe.net",
&addr,
0);
315 result = AddrStrToAddr(
"21@ftp.probe.net",
&addr,
0);
</PRE>
323 <A NAME=
"#AddrToAddrStr"></A>AddrToAddrStr
</H5>
324 <TT>char *AddrToAddrStr(char *const dst, size_t dsize, struct sockaddr_in
325 * const saddrp, int dns, const char *fmt);
</TT>
327 <P>This function takes a
<TT>struct sockaddr_in
</TT> and converts into
328 a readable internet textual address.
330 <P>The
<I>dns
</I> parameter specifies if name service should be used to
331 lookup the symbolic hostname from the raw address.
If zero, it expresses
332 the raw IP address in the standard dotted-decimal format, like
192.168.1.13.
334 <P>The
<I>fmt
</I> parameter is a magic cookie string, with the following
338 <TT>%h
</TT> = hostname
</LI>
341 <TT>%p
</TT> = port number
</LI>
344 <TT>%s
</TT> = service name (based off of the port number)
</LI>
346 This lets you print the address in just about any way you like.
The
347 <I>dst
</I> parameter is the string to write the results to, and is always
348 null-terminated.
The
<I>dst
</I> parameter is also returned as the
349 result of the function.
355 fputs(AddrToAddrStr(str, sizeof(str),
&sin,
1,
"%h"), stdout);
356 fputs(AddrToAddrStr(str, sizeof(str),
&sin,
1,
"%h:%p"), stdout);
357 fputs(AddrToAddrStr(str, sizeof(str),
&sin,
1,
"%s://%h"), stdout);
</PRE>
361 <A NAME=
"#DisposeSReadlineInfo"></A>DisposeSReadlineInfo
</H5>
362 <TT>void DisposeSReadlineInfo(SReadlineInfo *srl);
</TT>
364 <P>This function is used to dispose of a
<TT>SReadlineInfo
</TT> structure
365 that was created using
<TT><A HREF=
"#InitSReadlineInfo">InitSReadlineInfo()
</A></TT>.
366 You're required to use this to free dynamically allocated buffers it creates
367 unless you specified that you wanted to use your own buffer, in which case
368 it's optional (but recommended for clarity).
370 <A NAME=
"#FlushSReadlineInfo"></A>FlushSReadlineInfo
</H5>
371 <TT>void FlushSReadlineInfo(SReadlineInfo *srl);
</TT>
373 <P>This rarely used function is used to reset and clear the buffer used
374 by
<TT><A HREF=
"#SReadline">SReadline()
</A></TT>.
It acts similarly
375 to a
<TT>fflush(stdin)
</TT>.
377 <A NAME=
"#GetSocketBufSize"></A>GetSocketBufSize
</H5>
378 <TT>int GetSocketBufSize(int sockfd, size_t *const rsize, size_t *const
381 <P>This utility routine returns the size of the socket's internal buffers,
382 as maintained by the kernel (or socket library).
It does this by
383 calling
<TT>getsockopt()
</TT> with the
<TT>SO_RCVBUF
</TT> and
<TT>SO_SNDBUF
</TT>
384 options, if they are defined.
In the event they aren't defined, it
385 returns a negative result code.
389 <PRE>size_t rsize, ssize;
391 if (GetSocketBufSize(sockfd,
&rsize,
&ssize) ==
0) ...
</PRE>
395 <A NAME=
"#GetSocketLinger"></A>GetSocketLinger
</H5>
396 <TT>int GetSocketLinger(const int fd, int *const lingertime);
</TT>
398 <P>This utility routine returns whether linger mode has been turned on,
399 and also sets the amount of time in the
<I>lingertime
</I> parameter.
405 if (GetSocketLinger(sockfd,
&lingtime)
> 0)
406 /* linger is on... */ ...;
</PRE>
410 <A NAME=
"#GetSocketNagleAlgorithm"></A>GetSocketNagleAlgorithm
</H5>
411 <TT>int GetSocketNagleAlgorithm(const int fd);
</TT>
413 <P>This utility routine returns whether the
<I>Nagle Algorithm
</I> is in
414 effect (
<TT>TCP_NODELAY
</TT> mode not on).
416 <A NAME=
"#InitSReadlineInfo"></A>InitSReadlineInfo
</H5>
417 <TT>int InitSReadlineInfo(SReadlineInfo *srl, int sockfd, char *buf, size_t
418 bsize, int tlen);
</TT>
420 <P>This function is used to prepare a
<TT>SReadlineInfo
</TT> structure
421 for use with the
<TT><A HREF=
"#SReadline">SReadline()
</A></TT> function.
422 The
<I>sockfd
</I> parameter specifies the socket that will be used for
423 line buffering.
The
<I>sio
</I> library does not open or close this
426 <P>The buf parameter is the area of memory to use for buffering; it should
427 be large enough to hold several lines of data.
If
<I>buf
</I> is NULL,
428 the function will
<TT>malloc()
</TT> one of
<I>bsize
</I> bytes, otherwise
429 it is assumed that buf is maintained by you and is of size
<I>bsize
</I>
430 bytes.
If you let
<I>sio
</I> <TT>malloc()
</TT> this buffer, you must
431 also use
<TT><A HREF=
"#DisposeSReadlineInfo">DisposeSReadlineInfo()
</A></TT>
432 to free it when you're finished with it.
434 <P>The
<I>tlen
</I> parameter is the timeout value (in seconds) to use for
435 each call of
<TT><A HREF=
"#SReadline">SReadline()
</A></TT>.
439 <PRE>SReadlineInfo sri;
442 if (InitSReadlineInfo(
&sri, sockfd, NULL,
512,
10)
< 0)
443 perror(
"malloc 512 bytes failed");
445 (void) InitSReadlineInfo(
&sri, sockfd, localbuf, sizeof(localbuf),
10);
</PRE>
449 <A NAME=
"SAccept"></A>SAccept
</H5>
450 <TT>int SAccept(int sfd, struct sockaddr_in *const addr, int tlen);
</TT>
452 <P>This is does an
<TT>accept()
</TT>, with a timeout of
<I>tlen
</I> seconds
453 (
<I>tlen
</I> may be zero to mean block indefinitely).
If no new connection
454 is accepted,
<TT>kTimeoutErr
</TT> is returned, otherwise a new socket or
455 (-
1) is returned.
The socket is still usable if a timeout occurred,
456 so you can call
<TT>SAccept()
</TT> again.
458 <A NAME=
"#SBind"></A>SBind
</H5>
459 <TT>int SBind(int sockfd, const int port, const int nTries, const int reuseFlag);
</TT>
461 <P>This calls
<TT>bind()
</TT>, to the wildcard address with the specified
462 <I>port
</I>(not in network byte order).
The
<I>nTries
</I> parameter
463 tells how many attempts it tries before giving up (which is useful if other
464 processes are grabbing the same port number).
If the
<I>reuseFlag
</I>
465 parameter is non-zero,
<TT>SBind()
</TT> tries to turn on the
<TT>SO_REUSEADDR
</TT>
466 (and
<TT>SO_REUSEPORT
</TT>, if available) socket options before binding.
468 <P>Normally you will not call this function directly, since
<TT><A HREF=
"#SNewStreamServer">SNewStreamServer()
</A></TT>
469 and
<TT><A HREF=
"#SNewDatagramServer">SNewDatagramServer()
</A></TT> do
472 <A NAME=
"#SClose"></A>SClose
</H5>
473 <TT>int SClose(int sfd, int tlen);
</TT>
475 <P>This is
<TT>close()
</TT> with a timeout of
<I>tlen
</I> seconds.
476 Normally you don't need to worry about
<TT>close()
</TT> blocking, but if
477 you have turned on linger mode,
<TT>close()
</TT> could block.
<TT>SClose()
</TT>
478 calls
<TT>close()
</TT> for up to
<I>tlen
</I> seconds, and if the timeout
479 expires, it calls
<TT>shutdown()
</TT> on the socket.
481 <A NAME=
"#SConnect"></A>SConnect
</H5>
482 <TT>int SConnect(int sfd, const struct sockaddr_in *const addr, int tlen);
</TT>
484 <P>This is
<TT>connect()
</TT> with a timeout of
<I>tlen
</I> seconds (
<I>tlen
</I>
485 may be zero to mean block indefinitely).
If it returns (-
1) or
<TT>kTimeoutErr
</TT>,
486 the socket is no longer usable and must be closed.
488 <A NAME=
"#SConnectByName"></A>SConnectByName
</H5>
489 <TT>int SConnectByName(int sfd, const char * const addrStr, const int tlen);
</TT>
491 <P>This is
<TT>connect()
</TT> with a timeout of
<I>tlen
</I> seconds (
<I>tlen
</I>
492 may be zero to mean block indefinitely).
If it returns (-
1) or
<TT>kTimeoutErr
</TT>,
493 the socket is no longer usable and must be closed. The difference between
494 <TT><A HREF=
"#SConnect">SConnect()
</A></TT> is that this function takes
495 a textual address string instead of a
<TT>struct sockaddr_in
</TT>.
499 <PRE>if (SConnectByName(sockfd,
"http://www.probe.net",
15) ==
0) ...
</PRE>
503 <A NAME=
"#SListen"></A>SListen
</H5>
504 <TT>int SListen(int sfd, int backlog);
</TT>
506 <P>This isn't too useful at present, since it just does
<TT>listen(sfd,
507 backlog)
</TT>.
And, you will not call this function directly, since
508 <TT><A HREF=
"#SNewStreamServer">SNewStreamServer()
</A></TT> and
<TT><A HREF=
"#SNewDatagramServer">SNewDatagramServer()
</A></TT>
511 <A NAME=
"#SNewDatagramClient"></A>SNewDatagramClient
</H5>
512 <TT>int SNewDatagramClient(void);
</TT>
514 <P>This returns a new datagram socket, which is ready to send (and then
515 receive) datagrams.
This function is just
<TT>socket(AF_INET, SOCK_DGRAM,
516 0)
</TT>. If successful, it returns a non-negative socket descriptor.
522 sockfd = SNewDatagramClient();
</PRE>
526 <A NAME=
"#SNewDatagramServer"></A>SNewDatagramServer
</H5>
527 <TT>int SNewDatagramServer(const int port, const int nTries, const int
530 <P>This function creates a new socket and binds it to the specified
<I>port
</I>
531 (not in network byte order) on the wildcard address.
The
<I>nTries
</I>
532 and
<I>reuseFlag
</I> are used when it calls
<TT><A HREF=
"#SBind">SBind()
</A></TT>.
533 If successful, it returns a non-negative socket descriptor.
539 sockfd = SNewDatagramServer(
13,
3,
0);
541 /* ready to receive requests on the daytime port (
13) */
</PRE>
545 <A NAME=
"#SNewStreamClient"></A>SNewStreamClient
</H5>
546 <TT>int SNewStreamClient(void);
</TT>
548 This returns a new stream socket, which is ready to
<TT><A HREF=
"#SConnect">SConnect()
</A></TT>
549 to a server.
This function is just
<TT>socket(AF_INET, SOCK_STREAM,
550 0)
</TT>.
If successful, it returns a non-negative socket descriptor.
556 sockfd = SNewStreamClient();
</PRE>
560 <A NAME=
"#SNewStreamServer"></A>SNewStreamServer
</H5>
561 <TT>int SNewStreamServer(const int port, const int nTries, const int reuseFlag,
562 int listenQueueSize);
</TT>
564 <P>This function creates a new socket, binds it to the specified
<I>port
</I>
565 (not in network byte order) on the wildcard address, and turns it on for
566 listening.
The
<I>nTries
</I> and
<I>reuseFlag
</I> are used when it
567 calls
<TT><A HREF=
"#SBind">SBind()
</A></TT>. The
<I>listenQueueSize
</I>
568 is for the
<TT>listen()
</TT> call.
If successful, it returns a non-negative
575 sockfd = SNewStreamServer(
80,
3,
0);
577 /* ready to accept HTTP connections */
</PRE>
581 <A NAME=
"#SRead"></A>SRead
</H5>
582 <TT>int SRead(int sfd, char *const buf0, size_t size, int tlen, int retry);
</TT>
584 <P>This is
<TT>read()
</TT> on a socket descriptor, with a timeout of
<I>tlen
</I>
585 seconds (
<I>tlen
</I> must be greater than zero).
Like
<TT>read()
</TT>,
586 it can return
0, (-
1), or the number of bytes read, but in addition, it
587 can also return
<TT>kTimeoutErr
</TT>.
589 <P>If
<I>retry
</I> is set to
<TT>kFullBufferRequired
</TT>,
<TT>SRead()
</TT>
590 does not return until
<I>size
</I> bytes has been read or EOF is encountered.
591 This is useful if you expect fixed-length records, and it doesn't do much
592 good until a complete record has been read. However, it is still possible
593 that an EOF is encountered after some bytes have been read, and with
<I>retry
</I>
594 set to
<TT>kFullBufferRequired
</TT>, you get EOF instead of that partial
595 record.
If you set retry to
<TT>kFullBufferRequiredExceptLast
</TT>,
596 you get the partial record (and EOF on the next
<TT>SRead()
</TT>).
597 Otherwise, if you should set retry to kFullBufferNotRequired and SRead()
598 will return when there is some data read.
606 nread = SRead(sockfd, buf, sizeof(buf),
15, kFullBufferNotRequired);
607 if (nread
<=
0) {
608 if (nread ==
0)
609 break;
/* okay, EOF */
610 else if (nread == kTimeoutErr) {
611 fprintf(stderr,
"timed-out\n");
612 break;
613 } else {
614 perror(
"read");
615 }
617 (void) write(
1, buf, nread);
622 <A NAME=
"#SReadline"></A>SReadline
</H5>
623 <TT>int SReadline(SReadlineInfo *srl, char *const linebuf, size_t linebufsize);
</TT>
625 <P>It is often desirable to process data from sockets line by line, however
626 this is cumbersome to do on a socket descriptor.
The
<TT>SReadline()
</TT>
627 function allows you to do this, so you can do one call of the function
628 and get back a line of input.
It accomplishes this much the same
629 way the standard library's I/O routines do this, using a buffer.
630 However, it is usually not possible to determine if the standard library
631 takes the same special I/O measures on socket descriptors that sio does,
632 so using the standard library function
<TT>fdopen()
</TT> with a socket
633 descriptor may or may not work the way you want.
635 <P><TT>SReadline()
</TT> needs to maintain state information for each call,
636 so a data structure is required.
You must first call
<TT><A HREF=
"#InitSReadlineInfo">InitSReadlineInfo()
</A></TT>
637 to initialize a
<TT>SReadlineInfo
</TT> structure.
After that, you
638 may call
<TT>SReadline()
</TT> repeatedly until it returns
0 to indicate
639 EOF. The function returns the number of characters in the input line, including
640 a newline (however, carriage return characters are omitted).
You
641 must call
<TT><A HREF=
"#DisposeSReadlineInfo">DisposeSReadlineInfo()
</A></TT>
642 if you chose to let
<TT><A HREF=
"#InitSReadlineInfo">InitSReadlineInfo()
</A></TT>
643 use
<TT>malloc()
</TT> to allocate your buffer.
647 <PRE>SReadlineInfo sri;
651 if (InitSReadlineInfo(
&sri, sockfd, NULL,
512,
10)
< 0) {
652 perror(
"malloc");
653 exit(
1);
656 nread = SReadline(
&sri, line, sizeof(line));
657 if (nread
<=
0) {
658 if (nread == kTimeoutErr)
659 fprintf(stderr,
"readline timed-out.\n");
660 else if (nread
< 0)
661 perror(
"readline");
662 break;
664 line[nread] = '\
0';
/* omit newline */
665 fprintf(stdout,
"read [%s]\n", line);
667 DisposeSReadlineInfo(
&sri);
668 (void) SClose(sockfd,
3);
</PRE>
672 <A NAME=
"#SRecv"></A>SRecv
</H5>
673 <TT>int SRecv(int sfd, char *const buf0, size_t size, int fl, int tlen,
676 <P>This is the corresponding wrapper for
<TT>recv()
</TT>, as
<TT><A HREF=
"#SRead">SRead()
</A></TT>
677 is for
<TT>read()
</TT>.
You will never need this function, unless
678 you need the special receiving flags that
<TT>recv()
</TT> gives you.
680 <A NAME=
"#SRecvfrom"></A>SRecvfrom
</H5>
681 <TT>int SRecvfrom(int sfd, char *const buf, size_t size, int fl, struct
682 sockaddr_in *const fromAddr, int tlen);
</TT>
684 <P>This is
<TT>recvfrom()
</TT> with a timeout of
<I>tlen
</I> seconds (
<I>tlen
</I>
685 must be greater than zero).
Like
<TT>recvfrom()
</TT>, it can return
686 0, (-
1), or the number of bytes read, but in addition, it can also return
687 <TT>kTimeoutErr
</TT>. Upon a timeout, the socket is still valid for additional
694 struct sockaddr_in remoteClientAddr;
696 nread = SRecvfrom(sockfd, buf, sizeof(buf),
0,
&remoteClientAddr,
15);
698 if (nread == kTimeoutErr)
699 fprintf(stderr,
"recvfrom timed-out.\n");
700 else if (nread
< 0)
701 perror(
"recvfrom");
706 <A NAME=
"#SRecvmsg"></A>SRecvmsg
</H5>
707 <TT>int SRecvmsg(int sfd, void *const msg, int fl, int tlen);
</TT>
709 <P>This is the corresponding wrapper for
<TT>recvmsg()
</TT>, as
<TT><A HREF=
"#SRead">SRead()
</A></TT>
710 is for
<TT>read()
</TT>.
712 <A NAME=
"#SSend"></A>SSend
</H5>
713 <TT>int SSend(int sfd, char *buf0, size_t size, int fl, int tlen);
</TT>
715 <P>This is the corresponding wrapper for
<TT>send()
</TT>, as
<TT><A HREF=
"#SWrite">SWrite()
</A></TT>
716 is for
<TT>write()
</TT>.
You will never need this function, unless
717 you need the special receiving flags that
<TT>send()
</TT> gives you.
719 <A NAME=
"#SSendto"></A>SSendto
</H5>
720 <TT>int SSendto(int sfd, const char *const buf, size_t size, int fl, const
721 struct sockaddr_in *const toAddr, int tlen);
</TT>
723 <P>This is
<TT>sendto()
</TT> with a timeout of
<I>tlen
</I> seconds (
<I>tlen
</I>
724 must be greater than zero).
Like
<TT>sendto()
</TT>, it can return
725 0, (-
1), or the number of bytes sent, but in addition, it can also return
726 <TT>kTimeoutErr
</TT>. Upon a timeout, the socket is still valid for additional
729 <P>Since
<TT>sendto()
</TT> rarely blocks (only if the outgoing queue is
730 full), you probably do not want to use a timeout or bother with its associated
731 overhead; therefore
<TT><A HREF=
"#Sendto">Sendto()
</A></TT> would be a
734 <A NAME=
"#SSendtoByName"></A>SSendtoByName
</H5>
735 <TT>int SSendtoByName(int sfd, const char *const buf, size_t size, int
736 fl, const char *const toAddrStr, int tlen);
</TT>
738 <P>This is
<TT><A HREF=
"#SSendto">SSendto()
</A></TT>, only you can use
739 a textual internet address string instead of a
<TT>struct sockaddr_in
</TT>.
741 <A NAME=
"#SWrite"></A>SWrite
</H5>
742 <TT>int SWrite(int sfd, const char *const buf0, size_t size, int tlen);
</TT>
744 <P>This is
<TT>write()
</TT> on a network socket with a timeout of
<I>tlen
</I>
745 seconds (
<I>tlen
</I> must be greater than zero).
Like
<TT>write()
</TT>,
746 it can return
0, (-
1), or the number of bytes sent, but in addition, it
747 can also return
<TT>kTimeoutErr
</TT>.
749 <A NAME=
"SelectR"></A>SelectR
</H5>
750 <TT>int SelectR(SelectSetPtr ssp, SelectSetPtr resultssp);
</TT>
752 <P>This does a
<TT>select()
</TT> for reading with the file descriptors
753 in the specified
<TT>SelectSet
</TT>.
Using a
<TT>SelectSet
</TT> ensures
754 that the first argument to select is always correct (the smallest correct
755 value, for speed) and
<TT>SelectR()
</TT> does not destroy the original
756 <TT>fd_set
</TT> and
<TT>timeval
</TT> (it copies it to
<I>resultssp
</I>
757 before using
<TT>select()
</TT>).
761 <PRE>SelectSet ss, selected;
763 SelectSetInit(
&ss,
10.0);
764 SelectSetAdd(
&ss, sockfd1);
765 SelectSetAdd(
&ss, sockfd2);
766 rc = SelectR(
&ss,
&selected);
767 if ((rc
> 0)
&& (FD_ISSET(sockfd2,
&selected.fds))) ...
</PRE>
771 <A NAME=
"SelectW"></A>SelectW
</H5>
772 <TT>int SelectW(SelectSetPtr ssp, SelectSetPtr resultssp);
</TT>
774 <P>This does a
<TT>select()
</TT> for writing with the file descriptors
775 in the specified
<TT>SelectSet
</TT>.
Using a
<TT>SelectSet
</TT> ensures
776 that the first argument to select is always correct (the smallest correct
777 value, for speed) and
<TT>SelectW()
</TT> does not destroy the original
778 <TT>fd_set
</TT> and
<TT>timeval
</TT> (it copies it to
<I>resultssp
</I>
779 before using
<TT>select()
</TT>).
783 <PRE>SelectSet ss, selected;
785 SelectSetInit(
&ss,
10.0);
786 SelectSetAdd(
&ss, sockfd1);
787 SelectSetAdd(
&ss, sockfd2);
788 rc = SelectW(
&ss,
&selected);
789 if ((rc
> 0)
&& (FD_ISSET(sockfd2,
&selected.fds))) ...
</PRE>
793 <A NAME=
"#SelectSetAdd"></A>SelectSetAdd
</H5>
794 <TT>void SelectSetAdd(SelectSetPtr const ssp, const int fd);
</TT>
796 <P>This adds a descriptor to the set to select on.
802 SelectSetInit(
&ss,
10.0);
803 SelectSetAdd(
&ss, sockfd);
</PRE>
807 <A NAME=
"#SelectSetInit"></A>SelectSetInit
</H5>
808 <TT>void SelectSetInit(SelectSetPtr const ssp, const double timeout);
</TT>
810 <P>Before adding members to the
<TT>SelectSet
</TT> structure, it must be
811 initialized with this function.
The timeout parameter initializes
812 the timeout to use for future
<TT>Selects
</TT>.
814 <A NAME=
"#SelectSetRemove"></A>SelectSetRemove
</H5>
815 <TT>void SelectSetRemove(SelectSetPtr const ssp, const int fd);
</TT>
817 <P>This removes a descriptor from the set to select on.
You will
818 need to do this just before you close a descriptor that was in the set.
820 <A NAME=
"#Sendto"></A>Sendto
</H5>
821 <TT>int Sendto(int sfd, const char *const buf, size_t size, const struct
822 sockaddr_in *const toAddr);
</TT>
824 <P>This is a simple wrapper for
<TT>sendto()
</TT>, which only handles
<TT>EINTR
</TT>
825 for you.
It does not worry about
<TT>SIGPIPEs
</TT>.
827 <A NAME=
"#SendtoByName"></A>SendtoByName
</H5>
828 <TT>int SendtoByName(int sfd, const char *const buf, size_t size, const
829 char *const toAddrStr);
</TT>
831 <P>This is a simple wrapper for
<TT>sendto()
</TT>, which only handles
<TT>EINTR
</TT>
832 for you.
In addition, you can use a textual internet address string
833 instead of a
<TT>struct sockaddr_in
</TT>.
837 <PRE>if (SendtoByName(sockfd, msg, sizeof(msg),
"elwood.probe.net:13")
> 0) ...
</PRE>
841 <A NAME=
"#SetSocketBufSize"></A>SetSocketBufSize
</H5>
842 <TT>int SetSocketBufSize(int sockfd, size_t rsize, size_t ssize);
</TT>
844 <P>This utility routine changes the size of the socket's internal buffers,
845 as maintained by the kernel (or socket library).
It does this by
846 calling
<TT>setsockopt()
</TT> with the
<TT>SO_RCVBUF
</TT> and
<TT>SO_SNDBUF
</TT>
847 options, if they are defined.
In the event they aren't defined, it
848 returns a negative result code.
The operation is only performed if
849 the size is greater than zero, so if you only wanted to change the receive
850 buffer you could set
<I>rsize
</I> to greater than zero and
<I>ssize
</I>
853 <A NAME=
"#SetSocketLinger"></A>SetSocketLinger
</H5>
854 <TT>int SetSocketLinger(const int fd, const int l_onoff, const int l_linger);
</TT>
856 <P>This is an interface to the
<TT>SO_LINGER
</TT> socket option.
857 The
<I>l_onoff
</I> parameter is a boolean specifying whether linger is
858 on, and the
<I>l_linger
</I> parameter specifies the length of the linger
863 <PRE>if (SetSocketLinger(sockfd,
1,
90) ==
0) ...
</PRE>
867 <A NAME=
"#SetSocketNagleAlgorithm"></A>SetSocketNagleAlgorithm
</H5>
868 <TT>int SetSocketNagleAlgorithm(const int fd, const int onoff);
</TT>
870 <P>This utility routine enables or disables the
<I>Nagle Algorithm
</I>
871 (
<TT>TCP_NODELAY
</TT> mode is off or on).
Generally you won't care
872 about this, unless you're writing an interactive application like
<I>telnet
</I>,
873 <I>talk
</I>, or
<I>rlogin
</I>, where response time is more important than
878 <PRE>if (SetSocketNagleAlgorithm(sockfd,
0) ==
0) ...
</PRE>
882 <A NAME=
"Sample"></A>Sample Code
</H3>
883 Here is an example client and server that uses the
<I>sio
</I> library routines.
884 The server simply takes data and uppercases any lower case data, and returns
885 the result to the client.
To try it on port number
5123, you could
886 run
"<TT>ucase_s 5123</TT>" in one window, and
"<TT>ucase_c localhost:5123</TT>"
894 #include
<unistd.h
>
895 #include
<sys/types.h
>
896 #include
<sys/socket.h
>
897 #include
<sys/wait.h
>
898 #include
<netinet/in.h
>
899 #include
<arpa/inet.h
>
900 #include
<errno.h
>
901 #include
<stdio.h
>
902 #include
<string.h
>
903 #include
<stdlib.h
>
904 #include
<time.h
>
906 #include
"sio.h
"
909 ServeOneClient(int sockfd, struct sockaddr_in *cliAddr)
911 char buf[
32], cliAddrStr[
64];
912 int nread, nwrote, i;
914 printf(
"subserver[%d]: started, connected to %s.\n
", (int) getpid(),
915 AddrToAddrStr(cliAddrStr, sizeof(cliAddrStr), cliAddr,
1,
"<%h:%p
>")
918 nread = SRead(sockfd, buf, sizeof(buf),
15, kFullBufferNotRequired);
921 } else if (nread
< 0) {
922 fprintf(stderr,
"subserver[%d]: read error: %s\n
",
923 (int) getpid(), strerror(errno));
926 for (i=
0; i
<nread; i++)
928 buf[i] = toupper(buf[i]);
929 nwrote = SWrite(sockfd, buf, nread,
15);
931 fprintf(stderr,
"subserver[%d]: write error: %s\n
",
932 (int) getpid(), strerror(errno));
936 (void) SClose(sockfd,
10);
937 printf(
"subserver[%d]: done.\n
", (int) getpid());
939 } /* ServeOneClient */
945 int sockfd, newsockfd;
946 struct sockaddr_in cliAddr;
949 sockfd = SNewStreamServer(port,
3, kReUseAddrYes,
3);
951 perror(
"Server setup failed
");
955 printf(
"server[%d]: started.\n
", (int) getpid());
957 while (waitpid(-
1, NULL, WNOHANG)
> 0) ;
958 newsockfd = SAccept(sockfd,
&cliAddr,
5);
959 if (newsockfd
< 0) {
960 if (newsockfd == kTimeoutErr)
961 printf(
"server[%d]: idle\n
", (int) getpid());
963 fprintf(stderr,
"server[%d]: accept error: %s\n
",
964 (int) getpid(), strerror(errno));
965 } else if ((pid = fork())
< 0) {
966 fprintf(stderr,
"server[%d]: fork error: %s\n
",
967 (int) getpid(), strerror(errno));
969 } else if (pid ==
0) {
970 ServeOneClient(newsockfd,
&cliAddr);
973 /* Parent doesn't need it now. */
974 (void) close(newsockfd);
981 main(int argc, char **argv)
986 fprintf(stderr,
"Usage: %s
<port
>\n
", argv[
0]);
989 port = atoi(argv[
1]);
1000 #include
<unistd.h
>
1001 #include
<sys/types.h
>
1002 #include
<sys/socket.h
>
1003 #include
<sys/wait.h
>
1004 #include
<netinet/in.h
>
1005 #include
<arpa/inet.h
>
1006 #include
<errno.h
>
1007 #include
<stdio.h
>
1008 #include
<string.h
>
1009 #include
<stdlib.h
>
1010 #include
<time.h
>
1012 #include
"sio.h
"
1015 Client(char *serverAddrStr)
1018 int nread, nwrote, sockfd;
1020 sockfd = SNewStreamClient();
1021 if (sockfd
< 0) {
1022 fprintf(stderr,
"client[%d]: socket error: %s\n
",
1023 (int) getpid(), strerror(errno));
1027 if (SConnectByName(sockfd, serverAddrStr,
15)
< 0) {
1028 fprintf(stderr,
"client[%d]: could not connect to
<%s
>: %s\n
",
1029 (int) getpid(), serverAddrStr, strerror(errno));
1033 printf(
"client[%d]: connected to
<%s
>.\n
", (int) getpid(), serverAddrStr);
1034 for (buf[sizeof(buf) -
1] = '\
0';;) {
1035 printf(
"client[%d]: Enter message to send -
> ", (int) getpid());
1036 if (fgets(buf, sizeof(buf) -
1, stdin) == NULL)
1038 buf[strlen(buf) -
1] = '\
0'; /* Delete newline. */
1040 continue; /* Blank line. */
1042 /* Send the request line to the server. */
1043 nwrote = SWrite(sockfd, buf, strlen(buf),
15);
1044 if (nwrote
< 0) {
1045 fprintf(stderr,
"client[%d]: write error: %s\n
",
1046 (int) getpid(), strerror(errno));
1050 /* Wait for complete reply line */
1051 nread = SRead(sockfd, buf, nwrote,
15, kFullBufferRequired);
1053 fprintf(stderr,
"client[%d]: no reply received (EOF).\n
",
1056 } else if (nread
< 0) {
1057 fprintf(stderr,
"client[%d]: read error: %s\n
",
1058 (int) getpid(), strerror(errno));
1062 fprintf(stdout,
"client[%d]: received: %s\n
",
1063 (int) getpid(), buf);
1065 (void) SClose(sockfd,
10);
1066 printf(
"\nclient[%d]: done.\n
", (int) getpid());
1072 main(int argc, char **argv)
1077 fprintf(stderr,
"Usage: %s
<host:port
>\n
", argv[
0]);