티스토리 뷰
유디피 소켓 사용의 단점
1.TCP의 ack & 재전송 방식을 사용하지않는 비연결지향형 프로토콜인 UDP에서는 lost datagram이 생겼을때 프로그램상에서 별도의 처리를 해주어야 한다는 문제가 있음 ( 전송된 데이터가 유실됨 )
클라이언트에서 서버로 sendto 한다음에 recvfrom에서 블럭되어 있는데 보낸 패킷이 lost되었을 경우 recvfrom에서 무한히 블럭되어 있을 가능성이 있다. 그렇기 때문에 이것을 해결하기 위해 select 또는 sigalram시그널핸들러를 통해서 타이머를 세팅해주어야 한다.
2.상대방이 보내온 데이터가 정말로 내가 원하는 상대방인지 별도의 장치를 사용하지 않으면 알 수 가없다.
-> 서버쪽에서는 이런 문제가 상관이 없다. 클라이언트의 경우에는 udp소켓을 사용해서 내가 원하는 서버에 request했을때 내가 원하는 서버로부터 reply를 받았는지 보장을 받아야 한다.
내가 reply를 받은 ip가 sendto할때 사용한 ip와 같은지 확인을 해야한다. 서버의 경우에 여러개의 네트워크 인터페이스가 존재할 수 있다(아이피주소를 여러개 가질수있다.) 그렇기 때문에 내가 sendto한 아이피와 recvfrom한 아이피가 같은 서버의 경우에도 달라질수 있다는 얘기이다.
내가 원하는 상대방과만 통신을 하고 싶을때 별도의 장치가 필요하다.
3.sendto로 서버에 데이터를 보냈는데 서버 프로세스가 존재하지 않는 상황
->클라이언트는 recvfrom에서 무한히 블락될 가능성이 있다.tcp처럼 서버 커널이 리셋메세지를 되돌려주지 않는다.
-> 비동기적 에러라고 한다. asynchronous error
이런 문제를 해결하기 위해서 udp connect라는것이 나중에 유닉스에 구현되었다.
tcp 소켓을 만들고 나서 connect로 연결요청 하는것과 마찬가지로 udp소켓에 대해서도 적용이 가능하다.
유디피 소켓에 대해서 connect를 한다는 것은
(보통 클라이언트 프로그램에서 유디피 소켓을 만들고 connect를 호출하므로)
클라이언트 커널에게 비동기적 에러가 발생한 경우 그 에러를 발생시켜달라고 요청하는 셈이다.
7번째 줄에서 유디피 소켓애 대해서 커넥트를 호출하는것은
커널이 해당 유디피 소켓에 대해서 비동기적 에러가 생겼을 경우에 그 에러가 생겼다는 것을 유저 프로세스가 시스템 콜을 호출한 경우에 -1을 리턴하게끔 해달라고 커널에게 요청하는 것이다.
7번 줄에서 커넥티드 유디피 소켓을 만들게 되면 실제로는 아무 패킷도 서버로 전송하지 않고 클라이언트 커널에서 서버 유디피 소켓에 대한 정보만 가지고 있게 된다.
그런뒤, 9번째 줄에서 write를 하게 될 경우 서버 유디피 소켓에 udp 세그먼트를 보낸다. 그런데, 서버의 커널은 아이피 주소가 자신임을 확인하고 나서 포트번호를 확인해서 그 포트에 대한 소켓이 존재하지 않는다는것을 알고 난뒤 EHOSTUNREACH라는 ICMP메시지를 상대방(클라이언트) 커널에 되돌려 준다. TCP의 경우에는 이런 경우에 리셋 메세지를 되돌려 주었었지만 udp는 연결 지향이 아니기 때문에 방식이 조금 다르다.
클라이언트가 위의 프로그램을 실행시켜서 커넥티드 유디피 소켓을 통해 write를해서 서버에 패킷을 보내고, 서버에 그런 소켓이 존재하지 않아서 ICMP를 되돌려주고 이 ICMP메시지를 받은 클라이언트는 read블락을 깨고, -1을 리턴하며 errno에 EHOSTUNREACH를 세팅한다.
이것을 통해서 비동기적에러(클라이언트 프로세스는 살아있지만 서버 프로세스는 죽어있는상태때문에 발생함)는 적절히 해결할 수 있게 되었다.
비 동기적 에러를 해결하기 위해서 유디피 소켓에 대한 connect시스템콜 호출을 허락하게 끔 한것이다.
connect시스템콜을 호출하지 않고 그냥 udp소켓을 통해서 서버와 데이터를 주고 받는 경우 비동기적에러가 발생한 경우 클라이언트의 커널이 ICMP메시지를 받더라도 유저 프로세스에게 에러를 발생시키지 않는다.그렇기 때문에 read에서 무한히 블럭 됨.
서버에 네트워크 인터페이스가 여러개 있어서 A,B,C,D라는 아이피 주소를 갖는다고 해보자.
이때 클라이언트가 연결된 유디피 소켓을 통해서 서버에 데이터를 보내고 read에서 블럭되어 있을텐데 서버가 A라는 주소로 클라이언트의 패킷을 받고나서 B라는 주소로 다시 되돌려 주었다고 했을때 그 패킷을 받은 클라이언트는 아이피 주소가 다른 놈에게서 왔다고 판단하여 그 패킷을 버려버린다.(discard)
->이것을 해결하기 위해서 나중에 아이피주소를 사용하지 않고 URL을 사용한다.
tcp에서는 데이터를 보낼때 헤더에 recv buffer사이즈를 포함해서 보내기 때문에 flow control을 하게 되지만
udp는 그런 시스템이 존재하지 않는다.
유디피의 경우에는 수십키로 바이트 정도 크기의 수신버퍼가 존재하는데, 그것보다 더 큰 용량이 도착하게 되면 그냥 패킷을 버려버리고 아무일도 하지 않는다. 이문제에 대한 또 다른 해결책이 필요하다.
유디피 소켓의 경우에는 수신 버퍼 사이즈의 한계가 있음에도 flow control을 하지 않기 때문에 갑자기 많은 양의 데이터가 수신되어 버퍼에 모두 그 패킷을 담을수 없는 일이 자주 발생할 수 있다. 그렇기 때문에 응용프로그램상에서 이 문제를 적절히 해결해 주어야 한다.
'컴퓨터 공학과 졸업 > 소켓 프로그래밍' 카테고리의 다른 글
SCTP Protocol 1 (0) | 2017.12.02 |
---|---|
UDP와TCP 소켓을 모두 사용하는 서버(select를 poll로 바꿔보기,중요) (0) | 2017.11.29 |
소켓 옵션 (0) | 2017.11.14 |
poll시스템콜 (0) | 2017.11.13 |
개선된 서버 프로그램 (0) | 2017.11.11 |
- Total
- Today
- Yesterday
- storybook
- Next.js
- typescript
- type alias
- reactdom
- atomic design
- return type
- Polyfill
- react hooks
- await
- props
- useRef
- async
- design system
- rendering scope
- es6
- computed
- hydrate
- Action
- state
- reflow
- webpack
- react
- server side rendering
- promise
- javascript
- mobx
- reducer
- useEffect
- Babel
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |