티스토리 뷰

첫번째 경우. 서버가 Crashing된 경우


이 경우 클라이언트는 서버가 Crashing 됬는지 안됬는지 바로는 알 수 가없다.

그 서버에 가장 가까이 붙어있는 라우터가 그 서버가 Crashing됬다는걸 제일 빨리 알게 되고 라우팅 테이블이 인접 라우터들에게 전송되면서 결국에는 전세계 라우터들에게 전파되기 때문에 클라이언트에게 가장 가까운 라우터가 결국에는 그 ip주소로는 못간다고 알게 되기 때문에 언젠가는 알게된다. 근데, 이런 방법은 알게 되기 까지 시간이 상당히 걸린다.


따라서, 우리 프로그램의 경우에서 바로 알 수 있는 방법이 있다.

Fgets한다음에 Write를 하고 나서 read에서 블락되어 있을텐데 이때 상대방으로 부터 아무 반응이 없을 것이고(FIN도 안오고 RESET도 안옴) 

그렇기 때문에 계속 재전송하게 된다. 12번 정도(9분정도) 재전송 하고 나서 클라이언트 커널은 타임아웃을 발생시킨다. 그리고 더이상 상대방은 없는것으로 친다. 클라이언트 커널이 타임아웃을 발생시키게 되면 그때 클라이언트 프로세스는 read에서 블락 되어 있을텐데 read시스템콜을 -1리턴 시켜 버린다. errno는 ETIMEDOUT을 설정한다. 


if(read()==-1 && errno=ETIMEDOUT){

//적절한 타임아웃 처리.

}


아무리 오지에 있는 기계가 망가져도 전세계에 그 라우팅 정보가 퍼지는데 요즘은 이틀이면 가능하다. read 블락 된 상태에서 타임 아웃 되기 전에, 클라이언트가 보낸 패킷이 라우터를 타고 목적지 까지 가는 와중에 그 ip로는 갈수 없다는 라우팅 정보를 가지고 있는 라우터를 통하게 될 경우 그 라우터 에서 클라이언트에게 ICMP메세지를 돌려주게 된다. 

이런 경우에 read는 -1을 리턴시키고 EHOSTUNREACH 또는 ENETUNREACH를 errno에 세팅하게 된다.


두번째 경우. 서버가 Crashing되고 다시 Rebooting된 경우

(서버가 다운 됬다가 다시 켜진 경우)


연결이 설정 된걸 확인 하기 위해서 서버와 에코를 아래와 같이 한번씩 주고 받는다.

hi there //from client

hi there //from server

그리고 나서 갑자기 서버가 다운 되고 다시 켜졌다고 해보자. 이때 서버는 그전에 설정 되었던 소켓에 대한 정보가 다 날라갔을 것이다. 따라서

클라이언트가 Fgets로 키보드 입력을 받고 write를 해서 서버에 데이터를 보냈을때, 서버는 그런 소켓이 없다고 인지하기 때문에 클라이언트에게 Reset메세지를 돌려준다. 근데 이때 클라이언트는 read에서 블락 되어 있을것이다. 

그렇기 때문에 read시스템콜은 -1을 리턴시키고 errno에 ECONNRESET을 설정한다.


위의 두 경우들은 드문 케이스긴 하지만 발생할수 있는 경우이므로 잘 처리해 주어야 한다.

여태까지 다룬 에러 케이스는 Connection Aborted(클라이언트가 3way핸드쉐이킹 마지막 ack를 보내고 바로 RST를 서버에게 보낸경우)

ETIMEDOUT,EHOSTUNREACH,ENETUNREACH,ECONNRESET등을 배웠다.


숫자를 네트워크로 주고 받기


지금까지는 클라이언트와 서버 사이에 데이터를 주고 받는 경우를 살펴 보았다. 근데 텍스트(스트링)이 왔다갔다 하는것만 다루었지만

만약 Binary를 보내는 경우엔 신경 써 줘야 할것이 있다. 13이라는 숫자를 클라이언트가 보내건 서버가 보내건 서로에게 전송하는 경우를 생각해보자. 그 값을 바이너리 그상태로 보내면 절대 안된다. 왜냐면 컴퓨터의 씨피유마다 리틀 엔디안 빅엔디안이 다르기 때문이다. 따라서 바이너리 그 상태로 보내면 안되고 13을 문자열로 변환해서 보내고 받을때도 13이라는 문자열을 다시 숫자로 변환해서 처리해야 한다.


만약 data structure를 보내야 하는 경우엔?

그 구조체 내부에 여러개의 int,float,double이 있는 경우에 일일이 다 변경 해야 하나?

-> 그 구조체를 XDR(External Date Representation)포맷으로 변경해서 보내면 된다.



첫번째 경우를 실험 하는 방법은 다음과 같다.

1. 리눅스 서버에 클라이언트 프로그램을 실행시킨다.

2. 내 컴퓨터에서 서버 프로그램을 실행시킨다. 

3. 내 컴퓨터를 서버로 사용하기 위해서는 공유기를 사용하기 때문에 포트포워딩을 해야한다.

4. 하고 나서 외부에서 내 컴퓨터로 접근 가능하게 되면 연결이 설정됬다는것을 보여주기 위해서 서로 데이터(hi there)를 한번씩 주고 받고나서

내 컴퓨터(서버프로그램실행중)의 인터넷을 끊는다.

5. 리눅스 서버(클라이언트)에서 패킷을 다시 보내보면 한 20분정도 뒤에 타임 아웃 되는것을 확인 할 수 있다.


두번째 경우를 실험 하는 방법은 다음과 같다.

다른 과정은 위와 거의 비슷하다.

다른 부분은 내 컴퓨터(서버)의 인터넷을 끊고 나서 서버 프로그램을 종료시키고 다시 서버 프로그램을 실행시킨다음 클라이언트(리눅스 서버)에서 패킷을 보내보는 것이다.

그럴 경우 서버가 갖고 있던 TCP연결 정보를 다 잃어 버린 상태가 되므로 리셋 메세지를 클라이언트에게 돌려주게 된다.

리드 블럭 되어있던 클라이언트는 -1을 리턴시키고 CONNRESET을 errno에 설정한다.




댓글
최근에 올라온 글
최근에 달린 댓글
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
글 보관함