소켓 프로그래밍중 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...
댓글 달기