select 에 대해.....
글쓴이: 살자 / 작성시간: 월, 2003/04/07 - 8:29오후
int main(int argc,char *argv[]) { int i,listenfd,connfd,sockfd; int maxfd,maxi; int nready,clilen,client[FD_SETSIZE]; fd_set rset,allset; struct sockaddr_in cliaddr,servaddr; if((listenfd = socket(AF_INET,SOCK_STREAM,0)) < 0) { perror("Can not open socket"); exit(1); } bzero((char *)&servaddr,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORT); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)) < 0) { perror("error bind"); exit(1); } if(listen(listenfd,WQUEUE) < 0) { perror("error listen"); exit(1); } maxfd = listenfd; maxi = -1; for(i = 0;i < FD_SETSIZE;i++) client[i] = -1; FD_ZERO(&allset); FD_SET(listenfd,&allset); for(;;) { printf("for\n"); rset = allset; /*allset에서 설정된 bit를 rset으로 넘겨준다. printf("for1\n"); if((nready = select(maxfd + 1,&rset,NULL,NULL,NULL)) < 0) { perror("error select"); exit(1); } if(FD_ISSET(listenfd,&rset)) { clilen = sizeof(cliaddr); if((connfd = accept(listenfd,(struct sockaddr *)&cliaddr,&clilen)) < 0) { perror("error accept"); exit(1); } printf("connection clientt.... \n"); for(i = 0;i < FD_SETSIZE;i++) { if(client[i] < 0) { client[i] = connfd; break; } } if(i == FD_SETSIZE) perror("too many clients"); FD_SET(connfd,&allset); if(connfd > maxfd) maxfd = connfd; if(i > maxi) maxi = i; if(--nready <= 0) continue; } /*---- client communication----*/ for(i = 0;i <= maxi;i++) { if((sockfd = client[i]) < 0) continue; if(FD_ISSET(sockfd,&rset)) { close(sockfd); FD_CLR(sockfd,&allset); client[i] = -1; if(--nready <= 0) break; } } } }
코드 중간에 디버깅을위해 for와 for1을 printf를 사용하여 체크해 봤는데..
for만 나오고 for1은 나오지 않습니다.
rset = allset 이 문장에서 문제가있는것 같은데...
어떤문제인지 모르겠습니다.
책보구 했는데 안돼네여...
몇시간째 보구 있는데 도저히 모르겠습니다.
제발 도와주세요...
Forums:
FD_ZERO(&allset); FD_SET(liste
FD_ZERO(&allset);
FD_SET(listenfd,&allset);
이 문장은 for 문 안에 넣어야 할듯.
printf(); 다음에 꼭 flush(stdout); 하시고...
memcpy(&rset,&allset,sizeof(allset)); 으로 넣어보세요.
내 자식들도 나처럼 !!
윗분... for 안에 FD... 넣을 필요는 없다고 생각합니다.
윗분... for 안에 FD... 넣을 필요는 없다고 생각합니다.
그리고 윗분 말씀처럼 printf 다음엔 꼭 flush 해주세요.
아니면 printf 대신 fprintf(stderr, "...."); 를 써보시던지요.
_____________________________
언제나 맑고픈 샘이가...
http://purewell.biz
왜 그런가요?
저도 전에 이런 비슷한 오류가 있었습니다.
위와 비슷하게 allset을 for문 밖에서 셋팅했는데,
select를 한번 실행하고 2번째부터 쓰레기가 들어가더군요.
select에서는 readset으로 받아서 allset이 변할 수가 없는데...
왜 for 안에서 선언을 해야하나요?
어차피 밖에서 값을 한번 셋팅하고 바꾸지않으면, 안에서 계속할 필요는 없지않나요?
fd_set은 구조체일텐데...
fd_set은 구조체로 알고 있습니다만,
rset = allset;
이라는 문장이 C에서 성립하나요?
rset = allset; 문장에서 블락이 되어다기 보다는
rset에 잘못된값이 들어가서 select에서 블락이 된것 같습니다.
memcpy등을 이용해서 rset에 allset 비트를 카피해보세요.
Re: fd_set은 구조체일텐데...
구조체가 아니구 array로 되어있습니다.
고로 rset = allset은 성립합니다.
Re: select 에 대해.....
윗분 말씀대로 select에서 block된것 같군요.
client로 접속하신것 맞나요?
telnet <IP> <PORT> 로 테스트해보세요..
for1이 그때 나올것 같군요.. 강제로 나오게 하시려면 fflush를 해보세요.
근데.. 접속되두... 위의 코드처럼 클라이언트를 대접하면...
고객(client)들이 별로 안좋아할것 같은데요? :P
(접속만 하면 강제로 짤라버리니까요...FIN FIN FIN FIN....)
Re: 왜 그런가요?
FD_SET(connfd,&allset);
select는 return될때 읽을수 있는 descriptor set 을 업데이트하기 때문에 그런걸로 알고있습니다. i.e. 매번 바뀜.
그렇기때문에 allset은 우리가 관심있는 descriptor set(listenfd [+ connfd...]) 들을 bookkeeping해주는 역활을 하고 있습니다.. rset은 매번 업데이트가 되어서 우리가 원래 관심있는 descriptor에 대한 정보가 없어지기 때문입니다..
추신: UNP chapt. 6에 잘 나와있습니다. (원래 코드와 함께요)
...
답변 감사합니다 ^^
그런데 제 질문은 allset은 값이 안변하니까 for문에서 allset을 계속 셋팅할 필요가 없지않냐는겁니다.
select문에서도 rset으로 읽기가능한 fd를 받아오면... 각 fd를 처리하고 다시 select문에 들어가기전에 rset = allset 으로 셋팅해주잔아요.
그럼 allset은 값이 안변하는데... for문에서 계속 값을 초기화할 필요는 없을것 같거든요.
문제는... 이 에러를 못잡아서 다른분께 맞겼는데... allset없이 rset을 for문안에서 계속 초기화하는걸로 해결하더군요.
제 생각으로는 실제사용하는 rset과 초기화용 allset을 선언하고 for문밖에서 한번 선언된 allset을 계속 사용하면 될거같은데... 이게 안되는 이유가 무엇인지 정말 이해가 안되네요.
Re: ...
위에도 썼지만....
FD_SET(connfd,&allset);
allset은 변합니다!! 새로 접속한 녀석의 connfd를 allset에다가 FD_SET해주는겁니다... 연결된 녀석들하고 계속 통신을 해야하니까요...
UNP 6장에 자세하게 설명 되어있습니다~~ ^- ^
^^
o cjy1126 님의 동료분이 잡으셨다는 문제의 코드가 이 코드였나요?
제가 볼때는 코드를 칠 때 타이핑 실수인 듯 합니다. 아니었다면 죄송.
/*allset에서 설정된 bit를 rset으로 넘겨준다.
다음에 닫는 */ 이 없어서 쭈욱 아래에 있는
/*---- client communication----*/
이 나올 때까지가 모두 주석으로 처리된 것이죠. for1 을 찍는 문장은
당연히 주석 안에 들어가 있으니까 출력이 안되는 것이고요.
o rset = allset
이 문장은 가능합니다. array이기 때문에 가능한 것이 아니라 structure이기 때문에 가능합니다. 실제로 fd_set 의 타입 정의를 보시면 (Solaris 7 기준) structure안에 하나의 필드를 가지고 있고, 그 필드가 array입니다. 만일 structure를 없애고 그냥 array로만 되어 있다면 위 문장은 오류입니다.
o allset 을 for loop안에서 매번 초기화?
이 코드상에서 쓰인 allset은 for loop안에서 매번 초기화될 필요 없습니다. select()가 주어진 fdset 을 변경시키는 것 맞습니다. 그러나 코드상에서는 allset을 select의 인자로 주는것이 아니라 rset 에 할당한 후에 rset을 인자로 주기 때문에 문제되지 않습니다. rset은 매번 select할 때마다 값이 파괴될 수 있으므로 for loop 안에서 초기화해 주셔야 합니다. for loop 안에 가끔 allset이 보이는 것은 말씀하신 대로 client가 connect를 했을 때 해당 socket을 추가하고, 현재 코드에서는 socket에서 I/O가 발생하자마자 끊게 되어 있는데, 이 경우에 해당 socket을 fd_set에서 제외해 주기 위해서 입니다.
:lol: 님께서 하신 부분에 약간의 착오로 인하여 문제가 발생되
:lol:
님께서 하신 부분에 약간의 착오로 인하여 문제가 발생되었네요.
아래의 source 를 참조하십시요.
printf("for\n");
rset = allset; /*allset에서 설정된 bit를 rset으로 넘겨준다.
printf("for1\n");
if((nready = select(maxfd + 1,&rset,NULL,NULL,NULL)) < 0)
{
---------- 생략 -----------
/*---- client communication----*/
rset = allset; 문장에서 comment를 막으셔야 하는데...
comment 처리를 안하셔서 밑에 있는 "client communication"의
comment 까지 모든 source 가 ... (^_^)
참고로 select 문의 5번째 parameter가 NULL 이면 폭주가 발생할수 있으니
"struct timeval" 을 이용하여 timer 처리 하시구요...
nready 값에 대한 대한 처리도 빠져 있네요...
nready값이 음수면 select error 처리/ 0이면 do nothing 처리
그리고 양수면 FD_ISSET 처리를 하심이 어떨까요 ?
글코, 제가 아는 범위에서는 FD_SET은 for 바깥쪽에 있어도 상관없습니다.
댓글 달기