select() 함수가 감이 오지 않습니다.
글쓴이: hitman7 / 작성시간: 월, 2006/05/15 - 10:29오후
항상 기본...
아니 기초적인것만 물어보게 되어 부끄럽기 한이 없네요.
select() 가 감이 잡히질 않네요.
우선 목적은 서버에 접속한 클라이언트의 비정상적인 해제를 잡아내고자 합니다.
main() { ... listen(); while(1) { makethread(...,socket); } } thread(...,socket) { fd_set read; // 배열을 선언합니다. struct timeval timeout; // 타임아웃을 위해 선언합니다. int state; // select()의 리턴값을 위한것입니다. FD_ZERO(&read); // 배열을 초기화 합니다. FD_SET(socket,&read) // 배열에 소켓을 연결합니다. while(1) { timeout.tv_sec=5; timeout.tv_usec=0; state=select(1,&read,NULL,NULL,&timeout) // 살필 파일디스크립터가 1개이고 { // read에 변화는 있습니다.(클라이언트가 case -1: // 접속하자마 데이터(str)을 전송. printf("error\n"); break; case 0: printf("timeout\n"); break; default: printf("read\n"); break; } } }
제가 생각할때는 read가 나와야 할것 같은데요.
5초 간격으로 timeout만 출력이 됩니다.
책을 덜읽어서 일까요? 감이 안잡히네요.
좋은 글이나 설명을 부탁 드려도 될지요?
Forums:
첫번째 파라메터가 틀렸습니다.
FD_SET 호출에서 사용한 fd 값중 최대값 + 1을 첫번째 파라메터를 사용해야 합니다.
--
간디가 말한 우리를 파괴시키는 7가지 요소
첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스
이익추구를 위해서라면..
다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치
---------
간디가 말한 우리를 파괴시키는 7가지 요소
첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스
이익추구를 위해서라면..
다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치
일반적으로는 그렇게 알고 있습니다만.
함수 원형을 살펴보니. select 에서 모니터링 해고자 하는 디스크립터의 숫자로 되어 있어 위와 같이 사용하였습니다.
또한 최초의 접속이 4번 소켓을 사용하기 때문에(1-표준입력,2-표준출력,3-표준에러) 4, (또는 5, 또는 더 큰수)를 사용하였을때에도 마찬가지 현상입니다.
답변에 감사드립니다.
far and hard way
1. socket을 변수로
1. socket을 변수로 사용하는 것은 아니됩니다. 컴파일러가 socket(...)인지 socket인지 헷갈리면 미안하지 않겠습니까?
socket => sock 등으로 변경
* 아울러 read 도 좀 미안해 보이는데 ㅎㅎ 음 readSet?
* 미안하면 나중에 좋은 결과를 얻기 어렵습니다.
2. select의 첫번째 파라메터는 감시하고자 하는 최고 큰 fd의 값(0과 양의 정수) 에 1을 더한 값입니다. 그래서 흔히, max_descriptor+1로 그 값을 유지하고는 합니다만, 쓰레드로 코딩한 경우(예를들어 연결당 1개 쓰레드라면), 해당 쓰레드에서 값을 검토하기 위해서 파라메터의 결정은 넘겨받은 소켓+1이 되겠지요.
select(1,&readSet,NULL,NULL,&timeout)
==> select(sock+1,&readSet,NULL,NULL,&timeout)
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
함수 원형만으로는 의미를 알기 힘듭니다.
문제의 해결과는 관련이 없을듯 싶네요.
select() 의 프로토 타입상으로는 첫번째 아규먼트가 int n 라고만 적혀 있어서
디스크립터의 갯수로 생각하기 쉽지만,
select() 의 맨 페이지상에는 다음과 같이 n 의 의미에 대한 설명이 적혀 있습니다.
select()에서 디스크립터는 마음대로 지정할 수 없습니다.
확인하고자 하는 file descripter가 예컨대 3, 4, 7의 3개 뿐이라고 해도
select()를 이 3개에 대해서만 적용할 수 없습니다.
select()는 0, 1, 2, 3, 4, 5, 6, 7 전부에 대해서 대기하도록 할 수밖에 없습니다.
descripter 숫자라는 것은 그런 의미로 보아야 합니다.
원하는 몇몇 descripter에 대해서만 대기하도록 하려는 경우에는 poll()을 이용하면 됩니다.
쩝..
timeout라고 나오는 것은 진짜 timeout이어서가 아니고 select가 정상적으로 실행이 되었다는 결과값입니다. 검사를 하시려면 FD_ISSET()으로 하셔야죠.. man select를 해 보시기 바랍니다.
-----<꼬릿말 절취선 시작>-----
춥다,... 동전사절, 지폐환영.
복 받으실 거야요~
-----<꼬릿말 절취선 끝>-----
-----[꼬릿말 절취선 시작]-----
삽질전에 먼저 구글신께 기도하자.
-----[꼬릿말 절취선 끝]-----
답변에 감사드립니다.
mach님
실제 변수명은 그리 미안하게 하지 않았답니다..^^;
kslee80님, Trace님
첫번째 파라메터를 확실히 알수 있게 되었습니다. 감사합니다.
wfellow님
역시 가장 자세한 것은 메뉴얼이라는 사실은 알고 있습니다만.. 잘 안되어서요...:)
FD_ISSET을 이리저리 써보고 있습니다.
뭐랄까 제목대로 감이 잘 안온달까요??
FD_ZERO를 어느 블럭에 넣어야 할까...등등(머릿속에 딱 와 닿지를 않네요...)
이것저것 해보고 있는데.
일단 골은 클라이언트쪽의 비정상 적인 네트워크 단절(케이블을 뽑는다든가..정전이라던가)을 서버쪽에서 알기 위한 방법을 구상중에 이런 문제가 발생 했습니다.
다시한번...간단한 쪽코드라도 부탁드릴수 없을까요?
far and hard way
1) 의미없는 데이터를
1) 의미없는 데이터를 주고 받으면서, 비정상적인 연결단절만을 감지하고 싶은가요?
2) 클라이언트와의 의미있는 데이터를 주고 받으면서(서비스를 수행하며), 연결단절을 알고 싶은가요?
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
SO_KEEPALIVE 옵션 사용
setsockopt 함수를 사용해보세요.
---
간디가 말한 우리를 파괴시키는 7가지 요소
첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스
이익추구를 위해서라면..
다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치
---------
간디가 말한 우리를 파괴시키는 7가지 요소
첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스
이익추구를 위해서라면..
다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치
물론 의미 있는 데이터 입니다.
mach 님 관심에 감사드립니다.
서버와 클라이언트는 서로 정해진 프로토콜을 통하여 양쪽 머신의 상태를 동일하게 유지 합니다.
그러다가 클라이언트가 네트워크 상황에서 두절되었을때.(클라이언트가 네트워크 상황이 좋지 않습니다.) 이를 서버가 알아야 할 필요성이 생기기때문입니다.(관리자에게 notify해줘야 하거든요...)
아...위의 코드는 어느정도 감이 왔습니다...
감이 오고나서 코드를 본 소감이란.....참 난감하군요..ㅡㅡ;;;
이제 비정상 종료를 어떻게 감지 할것인가가...문제입니다.
far and hard way
* 먼저, select ()는
* 먼저, select ()는 연결종료를 감지하는데 사용하는 것은 아닙니다. 단지, 다수개의 I/O를 동시에 관찰하기 위해 사용하는 것입니다. 즉, select()의 결과는 IO이벤트(읽을 수 있는 상황, 쓸수 있는 상황등)의 발생만을 알리며, 이후 연결종료의 감지는 read/write해봐야 압니다.
1. 연결종료를 감지하는 법
1) read()에서 감지 -- 읽어봐야 안다........
(1) select() 를 사용했는데, 읽을것이 있다고 한다.
(2) 해당 소켓에 read()를 했다. nread = read(sock,....);
(3) 리턴값을 본다. nread == 0
(4) 리턴값이 0이라면 원격지 연결이 단절된 것이다.
* 참고 1-1) 1, 즉, select()는 단일 프로세스에서 다수개 I/O를 관찰하는 경우가 아니면, 생략가능하다. 예를들어, 클라이언트당 서버프로세스 한개 모델이나, 클라이언트당 서버쓰레드 한개 모델등이면서 I/O가 한곳이라면(소켓등) 구지 select()를 사용할 필요가 없다.
2) write() 에서 감지-- 써봐야 안다......
(1) select() 를 사용했는데, 쓸 수 있다고 한다.
(2) 해당 소켓에 write()를 했다. nwrite = write(sock,....);
(3) 리턴값 nread == -1 이면 에러이긴 한데, errno == EPIPE 인지를 한번 더 검사해야 한다.
(4) 위 3에서의 2개 조건을 만족하면 원격지가 연결 단절된 것이다.
* 참고 2-1) 1, 즉, select()는 단일 프로세스에서 다수개 I/O를 관찰하는 경우가 아니면, 생략가능하다. 예를들어, 클라이언트당 서버프로세스 한개 모델이나, 클라이언트당 서버쓰레드 한개 모델등이면서 I/O가 한곳이라면(소켓등) 구지 select()를 사용할 필요가 없다.
* 참고 2-2) SIGPIPE 시그널 핸들러를 적절히, 처리하지 않으면, write()를 호출한 프로세스는 죽는다.
* 참고 2-3) 위 3에서 errno가 EPIPE가 아닌 다른 값이면, 해당 처리를 수행해야 한다. 예를 들어, write()를 호출하는 시점에 임의의 시그널이 발생하면 -1이 리턴되고, 적절한 에러번호가 errno에 세팅될 수 있으며, 이는 에러는 아닌 경우가 많기 때문이다. 이는 모든 블록킹 시스템호출에 적용된다. 블록킹 시스템호출의 사례로는 select(), accept(), connect(), read(), write() 등 많다. 논블록킹 모드로 코딩하는 경우는 다소 차이가 있는데, 언급하지 않겠다.
2. 1로 연결단절을 감지하는게 일반적인 방법이며, 1을 응용하여 보다 정확하게 코딩해야 한다.
1) heartbeat의 사용 : 지정된 시간안에 메시지를 주고 받으며, 지정된 시간동안 메시지가 오지 않으면, 단절된 것으로 본다.
3. 결론적으로 read() write() 에 시간을 응용해서 연결단절을 구현하는게 일반적이다.
========= 부록 ========
* 단일 프로세스로 다수개의 연결을 관리하려면, 당연히 non blocking모드로 코딩해야 합니다. 특정한 한 연결(클라이언트)에 대해 read() 또는 write()수행시 통신상태에 따라 블록될 수 있고, 이는 전체 클라이언트와의 통신에 지연을 초래하게 되기 때문입니다. non blocking모드로 코딩할때는 모든 시스템호출이나 타시스템연동(데이터베이스 서버등)에서도 이를 고려해서 코딩해야 합니다. 소위 블록되지 않게 코딩해야 합니다. 좀 어렵겠지요? 고려사항 많다는...
* 다수 태스크( 멀티쓰레드, 멀티프로세스 , 멀티프로세스+ 멀티쓰레드)로 코딩하는 경우에, 연결당 1개의 태스크(쓰레드 또는 프로세스)를 배정하면 블록킹 시스템호출 및 타시스템연동(데이터베이스 서버등)시 좀 ... 쉽습니다. 고려사항이 많이 줄지요. 쉽다는 얘기....
* 다수 태스크지만, 위의 2가지를 짬뽕으로 한 경우 (예: 멀티프로세스+멀티쓰레드+쓰레드당 다수 연결)에는 조금 더 복잡할 수 있겠습니다.
* 아울러, 쓰레드, 프로세스를 생성할때, 미리 pool을 구성하는 방법도 성능에 조금 도움이 됩니다.
* 큐메카니즘을 구현해서 위의 모델들과 대충 연동하면 보다 쓸만한 서비스 서버가 될 수 있습니다.
* 이런것이 귀찮으면 적절한 미들웨어를 선택해서 사용하도록 합니다.
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
대단히 감사합니다.
mach님 대단히 감사합니다.
이건 조금더 해봐야 하겠는데요.
다른 것들은 바로바로 테스트 해봤었거든요.
사족이라면 select를 이용한것은 검출 그 자체를 위한것보다. 일종의 타이머를 생각해서 사용한 것입니다.
즉 read()에서 블럭이 되어 버리는것을 바라지 않았기 때문에 select를 사용한것이죠
(이런 아이디어가 맞을까요?? 아직 많이 부족합니다. ㅠ,.ㅠ)
우선 위의 답변 만으로도 큰 도움을 받은것 같습니다. 숙제거리를 포함해서 말이죠. :)
far and hard way
* read()에서 블록되지
* read()에서 블록되지 않게 하기 위해 select()등의 이벤트감지를 사용하셔도 무방하겠습니다.
----- 참고 ------
블록킹을 방지하기 위한 고려.
1) 전체 프로그래밍 로직을 non-blocking으로 작성하는 것도 방법입니다.
2) read를 nonblock으로 수행하는 wrapper를 만들어서 사용하는 것도 방법입니다.
nonBlockRead(...){
- fcntl(논블록세팅 파라메터);
- ret = read(...);
- ret에 따른 처리;
- fcntl(블록세팅 파라메터);
}
3) io가 가능할때, 시그널을 발생시키도록 코딩하는 것도 방법입니다.
4) aio_*()를 이용하는 것도 방법이겠습니다.
*고려사항으로는 performance? portability? scalability? 등의 관점에서 주목적을 어디에 둘것인가에 따라 구현이 틀려질 수 있습니다.
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
------------------ P.S. --------------
지식은 오픈해서 검증받아야 산지식이된다고 동네 아저씨가 그러더라.
댓글 달기