소켓 프로그래밍중 accept() 에러
글쓴이: peccavi / 작성시간: 화, 2005/02/01 - 5:17오후
몇일간 끙끙 앓다가.. 코드 일부를 올려봅니다..
스티븐스 책에 있는 poll() 루틴을 랩핑한건데요
accept() 부분에서 가끔
WARNING : accept failed, connfd = -1, errno = 9
이 메세지를 찍으며 무한루프를 도네요..
구조적으로 어느 부분이 잘못되었는지 지적좀 부탁드립니다..
아무리 봐도 안나오네요.. ㅠㅠ
코드를 짧게 올리려고 중간중간 관계 없는 부분은 삭제했습니다.
먼저 메인 루틴 부분입니다.
void *thread_recvmsg(void *arg)
{
int sid;
ePollResult ret;
while(1)
{
ret = Server.CheckPoll();
if( ret == POLL_NEWUSER )
{
UserConnected(Server.nNewSID, Server.nNewSockfd);
continue;
}
else if( ret == POLL_USERFULL )
{
SysLog.Putf("WARNING : User full!!\n");
Server.Close(Server.nNewSockfd);
}
else if( ret == POLL_ERROR ) continue;
for( sid=1 ; sid<=Server.nMaxi ; sid++ )
{
ret = Server.ReadPoll(sid);
if( ret == POLL_CONTINUE )
{
continue;
}
else if( ret == POLL_RECVMSG )
{
RecvQ.PutQ(Server.nRecvSocket, Server.sRecvBuffer, Server.nRecvSize);
}
else if( ret == POLL_DISCONNECT )
{
UserDisconnected(Server.nRecvSocket);
Server.Close(Server.nRecvSocket);
Server.Client[sid].fd = -1;
}
else if( ret == POLL_ERROR )
{
printf("poll error\n");
}
else
{
printf("unknown poll error\n");
}
if( --Server.nReady <= 0 || ret == POLL_BREAK )
{
break;
}
}
}
return arg;
}
CheckPoll() 부분입니다.
ePollResult CSocket::CheckPoll()
{
int sid, connfd;
bool bTempFlag;
nReady = poll(Client, nMaxi + 1, POLL_TIMEOUT);
if( nReady < 0 )
{
SysLog.Putf("WARNING : poll() fail, nReady = %d, errno = %d, port = %d\n", nReady, errno, nPort);
return POLL_ERROR;
}
if( Client[0].revents & POLLIN )
{
nClilen = sizeof(Cliaddr);
connfd = accept(nListenfd, (struct sockaddr *)&Cliaddr, &nClilen);
printf("accept result = %d, errno = %d\n", connfd, errno);
if( connfd < 0 )
{
SysLog.Putf("WARNING : accept() failed, connfd = %d, errno = %d, port = %d\n", connfd, errno, nPort);
return POLL_ERROR; // 이부분에서 무한루프가 돕니다..
}
SetSocketNonblocking(connfd);
if( bDisableNagle == true ) SetSocketDisableNagle(connfd);
bTempFlag = false;
nNewSockfd = connfd;
for( sid=1 ; sid<nMaxUser ; sid++ )
{
if( Client[sid].fd < 0 )
{
bTempFlag = true;
Client[sid].fd = connfd;
Client[sid].events = POLLIN;
nNewSID = sid;
break;
}
} // for
if( bTempFlag == false )
{
SysLog.Putf("WARNING : user full at port %d\n", nPort);
return POLL_USERFULL;
}
if( sid > nMaxi ) nMaxi = sid;
if( --nReady <= 0 ) return POLL_NEWUSER;
return POLL_BREAK;
}
return POLL_BREAK;
}
ReadPoll() 부분입니다.
ePollResult CSocket::ReadPoll(int sid)
{
int sockfd;
if( (sockfd=Client[sid].fd) < 0 ) return POLL_CONTINUE;
if( Client[sid].revents & ( POLLIN | POLLERR ) )
{
pthread_mutex_lock(&mutex_lock_socket);
nRecvSize = read(sockfd, sRecvBuffer, MAXLINE);
pthread_mutex_unlock(&mutex_lock_socket);
nRecvSocket = sockfd;
if( nRecvSize < 0 )
{
return POLL_DISCONNECT;
}
else if( nRecvSize == 0 )
{
return POLL_DISCONNECT;
}
else
{
sRecvBuffer[nRecvSize] = '\0';
return POLL_RECVMSG;
}
}
return POLL_CONTINUE;
}
Forums:


Re: 소켓 프로그래밍중 accept() 에러
Client[0].fd 에 들어가 있는 값이 nListenfd 맞나요?
그리고 nListenfd 에 들어가 있는 값이 리슨 소켓번호 맞나요?
에러 발생시에 한번 찍어 보세요.
네.. Client[0].fd 에 nListenfd, 리슨소켓값 맞습니다
네.. Client[0].fd 에 nListenfd, 리슨소켓값 맞습니다.
서버를 시작하면 한동안은 아무 이상 없이 작동 되구요..
구조적으로 분기가 좀 이상한 부분이 있긴 하지만, accept()를 실패할 요인은 없는거 같은데 당최 모르겠네요..
답변 감사드립니다..
----
jai guru deva om...
errno 9에 대응하는 상수를/usr/include/asm-ge
errno 9에 대응하는 상수를
/usr/include/asm-generic/errno-base.h를 보니까
아래 줄이 있군요.
errno 9면 EBADF이므로
File Descriptor/Socket Descriptor와 관련된 문제임은 확실합니다
정상작동할때와 그렇지 않을때의 Socket Descriptor 값을
찍는 식으로 추적해봐야 할 것 같습니다. 메모리 잘못
접근하는걸로도 얼마든지 발생할 수 있는 문제니
Written By the Black Knight of Destruction
결론적으로, accept()에서 EBADF이 났다는건 리슨소켓이 올바른
결론적으로, accept()에서 EBADF이 났다는건 리슨소켓이 올바른 fd가 아니라는 얘긴데,,, 뭔가 다른 요인에 의해 nListenfd값이 변형될 수 있는 상황을 찾아봐야겠네요..
에구..
답변주신분들 감사드립니다..
----
jai guru deva om...
댓글 달기