티스토리 뷰

우리가 여태까지 만들었던 concurrent서버에서는 서버의 커널에 incomplete큐와 complete큐가 클라이언트의 요청정보를 담는다고 했었다.

그런데, 서버프로그램의 경우에 3-way핸드쉐이킹을 끝마친 클라이언트의 요청은 complete큐에 담기게 된다.

매우 바쁜 서버의 경우에 이 큐가 꽉차게 될경우가 매우 빈번히 생길수 있고 그렇게 될 경우 클라이언트 입장에서는 반응성이 매우 떨어진다. 


서버와 클라이언트가 통신중이라고 가정하자.

이때, 클라이언트가 SYN 서버가 SYN+ACK 다시 클라이언트가 ACK를 보냈을때 ACK를 받은 서버는 incomplete 큐에 있던 클라이언트의 연결 요청 정보를 complete큐에 옮겨 담게 된다.

 그러고 나서 서버프로그램에서 complete큐에 있는 그 요청 정보를 accept()시스템콜 반환 하면서 커넥트 소켓을 만들것이다. 

근데 이때

(complete큐에 클라이언트의 요청 정보가 맨 뒤에 삽입이 되고 서버에서 complete큐에서 요청정보들을

 하나하나씩 accept시스템콜 리턴시키는중인 상황


클라이언트가 프로세스를 종료해버렸다(탭을 없애버렸다던지) 클라이언트의 커널은 그 클라이언트 프로세스가 

사용했었던 모든 파일들의 reference count를 1씩 깎는다. 또한 이미 연결이 되어 있는 상태였다면 클라이언트 프로세스를 종료 시켰을때 FIN메세지를 보내겠지만, 지금은 연결이 안된 상태(연결도중끊김)기 때문에 RESET메세지를 서버에게 보내게 된다.


상황을 다시한번 정리하자면 클라이언트가 3way 핸드쉐이킹 과정에서 보낸 마지막 ACK를 서버가 수신해서 incomplete 큐에 있던

그 클라이언트의 연결요청정보를 complete큐에 옮기고(매우 바쁜 서버이기 때문에 complete큐가 거의 꽉차있고, 맨 뒤에 삽입됨)

큐의 맨앞에서부터 accept()시스템콜을 리턴 시키면서 커넥트 소켓을 차례차례 만드는 중이다.


근데 방금전에 보낸 클라이언트 A의 요청정보가 complete 큐의 맨뒤에서 기다리며 자기 차례가 와서 

accept가 리턴되어 커넥트 소켓이 만들어지게끔 하고 있다.

 근데 이 와중에 클라이언트 프로세스가 종료되어서(x버튼클릭) 클라이언트로부터 RST메세지가 서버에게 도달했다.


POSIX의 경우에는 이런 경우에 그 RST를 보낸 클라이언트의 연결 요청 정보를 accept()시스템콜 리턴 할때

-1을 반환하고 CONNECTION ABORTED라는 에러메세지를 errno에 설정하도록 되어 있다.

우리의 경우에 이런 에러가 발생한 경우 클라이언트가 연결이 최종적으로 성공되기 전에 종료를 시킨경우로 인식할수 있기 때문에

다시 accept() 시스템콜을 호출하게 끔 해서 그 다음 complete큐에서 대기중인 다른 클라이언트의 연결요청을 수락할수 있도록 하면 된다.



만약 이런 상황에서 -1이 리턴 됬는데 우리가 이 상황을 제대로 처리해주지 않을 경우 발생하는 문제

1.서버 부모 프로세스에서 fork()를 호출해서 서버 자식 프로세스가 만들어짐.

2.원래는 fork를 호출하기 전에 서버 부모 프로세스에서 커넥트 소켓과 리슨소켓이 두개 동시에 있는 상태임.

3.근데 이 상황에서는 리슨소켓만 존재한채로 fork가 실행되서 자식 프로세스는 리슨소켓만 가짐

4. 우리 프로그램에서는 서버 부모프로세스는 커넥트 소켓을 닫고 서버 자식 프로세스는 리슨 소켓을 닫게 끔 되어있음

5.현재 자식 프로세스에서 리슨소켓만 있는 상태인데 리슨 소켓을 닫기 때문에 아무일도 하지 않는 프로세스가 여러개가 생성

6. 의미없는 프로세스가 계속 생성되기 때문에 문제가 발생한다.


우리가 짠 클라이언트 프로그램에서 파일은 stdin(키보드),stdout(모니터),커넥트 소켓이 존재하는데 

여기서 read 블락 될 수있는 파일은 stdin과 커넥트 소켓이다.

실제로는 우리가 설계해놓은 프로그램 순서대로 동작하지 않는 경우가 발생할 수 있다.


Fgets() -> Write() -> Read() -> Fputs() 순서대로 클라이언트 프로그램이 짜여져 있다.

다음 상황을 가정해보자.

에코 concurrent 클라이언트,서버 프로그램에서 클라이언트가 야호를 보내고 서버는 야호를 받아서 다시 에코해서

클라이언트에게 야호를 보낸 상황이다 이때 다시 for문이 돌아서 클라이언트 프로세스의 Fgets에서 블락된 상태로 사용자의 키보드 입력을 기다리고 있다. 이때 서버에서 무슨일이 생겨서 갑자기 서버 프로세스가 종료되었다고 해보자.


그럼 서버의 커널은 FIN메세지를 클라이언트에게 보낼것이고, 그 FIN메세지는 클라이언트의 커널이 받을것이다.

그 다음에 클라이언트 프로세스가 실행돼서 Fgets()를 호출하고 Write()한다음에 Read()할때 FIN메세지를 읽게 될것이다.


Write()를 했을때 서버 프로세스는 존재 하지 않으므로 서버 커널이 Reset메세지를 커널에게 돌려준다.

그다음 Read()가 호출되면 FIN을 읽기 때문에 EOF이벤트가 발생해서 read시스템콜이 0을 리턴하게 된다.

이건 우리가 프로그램을 잘 못 짠것이다.


다시 말해서 read블락될수 있는 시스템콜을 2개 이상 가지고 있으며 이 시스템콜의 순서가 정해진대로 동작해야 한다

할때 클라이언트건 서버건 이때 거의 무조건 문제가 발생한다.









'컴퓨터 공학과 졸업 > 소켓 프로그래밍' 카테고리의 다른 글

비정상적인 서버 종료  (0) 2017.11.07
SIGPIPE 시그널  (0) 2017.11.07
wait waitpid 좀비프로세스  (1) 2017.10.19
시그널과 좀비 프로세스  (0) 2017.10.18
Concurrent 서버 2  (0) 2017.10.17
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함