Dev/C, C++
socket connect timeout
newtype
2007. 5. 29. 17:34
connection 할때 timeout 처리에 관해 찾아 보는 중.
nonblocking socket을 이용한 Rechard stevens의 소스가 있더군요.
예전에 포스팅 한 http socket client 에 적용하면서 windows 버전으로도 만들어 봤습니다.
int CHttpSocket::connect_nonb(int sockfd, const struct sockaddr *saptr, socklen_t salen, struct timeval tval)
{
int flags, n, error;
socklen_t len;
fd_set rset, wset;
#ifdef WIN32
int nonblocking =1;
ioctlsocket(sockfd, FIONBIO, (unsigned long*) &nonblocking);
#else
flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
#endif
error = 0;
if ( (n = connect(sockfd, (struct sockaddr *) saptr, salen)) < 0)
{
#ifdef WIN32
errno = WSAGetLastError();
#endif
if (errno != EINPROGRESS && errno!= EWOULDBLOCK)
{
return(-1);
}
}
/* Do whatever we want while the connect is taking place. */
if (n == 0)
goto done; /* connect completed immediately */
FD_ZERO(&rset);
FD_SET(sockfd, &rset);
wset = rset;
if ( (n = select(sockfd+1, &rset, &wset, NULL,
((tval.tv_sec>0) || (tval.tv_usec>0))? &tval : NULL)) == 0)
{
close(sockfd); /* timeout */
errno = ETIMEDOUT;
return(-1);
}
if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset))
{
#ifndef WIN32
len = sizeof(error);
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
return(-1); /* Solaris pending error */
#endif
} else
return(-1); //err_quit("select error: sockfd not set");
done:
#ifdef WIN32
nonblocking =0;
ioctlsocket(sockfd, FIONBIO, (unsigned long*) &nonblocking);
#else
fcntl(sockfd, F_SETFL, flags); /* restore file status flags */
#endif
if (error) {
close(sockfd); /* just in case */
errno = error;
return(-1);
}
return(0);
}
{
int flags, n, error;
socklen_t len;
fd_set rset, wset;
#ifdef WIN32
int nonblocking =1;
ioctlsocket(sockfd, FIONBIO, (unsigned long*) &nonblocking);
#else
flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
#endif
error = 0;
if ( (n = connect(sockfd, (struct sockaddr *) saptr, salen)) < 0)
{
#ifdef WIN32
errno = WSAGetLastError();
#endif
if (errno != EINPROGRESS && errno!= EWOULDBLOCK)
{
return(-1);
}
}
/* Do whatever we want while the connect is taking place. */
if (n == 0)
goto done; /* connect completed immediately */
FD_ZERO(&rset);
FD_SET(sockfd, &rset);
wset = rset;
if ( (n = select(sockfd+1, &rset, &wset, NULL,
((tval.tv_sec>0) || (tval.tv_usec>0))? &tval : NULL)) == 0)
{
close(sockfd); /* timeout */
errno = ETIMEDOUT;
return(-1);
}
if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset))
{
#ifndef WIN32
len = sizeof(error);
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
return(-1); /* Solaris pending error */
#endif
} else
return(-1); //err_quit("select error: sockfd not set");
done:
#ifdef WIN32
nonblocking =0;
ioctlsocket(sockfd, FIONBIO, (unsigned long*) &nonblocking);
#else
fcntl(sockfd, F_SETFL, flags); /* restore file status flags */
#endif
if (error) {
close(sockfd); /* just in case */
errno = error;
return(-1);
}
return(0);
}
반응형