2009年12月24日 星期四

enalbing connect() to timeout

This is a very useful technique that you should try out while you are starting up a tcp connection.
Instead of "breaking out on error" or being "blocked" at the point of "connect() " when the remote server is temporary unavalible, this function will try to connect in a given period of time.
Code:
void connect_w_to(void) {
int res;
struct sockaddr_in addr;
long arg;
fd_set myset;
struct timeval tv;
int valopt;
socklen_t lon;

// Create socket
soc = socket(AF_INET, SOCK_STREAM, 0);
if (soc < 0) {
fprintf(stderr, "Error creating socket (%d %s)\n", errno, strerror(errno));
exit(0);
}

addr.sin_family = AF_INET;
addr.sin_port = htons(2000);
addr.sin_addr.s_addr = inet_addr("192.168.0.1");

// Set non-blocking
if( (arg = fcntl(soc, F_GETFL, NULL)) < 0) {
fprintf(stderr, "Error fcntl(..., F_GETFL) (%s)\n", strerror(errno));
exit(0);
}
arg |= O_NONBLOCK;
if( fcntl(soc, F_SETFL, arg) < 0) {
fprintf(stderr, "Error fcntl(..., F_SETFL) (%s)\n", strerror(errno));
exit(0);
}
// Trying to connect with timeout
res = connect(soc, (struct sockaddr *)&addr, sizeof(addr));
if (res < 0) {
if (errno == EINPROGRESS) {
fprintf(stderr, "EINPROGRESS in connect() - selecting\n");
do {
tv.tv_sec = 15;
tv.tv_usec = 0;
FD_ZERO(&myset);
FD_SET(soc, &myset);
res = select(soc+1, NULL, &myset, NULL, &tv);
if (res < 0 && errno != EINTR) {
fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
exit(0);
}
else if (res > 0) {
// Socket selected for write
lon = sizeof(int);
if (getsockopt(soc, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon) < 0) {
fprintf(stderr, "Error in getsockopt() %d - %s\n", errno, strerror(errno));
exit(0);
}
// Check the value returned...
if (valopt) {
fprintf(stderr, "Error in delayed connection() %d - %s\n", valopt, strerror(valopt)
);
exit(0);
}
break;
}
else {
fprintf(stderr, "Timeout in select() - Cancelling!\n");
exit(0);
}
} while (1);
}
else {
fprintf(stderr, "Error connecting %d - %s\n", errno, strerror(errno));
exit(0);
}
}
// Set to blocking mode again...
if( (arg = fcntl(soc, F_GETFL, NULL)) < 0) {
fprintf(stderr, "Error fcntl(..., F_GETFL) (%s)\n", strerror(errno));
exit(0);
}
arg &= (~O_NONBLOCK);
if( fcntl(soc, F_SETFL, arg) < 0) {
fprintf(stderr, "Error fcntl(..., F_SETFL) (%s)\n", strerror(errno));
exit(0);
}
// I hope that is all
}

沒有留言: