Test for events on multiple sockets simultaneously
- Prototypes
-
#include <sys/poll.h>
int poll(struct pollfd *ufds, unsigned int nfds, int
timeout);
- Description
-
This function is very similar to select() in that they both watch
sets of file descriptors for events, such as incoming data ready to
recv(), socket ready to send() data to, out-of-band data ready
to recv(), errors, etc.
The basic idea is that you pass an array of nfds struct
pollfds in ufds, along with a timeout in milliseconds (1000
milliseconds in a second.) The timeout can be negative if you
want to wait forever. If no event happen on any of the socket descriptors by the
timeout, poll() will return.
Each element in the array of struct pollfds represents one socket
descriptor, and contains the following fields:
struct pollfd { int fd; // the socket descriptor short events; // bitmap of events we're interested in short revents; // when poll() returns, bitmap of events that occurred };
|
Before calling poll(), load fd with the socket
descriptor (if you set fd to a negative number, this struct
pollfd is ignored and its revents field is set to zero) and
then construct the events field by bitwise-ORing the following
macros:
|
POLLIN |
Alert me when data is ready to recv() on this socket. |
|
POLLOUT |
Alert me when I can send() data to this socket without
blocking. |
|
POLLPRI |
Alert me when out-of-band data is ready to recv() on this
socket. |
Once the poll() call returns, the revents field will
be constructed as a bitwise-OR of the above fields, telling you which
descriptors actually have had that event occur. Additionally, these other fields
might be present:
|
POLLERR |
An error has occurred on this socket. |
|
POLLHUP |
The remote side of the connection hung up. |
|
POLLNVAL |
Something was wrong with the socket descriptor fd--maybe it's
uninitialized? |
- Return Value
-
Returns the number of elements in the ufds array that have
had event occur on them; this can be zero if the timeout occurred. Also returns
-1 on error (and errno will be set
accordingly.)
- Example
-
int s1, s2; int rv; char buf1[256], buf2[256]; struct pollfd ufds[2];
s1 = socket(PF_INET, SOCK_STREAM, 0); s2 = socket(PF_INET, SOCK_STREAM, 0);
// pretend we've connected both to a server at this point //connect(s1, ...)... //connect(s2, ...)...
// set up the array of file descriptors. // // in this example, we want to know when there's normal or out-of-band // data ready to be recv()'d...
ufds[0].fd = s1; ufds[0].events = POLLIN | POLLPRI; // check for normal or out-of-band
ufds[1] = s2; ufds[1].events = POLLIN; // check for just normal data
// wait for events on the sockets, 3.5 second timeout rv = poll(ufds, 2, 3500);
if (rv == -1) { perror("poll"); // error occurred in poll() } else if (rv == 0) { printf("Timeout occurred! No data after 3.5 seconds.
"); } else { // check for events on s1: if (ufds[0].revents & POLLIN) { recv(s1, buf1, sizeof(buf1), 0); // receive normal data } if (ufds[0].revents & POLLPRI) { recv(s1, buf1, sizeof(buf1), MSG_OOB); // out-of-band data }
// check for events on s2: if (ufds[1].revents & POLLIN) { recv(s1, buf2, sizeof(buf2), 0); } }
|
- See Also
-
select()
Recieve data on a socket
- Prototypes
-
#include <sys/types.h> #include
<sys/socket.h>
ssize_t recv(int s, void *buf, size_t len, int
flags); ssize_t recvfrom(int s, void *buf, size_t len, int
flags, struct sockaddr *from, socklen_t
*fromlen);
- Description
-
Once you have a socket up and connected, you can read incoming data from the
remote side using the recv() (for TCP SOCK_STREAM
sockets) and recvfrom() (for UDP SOCK_DGRAM
sockets).
Both functions take the socket descriptor s, a pointer to the
buffer buf, the size (in bytes) of the buffer
len, and a set of flags that control how the
functions work.
Additionally, the recvfrom() takes a struct sockaddr*,
from that will tell you where the data came from, and will fill
in fromlen with the size of struct sockaddr. (You must
also initialize fromlen to be the size of from
or struct sockaddr.)
So what wonderous flags can you pass into this function? Here are some of
them, but you should check your local man pages for more information and what is
actually supported on your system. You bitwise-or these together, or just set
flags to 0 if you want it to be a regular
vanilla recv().
|
MSG_OOB |
Recieve Out of Band data. This is how to get data that has been sent to you
with the MSG_OOB flag in send(). As the recieving side,
you will have had signal SIGURG raised telling you there is
urgent data. In your handler for that signal, you could call recv()
with this MSG_OOB flag. |
|
MSG_PEEK |
If you want to call recv() "just for pretend", you can call it with
this flag. This will tell you what's waiting in the buffer for when you call
recv() "for real" (i.e. without the MSG_PEEK
flag. It's like a sneak preview into the next recv()
call. |
|
MSG_WAITALL |
Tell recv() to not return until all the data you specified in the
len parameter. It will ignore your wishes in extreme
circumstances, however, like if a signal interrupts the call or if some error
occurs or if the remote side closes the connection, etc. Don't be mad with
it. |
When you call recv(), it will block until there is some data to
read. If you want to not block, set the socket to non-blocking or check with
select() or poll() to see if there is incoming data before
calling recv() or recvfrom().
- Return Value
-
Returns the number of bytes actually recieved (which might be less than you
requested in the len paramter), or -1 on error
(and errno will be set accordingly.)
If the remote side has closed the connection, recv() will return
0. This is the normal method for determining if the remote side
has closed the connection. Normality is good, rebel!
- Example
-
int s1, s2; int byte_count, fromlen; struct sockaddr_in addr; char buf[512];
// show example with a TCP stream socket first s1 = socket(PF_INET, SOCK_STREAM, 0);
// info about the server addr.sin_family = AF_INET; addr.sin_port = htons(3490); inet_aton("10.9.8.7", &addr.sin_addr);
connect(s1, &addr, sizeof(addr)); // connect to server
// all right! now that we're connected, we can recieve some data! byte_count = recv(s1, buf, sizeof(buf), 0); printf("recv()'d %d bytes of data in buf
", byte_count);
// now demo for UDP datagram sockets: s2 = socket(PF_INET, SOCK_DGRAM, 0);
fromlen = sizeof(addr); byte_count = recvfrom(s2, buf, sizeof(buf), 0, &addr, &fromlen); printf("recv()'d %d bytes of data in buf
", byte_count); printf("from IP address %s
", inet_ntoa(addr.sin_addr));
|
- See Also
-
send(), sendto(), select(), poll(),
Blocking
Check if sockets descriptors are ready to read/write
- Prototypes
-
#include <sys/select.h>
int select(int n, fd_set *readfds, fd_set
*writefds, fd_set *exceptfds, struct timeval
*timeout); FD_SET(int fd, fd_set *set); FD_CLR(int fd,
fd_set *set); FD_ISSET(int fd, fd_set
*set); FD_ZERO(fd_set *set);
- Description
-
The select() function gives you a way to simultaneously check
multiple sockets to see if they have data waiting to be recv()d, or if
you can send() data to them without blocking, or if some exception has
occurred.
You populate your sets of socket descriptors using the macros, like
FD_SET(), above. Once you have the set, you pass it into the function
as one of the following parameters: readfds if you want to know
when any of the sockets in the set is ready to recv() data,
writefds if any of the sockets is ready to send() data
to, and/or exceptfds if you need to know when an exception
(error) occurs on any of the sockets. Any or all of these parameters can be
NULL if you're not interested in those types of events. After
select() returns, the values in the sets will be changed to show which
are ready for reading or writing, and which have exceptions.
The first parameter, n is the highest-numbered socket
descriptor (they're just ints, remember?) plus one.
Lastly, the struct timeval, timeout, at the
end--this lets you tell select() how long to check these sets for.
It'll return after the timeout, or when an event occurs, whichever is first. The
struct timeval has two fields: tv_sec is the number of
seconds, to which is added tv_usec, the number of microseconds
(1,000,000 microseconds in a second.)
The helper macros do the following:
|
FD_SET(int fd, fd_set *set); |
Add fd to the set. |
|
FD_CLR(int fd, fd_set *set); |
Remove fd from the set. |
|
FD_ISSET(int fd, fd_set *set); |
Return true if fd is in the
set. |
|
FD_ZERO(fd_set *set); |
Clear all entries from the
set. |
- Return Value
-
Returns the number of descriptors in the set on success, 0 if
the timeout was reached, or -1 on error (and errno will
be set accordingly.) Also, the sets are modified to show which sockets are
ready.
- Example
-
int s1, s2, n; fd_set readfds; struct timeval tv; char buf1[256], buf2[256];
s1 = socket(PF_INET, SOCK_STREAM, 0); s2 = socket(PF_INET, SOCK_STREAM, 0);
// pretend we've connected both to a server at this point //connect(s1, ...)... //connect(s2, ...)...
// clear the set ahead of time FD_ZERO(&readfds);
// add our descriptors to the set FD_SET(s1, &readfds); FD_SET(s2, &readfds);
// since we got s2 second, it's the "greater", so we use that for // the n param in select() n = s2 + 1;
// wait until either socket has data ready to be recv()d (timeout 10.5 secs) tv.tv_sec = 10; tv.tv_usec = 500000; rv = select(n, &readfds, NULL, NULL, &tv);
if (rv == -1) { perror("select"); // error occurred in select() } else if (rv == 0) { printf("Timeout occurred! No data after 10.5 seconds.
"); } else { // one or both of the descriptors have data if (FD_ISSET(s1, &readfds)) { recv(s1, buf1, sizeof(buf1), 0); } if (FD_ISSET(s2, &readfds)) { recv(s1, buf2, sizeof(buf2), 0); } }
|
- See Also
-
poll()
Set various options for a socket
- Prototypes
-
#include <sys/types.h> #include
<sys/socket.h>
int getsockopt(int s, int level, int optname, void
*optval, socklen_t *optlen); int
setsockopt(int s, int level, int optname, const void
*optval, socklen_t optlen);
- Description
-
Sockets are fairly configurable beasts. In fact, they are so configurable,
I'm not even going to cover it all here. It's probably system-dependent anyway.
But I will talk about the basics.
Obviously, these functions get and set certain options on a socket. On a
Linux box, all the socket information is in the man page for socket in section
7. (Type: "man 7 socket" to get all these goodies.)
As for parameters, s is the socket you're talking about,
level should be set to SOL_SOCKET. Then you set the
optname to the name you're interested in. Again, see your man
page for all the options, but here are some of the most fun ones:
|
SO_BINDTODEVICE |
Bind this socket to a symbolic device name like eth0 instead of
using bind() to bind it to an IP address. Type the command
ifconfig under Unix to see the device names. |
SO_REUSEADDR
|
Allows other sockets to bind() to this
port, unless there is an active listening socket bound to the port already. This
enables you to get around those "Address already in use" error messages when you
try to restart your server after a crash.
|
SO_BROADCAST
|
Allows UDP datagram (SOCK_DGRAM)
sockets to send and recieve packets sent to and from the broadcast address. Does
nothing--NOTHING!!--to TCP stream sockets! Hahaha!
|
As for the parameter optval, it's usually a pointer to an
int indicating the value in question. For booleans, zero is false, and
non-zero is true. And that's an absolute fact, unless it's different on your
system. If there is no parameter to be passed, optval can be
NULL.
The final parameter, optlen, is filled out for you by
getsockopt() and you have to specify it for getsockopt(),
where it will probably be sizeof(int).
Warning: on some systems (notably Sun and Windows), the option can be
a char instead of an int, and is set to, for example, a
character value of '1' instead of an int value of
1. Again, check your own man pages for more info with
"man setsockopt" and "man 7
socket"!
- Return Value
-
Returns zero on success, or -1 on error (and errno
will be set accordingly.)
- Example
-
int optval; int optlen; char *optval2;
// set SO_REUSEADDR on a socket to true (1): optval = 1; setsockopt(s1, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
// bind a socket to a device name (might not work on all systems): optval2 = "eth1"; // 4 bytes long, so 4, below: setsockopt(s2, SOL_SOCKET, SO_BINDTODEVICE, optval2, 4);
// see if the SO_BROADCAST flag is set: getsockopt(s3, SOL_SOCKET, SO_BROADCAST, &optval, &optlen); if (optval != 0) { print("SO_BROADCAST enabled on s3!
"); }
|
- See Also
-
fcntl()
Send data out over a socket
- Prototypes
-
#include <sys/types.h> #include
<sys/socket.h>
ssize_t send(int s, const void *buf, size_t
len, int flags);
ssize_t sendto(int s, const void *buf, size_t
len, int flags, const struct sockaddr
*to, socklen_t tolen);
- Description
-
These functions send data to a socket. Generally speaking, send() is
used for TCP SOCK_STREAM connected sockets, and
sendto() is used for UDP SOCK_DGRAM unconnected
datagram sockets. With the unconnected sockets, you must specify the destination
of a packet each time you send one, and that's why the last parameters of
sendto() define where the packet is going.
With both send() and sendto(), the parameter
s is the socket, buf is a pointer to the data
you want to send, len is the number of bytes you want to send,
and flags allows you to specify more information about how the
data is to be sent. Set flags to zero if you want it to be
"normal" data. Here are some of the commonly used flags, but check your local
send() man pages for more details:
|
MSG_OOB |
Send as "out of band" data. TCP supports this, and it's a way to tell the
receiving system that this data has a higher priority than the normal data. The
receiver will recieve the signal SIGURG and it can then recieve
this data without first recieving all the rest of the normal data in the
queue. |
|
MSG_DONTROUTE |
Don't send this data over a router, just keep it local. |
|
MSG_DONTWAIT |
If send() would block because outbound traffic is clogged, have it
return EAGAIN. This is like a "enable non-blocking just for this
send." See the section on blocking for more
details. |
|
MSG_NOSIGNAL |
If you send() to a remote host which is no longer
recv()ing, you'll typically get the signal SIGPIPE.
Adding this flag prevents that signal from being
raised. |
- Return Value
-
Returns the number of bytes actually sent, or -1 on error
(and errno will be set accordingly.) Note that the number of bytes
actually sent might be less than the number you asked it to send! See the
section on handling partial send()s for a helper
function to get around this.
Also, if the socket has been closed by either side, the process calling
send() will get the signal SIGPIPE. (Unless
send() was called with the MSG_NOSIGNAL
flag.)
- Example
-
int spatula_count = 3490; char *secret_message = "The Cheese is in The Toaster";
int stream_socket, dgram_socket; struct sockaddr_in dest; int temp;
// first with TCP stream sockets: stream_socket = socket(PF_INET, SOCK_STREAM, 0); . . . // convert to network byte order temp = htonl(spatula_count); // send data normally: send(stream_socket, &temp, sizeof(temp), 0);
// send secret message out of band: send(stream_socket, secret_message, strlen(secret_message)+1, MSG_OOB);
// now with UDP datagram sockets: dgram_socket = socket(PF_INET, SOCK_DGRAM, 0); . . . // build destination dest.sin_family = AF_INET; inet_aton("10.0.0.1", &dest.sin_addr); dest.sin_port = htons(2223);
// send secret message normally: sendto(dgram_socket, secret_message, strlen(secret_message)+1, 0, (struct sockaddr*)&dest, sizeof(dest));
|
- See Also
-
recv(), recvfrom()
Stop further sends and recieves on a socket
- Prototypes
-
#include <sys/socket.h>
int shutdown(int s, int how);
- Description
-
That's it! I've had it! No more send()s are allowed on this socket,
but I still want to recv() data on it! Or vice-versa! How can I do
this?
When you close() a socket descriptor, it closes both sides of the
socket for reading and writing, and frees the socket descriptor. If you just
want to close one side or the other, you can use this shutdown()
call.
As for parameters, s is obviously the socket you want to
perform this action on, and what action that is can be specified with the
how paramter. How can be SHUT_RD to prevent
further recv()s, SHUT_WR to prohibit further
send()s, or SHUT_RDWR to do both.
Note that shutdown() doesn't free up the socket descriptor, so you
still have to eventually close() the socket even if it has been fully
shut down.
This is a rarely used system call.
- Return Value
-
Returns zero on success, or -1 on error (and errno
will be set accordingly.)
- Example
-
int s = socket(PF_INET, SOCK_STREAM, 0);
// ...do some send()s and stuff in here...
// and now that we're done, don't allow any more sends()s: shutdown(s, SHUT_RD);
|
- See Also
-
close()
Allocate a socket descriptor
- Prototypes
-
#include <sys/types.h> #include
<sys/socket.h>
int socket(int domain, int type, int protocol);
- Description
-
Returns a new socket descriptor that you can use to do sockety things with.
This is generally the first call in the whopping process of writing a socket
program, and you can use the result for subsequent calls to listen(),
bind(), accept(), or a variety of other functions.
|
domain |
domain describes what kind of socket you're interested in.
This can, believe me, be a wide variety of things, but since this is a socket
guide, it's going to be PF_INET for you. And, correspondingly,
when you load up your struct sockaddr_in to use with this socket,
you're going to set the sin_family field to AF_INET
(Also of interest is PF_INET6 if you're going to be doing
IPv6 stuff. If you don't know what that is, don't worry about
it...yet.) |
type
|
Also, the type parameter can be a
number of things, but you'll probably be setting it to either
SOCK_STREAM for reliable TCP sockets (send(),
recv()) or SOCK_DGRAM for unreliable fast UDP sockets
(sendto(), recvfrom().)
(Another interesting socket type is SOCK_RAW which can be
used to construct packets by hand. It's pretty cool.) |
protocol
|
Finally, the protocol parameter
tells which protocol to use with a certain socket type. Like I've already said,
for instance, SOCK_STREAM uses TCP. Fortunately for you, when
using SOCK_STREAM or SOCK_DGRAM, you can just
set the protocol to 0, and it'll use the proper protocol automatically.
Otherwise, you can use getprotobyname() to look up the proper protocol
number.
|
- Return Value
-
The new socket descriptor to be used in subsequent calls, or
-1 on error (and errno will be set
accordingly.)
- Example
-
int s1, s2;
s1 = socket(PF_INET, SOCK_STREAM, 0); s2 = socket(PF_INET, SOCK_DGRAM, 0);
if (s1 == -1) { perror("socket"); }
|
- See Also
-
accept(), bind(), listen()
Structures for handling internet addresses
- Prototypes
-
#include <netinet/in.h>
struct sockaddr_in { short sin_family; // e.g. AF_INET unsigned short sin_port; // e.g. htons(3490) struct in_addr sin_addr; // see struct in_addr, below char sin_zero[8]; // zero this if you want to };
struct in_addr { unsigned long s_addr; // load with inet_aton() };
|
- Description
-
These are the basic structures for all syscalls and functions that deal with
internet addresses. In memory, the struct sockaddr_in is the same size
as struct sockaddr, and you can freely cast the pointer of one type to
the other without any harm, except the possible end of the universe.
Just kidding on that end-of-the-universe thing...if the universe does end
when you cast a struct sockaddr_in* to a struct sockaddr*, I
promise you it's pure coincidence and you shouldn't even worry about it.
So, with that in mind, remember that whenever a function says it takes a
struct sockaddr* you can cast your struct sockaddr_in* to that
type with ease and safety.
There's also this sin_zero field which some people claim must be set
to zero. Other people don't claim anything about it (the Linux documentation
doesn't even mention it at all), and setting it to zero doesn't seem to be
actually necessary. So, if you feel like it, set it to zero using
memset().
Now, that struct in_addr is a weird beast on different systems.
Sometimes it's a crazy union with all kinds of #defines and
other nonsense. But what you should do is only use the s_addr
field in this structure, because many systems only implement that one.
With IPv4 (what basically everyone in 2005 still uses), the struct
s_addr is a 4-byte number that represents one digit in an IP address per
byte. (You won't ever see an IP address with a number in it greater than
255.)
- Example
-
struct sockaddr_in myaddr; int s;
myaddr.sin_family = AF_INET; myaddr.sin_port = htons(3490); inet_aton("63.161.169.137", &myaddr.sin_addr.s_addr);
s = socket(PF_INET, SOCK_STREAM, 0); bind(s, (struct sockaddr*)myaddr, sizeof(myaddr));
|
- See Also
-
accept(), bind(), connect(), inet_aton(), inet_ntoa()
You've come this far, and now you're screaming for more! Where else can you
go to learn more about all this stuff?
For old-school actual hold-it-in-your-hand pulp paper books, try some of the
following excellent guides. Note the prominent Amazon.com logo. What all this
shameless commercialism means is that I basically get a kickback (Amazon.com
store credit, actually) for selling these books through this guide. So if you're
going to order one of these books anyway, why not send me a special thank you by
starting your spree from one of the links, below.
Besides, more books for me might ultimately lead to more guides for you.
;-)
Unix Network Programming, volumes 1-2 by W. Richard Stevens. Published
by Prentice Hall. ISBNs for volumes 1-2: 013490012X,
0130810819.
Internetworking with TCP/IP, volumes I-III by Douglas E. Comer and
David L. Stevens. Published by Prentice Hall. ISBNs for volumes I, II, and III:
0130183806,
0139738436,
0138487146.
TCP/IP Illustrated, volumes 1-3 by W. Richard Stevens and Gary R.
Wright. Published by Addison Wesley. ISBNs for volumes 1, 2, and 3: 0201633469,
020163354X,
0201634953.
TCP/IP Network Administration by Craig Hunt. Published by O'Reilly
& Associates, Inc. ISBN 1565923227.
Advanced Programming in the UNIX Environment by W. Richard Stevens.
Published by Addison Wesley. ISBN 0201563177.
Using C on the UNIX System by David A. Curry. Published by O'Reilly
& Associates, Inc. ISBN 0937175234. Out of print.
On the web:
BSD Sockets: A Quick And
Dirty Primer (has other great Unix system programming info, too!)
The Unix Socket
FAQ
Client-Server
Computing
Intro to
TCP/IP
Another
Different Intro to TCP/IP
TCP/IP
FAQ
The Winsock FAQ
RFCs--the real dirt:
RFC-768--The
User Datagram Protocol (UDP)
RFC-791--The
Internet Protocol (IP)
RFC-793--The
Transmission Control Protocol (TCP)
RFC-854--The
Telnet Protocol
RFC-951--The
Bootstrap Protocol (BOOTP)
RFC-1350--The
Trivial File Transfer Protocol (TFTP)
|
|