TCP - Socket, Unix Domain Socket, Raw Socket

0

tcp

목록 보기
2/2

Socket

socket은 특정 host에 있는 application이 kernel로부터 transport layer의 기능을 도움받기 위해 사용하는 인터페이스이다. 이를 위해서 application은 host에 자신을 식별할 수 있는 식별자로 port를 전달한다.

이를 기반으로 socket은 host의 IP와 application의 port를 식별자로 만들어진다.

일반적으로 TCP 연결을 위한 socket은 Transport layer의 기능인 연결 지향 전송, 패킷 도착 보장, 순서 보장, 에러 검출, 흐름 제어, 혼잡 제어 등의 기능을 kernel로부터 도움을 받을 수 있다.

https://velog.velcdn.com/images/cyw320712/post/848ea521-bbe2-4fdf-952d-41a2cff0b891/image.png

trasnport layer에는 tcp뿐만 아니라, UDP도 있는데 udp역시도 socket을 기반으로 통신을 한다. 다만, tcp처럼 연결 지향이 아니기 때문에 packet들을 가지고 순서를 맞추지 않는다. 또한, 신뢰성있는 전송이 보장되지 않는다. 이러한 추가 기능들은 application계층에서 알아서 해주어야 하는 것이다. 즉, tcp에서 전달되는 packet은 mtu(1460byte)로 쪼개져서 전달된 다음 transport layer에서 재조립을 해주는 반면에, udp에서는 전달되는 packet은 mtu로 쪼개지지만 transport layer에서 재조립되지 않는다. 바로 application로 전달될 뿐이다.

tcp에서 전달하는 data를 일반적으로 stream이라고 한다. 따라서 tcp socket을 stream socket이라고도 한다. 반면에 udp에서 전달하는 data를 datagram이라고 한다. 따라서 udp socket을 datagram socket이라고도 한다.

UDS(unix domain socket)

unix domain socket은 서로 다른 subnet을 가진 host들 간의 통신을 위해 사용하는 것이 아니라, host 내의 application들 간의 통신을 위해 사용된다. 즉, process 간 통신에 사용되는 것으로 IPC socket이라고도 불린다.

unix domain socket은 file을 하나 만들고 이 file을 socket으로 사용하여 kernel의 transport layer 계층과 같은 서비스를 제공받을 수 있다. 즉, unix domain socket으로 tcp와 udp처럼의 data를 송수신 할 수 있는데, 이 기능을 제공받기 위해서 실제 transport layer를 거치는 것이 아니라, kernel이 대신 제공해준다. 마치 transport layer를 거치는 것과 같은 모습을 띄게하는 것이다.

https://inside.java/images/blog/jep380.jpg

그림의 왼쪽은 같은 host 내에 서로 다른 application 끼리의 loopback 통신을 보여준다. 이는 localhost를 통한 통신이 어떻게 동작하는 지를 보여준다. transport layer와 network layer를 모두 거치기 때문에 port와 ip의 영향을 받는다. 그러나, link layer에는 NIC까지만 지나기 때문에 실제로 외부로 traffic이 흘러가는 것이 아니라, 내부 host의 network stack만 거친다.

반면에 오른쪽은 unix domain socket의 모습으로 transport layer, network layer 등 network stack을 거치지 않는다. 그럼에도 unix domain socket 역시도 stream, datagram을 선택하여 TCP, UDP를 지원할 수 있는데, 이는 kernel에서 transport layer와 같은 기능을 대신 제공해주기 때문에 가능한 것이다.

또한, unix domain socket의 경우 ip, port를 통한 socket이 아니라 file기반의 socket 통신을 한다고 했다. 이 역시도 unix domain socket이 transport layer와 network layer를 거치지 않기 때문에 가능한 것이다. 가령 docker의 경우 /run/docker.sock file을 만들어 UDS를 사용한다.

unix domain socket을 사용하는 이유는 localhost로 연결하는 방법보다 IPC로 process 간 연결에 있어서 훨씬 더 빠르다는 이득을 볼 수 있기 때문이다. 실제로 haproxy도 unix domain socket을 사용하여 내부적인 라우팅을 실행하도록 한다.

Raw socket

raw socket은 kernel로부터 transport layer의 도움을 받지 않고, IP packet을 그대로를 가져오는 인터페이스이다. 즉, 네트워크의 원시 패킷을 그대로 주고 받을 수 있도록하는 네트워크 소켓이다. 이는 kernel의 TCP/IP 처리 시스템을 무시하고 특정 사용자 application에 packet을 전송한다는 특징이 있다.

물론 Network layer의 IP 기능을 제공 받을 수도 있지만, 대부분 link layer에서 frame을 그대로 받아 IP, TCP 네트워크 처리를 application 자체에서 동작하도록 한다.

raw socket은 주로 packet snippet과 capture, TCP 직접 구현 등에 사용되며 주로 직접 새로운 프로토콜을 만들 때 사용한다. unix domain socket 처럼 IPC 용은 아니며, 실제로 서로 다른 subnet에서의 host들 끼리의 통신에도 사용된다. 가장 대표적인 오픈소스로는 tcpcopy로 raw socket으로 tcp 동작을 따라하도록 만들어, 기존의 tcp 데이터를 복사해서 다른 곳에 스트리밍하도록 하는 기능을 제공한다.

https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLJyzE%2FbtsFIjdnl56%2Fbt0J4tZ3V8QkSQ3VEinx10%2Fimg.png

raw socket은 위의 그림과 같이 L2 layer에서 바로 raw socket으로 data를 보내는 것을 알 수 있다. 그러나, 이는 어떻게 raw socket을 만드냐에 따라서 다르다. L2 raw socket을 만들어서 frame 단위로 조작이 가능하고, L3 raw socket을 만들어서 IP단위의 조작을 가능하게 만들 수도 있다.

실제 생성하는 방법은 그닥 어렵지 않은데, socket 코드를 통해 쉽게 만들 수 있다.

sock = socket(AF_INET, SOCK_RAW, PROTOCOL);

SOCK_RAW을 사용하여 socket을 만들면 된다. 이를 통해서 자체적인 protocol 구현도 가능한 것이다.

0개의 댓글

Powered by GraphCDN, the GraphQL CDN