A: If you don't have them on your system already, you probably don't need them. Check the manual for your particular platform. If you're building for Windows, you only need to #include <winsock.h>.
A: You have to use setsockopt() with the SO_REUSEADDR option on the listening socket. Check out the section on bind() and the section on select() for an example.
A: Use the netstat. Check the man page for full details, but you should get some good output just typing:
$ netstat |
The only trick is determining which socket is associated with which program. :-)
A: You can tell because recv() will return 0.
A: First, delete Windows and install Linux or BSD. };-). No, actually, just see the section on building for Windows in the introduction.
A: The linker errors happen because Sun boxes don't automatically compile in the socket libraries. See the section on building for Solaris/SunOS in the introduction for an example of how to do this.
A: Signals tend to cause blocked system calls to return -1 with errno set to EINTR. When you set up a signal handler with sigaction(), you can set the flag SA_RESTART, which is supposed to restart the system call after it was interrupted.
Naturally, this doesn't always work.
My favorite solution to this involves a goto statement. You know this irritates your professors to no end, so go for it!
select_restart: if ((err = select(fdmax+1, &readfds, NULL, NULL, NULL)) == -1) { if (errno == EINTR) { // some signal just interrupted us, so restart goto select_restart; } // handle the real error here: perror("select"); } |
Sure, you don't need to use goto in this case; you can use other structures to control it. But I think the goto statement is actually cleaner.
A: Use select()! It allows you to specify a timeout parameter for socket descriptors that you're looking to read from. Or, you could wrap the entire functionality in a single function, like this:
#include <unistd.h> #include <sys/time.h> #include <sys/types.h> #include <sys/socket.h> int recvtimeout(int s, char *buf, int len, int timeout) { fd_set fds; int n; struct timeval tv; // set up the file descriptor set FD_ZERO(&fds); FD_SET(s, &fds); // set up the struct timeval for the timeout tv.tv_sec = timeout; tv.tv_usec = 0; // wait until timeout or data received n = select(s+1, &fds, NULL, NULL, &tv); if (n == 0) return -2; // timeout! if (n == -1) return -1; // error // data must be here, so do a normal recv() return recv(s, buf, len, 0); } // Sample call to recvtimeout(): . . n = recvtimeout(s, buf, sizeof(buf), 10); // 10 second timeout if (n == -1) { // error occurred perror("recvtimeout"); } else if (n == -2) { // timeout occurred } else { // got some data in buf } . . |
Notice that recvtimeout() returns -2 in case of a timeout. Why not return 0? Well, if you recall, a return value of 0 on a call to recv() means that the remote side closed the connection. So that return value is already spoken for, and -1 means "error", so I chose -2 as my timeout indicator.