TCP Connection timeout 구현 관련

twins99의 이미지

다음 코드는 TCP에 timeout을 걸어주기 위해 구성한 코드인데요,

문제는 꺼져있는 호스트에 접근할 때, 제생각엔 select에서 걸려 timeout이 발생해야 할 것 같은데,

쭉 끝까지 내려가면서 Operation now in progress란 error code를 뱉어내네요

문제점이 무엇이고, 어떻게 해결하면 좋을까요. 혹 제가 잘못 알고 있는건가요?

궁금합니다.

다음은 코드입니다.

P.S. KLDP가 리모델링 되면서 적응을 못하고 있는데요, 코드삽입할때 어떻게 넣어야 하는지요. 쭉 늘어놓으면 보기힘들어서..
P.S.2 검색은 어디서 하나요? 오른쪽 상단에 찾기는 구글 search이던데.. 예전처럼 전체 검색, 혹은 게시판별 검색이 가능한가요? 방법은??

Int32 CNetworkClient::TCPConnect(string strHostName, Int32 nPort, Int32 nTimeoutSec)

{

//Domain Name resolution
string strIPAddress;
if(NameResolution(strHostName, strIPAddress) != NWC_OK){
DBG_E_PRINT("CNetworkClient::TCPConnect-->NameResolution fail\n");
return NWC_TCP_CONNECTION_ERROR;
}

//TCP Connect
Int32 socketFD;
Int32 err;
Int32 saveFlags,ret,back_err;
fd_set fd_w;
struct timeval timeout;
struct sockaddr_in sockAddr;

/*connects to server
*/

socketFD = socket(AF_INET, SOCK_STREAM,0);

memset(&sockAddr,'\0', sizeof(sockAddr));

sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(nPort);
sockAddr.sin_addr.s_addr = inet_addr(strIPAddress.c_str());
// inet_pton(AF_INET, strIpAddress, &sockAddr.sin_addr);

DBGPRINT("CNetworkClient::TCPConnect-->Try to Connect host:%s\n",strHostName.c_str());

saveFlags = fcntl(socketFD, F_GETFL, 0);
if(saveFlags<0)
{
DBG_E_PRINT("CNetworkClient::TCPConnect-->fcntl()1 error\n");
return NWC_TCP_CONNECTION_ERROR;
}
//Set Non Blocking
if(fcntl(socketFD, F_SETFL, saveFlags | O_NONBLOCK)<0)
{
DBG_E_PRINT("CNetworkClient::TCPConnect-->fcntl()2 error\n");
return NWC_TCP_CONNECTION_ERROR;
}
err=connect(socketFD, (struct sockaddr*)&sockAddr, sizeof(sockAddr));
back_err = errno;
DBG_E_PRINT("CNetworkClient::TCPConnect-->%s \n", strerror(errno));

//resotre flags
if(fcntl(socketFD, F_SETFL, saveFlags)<0)
{
DBG_E_PRINT("CNetworkClient::TCPConnect-->fcntl()3 error\n");
return NWC_TCP_CONNECTION_ERROR;
}

/* return unless the connection was successful or the connect is
still in progress. */
if(err<0 && back_err!=EINPROGRESS)
{
DBG_E_PRINT("CNetworkClient::TCPConnect-->connect() error\n");
return NWC_TCP_CONNECTION_ERROR;
}

timeout.tv_sec = (long)nTimeoutSec;
timeout.tv_usec = 0L;

FD_ZERO(&fd_w);
FD_SET(socketFD,&fd_w);

err=select(FD_SETSIZE,NULL,&fd_w,NULL,&timeout);
if(err<0)
{
DBG_E_PRINT("CNetworkClient::TCPConnect-->select() error\n");
return NWC_TCP_CONNECTION_ERROR;
}

/* 0 means it timeout out & no fds changed */
if(err==0)
{
DBGPRINT("CNetworkClient::TCPConnect-->Timeout Occurred\n");
m_tNWCState = NWC_STATE_ERROR_TIMEOUT;
return NWC_TCP_CONNECTION_TIME_OUT;
}

// Get the return code from the connect
socklen_t len=sizeof(ret);
err=getsockopt(socketFD, SOL_SOCKET, SO_ERROR, &ret, &len);
if(err<0)
{
DBG_E_PRINT("CNetworkClient::TCPConnect-->getsockopt() error\n");
return NWC_TCP_CONNECTION_ERROR;
}

// ret=0 means success, otherwise it contains the errno
if(ret)
{
err=ret;
DBG_E_PRINT("CNetworkClient::TCPConnect-->%s \n", strerror(errno));
return NWC_TCP_CONNECTION_ERROR;
}

if(m_nTCPSocketFD !=-1){
// cout<<"Socket:"< close(m_nTCPSocketFD);
}

m_nTCPSocketFD = socketFD;
// cout<<"Port:"< return NWC_OK;

}

{

//Domain Name resolution
string strIPAddress;
if(NameResolution(strHostName, strIPAddress) != NWC_OK){
DBG_E_PRINT("CNetworkClient::TCPConnect-->NameResolution fail\n");
return NWC_TCP_CONNECTION_ERROR;
}

//TCP Connect
Int32 socketFD;
Int32 err;
Int32 saveFlags,ret,back_err;
fd_set fd_w;
struct timeval timeout;
struct sockaddr_in sockAddr;

/*connects to server
*/

socketFD = socket(AF_INET, SOCK_STREAM,0);

memset(&sockAddr,'\0', sizeof(sockAddr));

sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(nPort);
sockAddr.sin_addr.s_addr = inet_addr(strIPAddress.c_str());
// inet_pton(AF_INET, strIpAddress, &sockAddr.sin_addr);

DBGPRINT("CNetworkClient::TCPConnect-->Try to Connect host:%s\n",strHostName.c_str());

saveFlags = fcntl(socketFD, F_GETFL, 0);
if(saveFlags<0)
{
DBG_E_PRINT("CNetworkClient::TCPConnect-->fcntl()1 error\n");
return NWC_TCP_CONNECTION_ERROR;
}
//Set Non Blocking
if(fcntl(socketFD, F_SETFL, saveFlags | O_NONBLOCK)<0)
{
DBG_E_PRINT("CNetworkClient::TCPConnect-->fcntl()2 error\n");
return NWC_TCP_CONNECTION_ERROR;
}
err=connect(socketFD, (struct sockaddr*)&sockAddr, sizeof(sockAddr));
back_err = errno;
DBG_E_PRINT("CNetworkClient::TCPConnect-->%s \n", strerror(errno));

//resotre flags
if(fcntl(socketFD, F_SETFL, saveFlags)<0)
{
DBG_E_PRINT("CNetworkClient::TCPConnect-->fcntl()3 error\n");
return NWC_TCP_CONNECTION_ERROR;
}

/* return unless the connection was successful or the connect is
still in progress. */
if(err<0 && back_err!=EINPROGRESS)
{
DBG_E_PRINT("CNetworkClient::TCPConnect-->connect() error\n");
return NWC_TCP_CONNECTION_ERROR;
}

timeout.tv_sec = (long)nTimeoutSec;
timeout.tv_usec = 0L;

FD_ZERO(&fd_w);
FD_SET(socketFD,&fd_w);

err=select(FD_SETSIZE,NULL,&fd_w,NULL,&timeout);
if(err<0)
{
DBG_E_PRINT("CNetworkClient::TCPConnect-->select() error\n");
return NWC_TCP_CONNECTION_ERROR;
}

/* 0 means it timeout out & no fds changed */
if(err==0)
{
DBGPRINT("CNetworkClient::TCPConnect-->Timeout Occurred\n");
m_tNWCState = NWC_STATE_ERROR_TIMEOUT;
return NWC_TCP_CONNECTION_TIME_OUT;
}

// Get the return code from the connect
socklen_t len=sizeof(ret);
err=getsockopt(socketFD, SOL_SOCKET, SO_ERROR, &ret, &len);
if(err<0)
{
DBG_E_PRINT("CNetworkClient::TCPConnect-->getsockopt() error\n");
return NWC_TCP_CONNECTION_ERROR;
}

// ret=0 means success, otherwise it contains the errno
if(ret)
{
err=ret;
DBG_E_PRINT("CNetworkClient::TCPConnect-->%s \n", strerror(errno));
return NWC_TCP_CONNECTION_ERROR;
}

if(m_nTCPSocketFD !=-1){
// cout<<"Socket:"< close(m_nTCPSocketFD);
}

m_nTCPSocketFD = socketFD;
// cout<<"Port:"< return NWC_OK;

}

mach의 이미지

먼저, connect()라는 시스템호출을 잠시 살펴보면, 응용프로그래머입장에서는 단지 적절한 파라메터를 주어 한번의 호출입니다. 이렇게 적절히 호출하면 상대가 대기하고 있는 경우 연결을 확립하여 리턴하거나, 상대가 대기하지 않거나, 기타 사유로 문제가 되면 에러메시지를 주고 리턴합니다.
연결이 안되는 경우에 대해 고찰하면, 다양한 문제가 있을 수 있는데, 안되면 왜? 안된다 하고, 즉시, 리턴해주면 차라리 좋은데, 너무 오랜 시간동안 connect()를 수행하기 위해 시간을 소모하는 경우에 대한 대처가 없는 경우 문제가 되는 경우가 있습니다. (테스트환경에서는 대체로 잘되는 편이지만) 그것도 가변적으로 말입니다.
소위, 특정 함수(시스템호출 connect())에서 어떤 경우 빠르게, 어떤 경우 느리게, 그때 그때 다른 시간으로 수행되어서 전체 응용프로그램의 behavior를 예측하기 힘든 경우가 나타날 수 있다는 것입니다. (특히, 자동화된 접속 및 처리등에서)
결과적으로, 이를 해결하기 위해서는 해당 호출을 할때, 일정한 시간을 넘지 않고 리턴하도록 인위적인 조작이 필요한데, 이를 위해 시스템호출에 대해 non-blocking 메카니즘을 도입하는 것이 여러 방법중 하나의 방법입니다.

제시한 에러메시지는 아직 연결이(connect, 즉, tcp 3-way handshake가 종결되지 않았음) 되지 않았다는 얘기입니다.
에러라고 간주하기 보다는 다시(루프?) 연결이 확립되었는지를 검사해야 하는 상황으로 봐야합니다. 그러나, 무한히 이를 기다릴 수는 없으므로 타임아웃을 검사해야겠지요.
이러한 내용을 구현하고자 한 시도는 곳곳에 들어 있는데, 배열(?)이 적절하지 않은 듯 합니다.

non blocking connect의 좋은(참고) 구현은 역시나 고 Stevens님의 책에 잘 나와있습니다. 그 책의 소스를 참고하여 만드시면 될 듯합니다. 또한, 이곳에도 여러차례 이슈가 되었으니, 검색해서 찾아보셔도 될듯하고요. 인터넷에서도 어렵지 않게 찾으실것으로 예상됩니다.

------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.

------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.

kuaaan의 이미지

참고로... 이 nonblock소켓을 이용한 connect는 OS에 따라
미묘한 차이가 있습니다. (아직 진행중인지, 실패한건지 판단하는 부분에서...)

google에 "connect_nonb.c"를 검색해보세요.
스티븐스 아저씨의 아름다운 코드를 감상하실수 있습니다.
:)

----------------------------------------------
한번뿐인 인생....
미친듯이 살아보자!
----------------------------------------------

----------------------------------------------
한번뿐인 인생....
미친듯이 살아보자!
----------------------------------------------

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.