본문 바로가기
기타

소켓 통신 기본 개념 정리

by KBS 2022. 5. 19.
728x90

소켓 통신

소켓이란 두 프로그램이 서로 데이터를 주고 받을 수 있고 양쪽(두 프로그램 모두)에 생성되는 통신단자입니다.

소켓통신이란 서버와 클라이언트 양방향 연결이 이루어지는 통신으로, 클라이언트도 서버로 요청을 보낼 수 있고 서버도 클라이언트로 요청을 보낼 수 있는 통신으로 다음과 같은 특성을 지닙니다.

클라이언트와 서버 양쪽에서 데이터 전달을 하는 방식의 양방향 통신

보통 스트리밍이나 실시간 채팅 등 실시간으로 데이터를 주고 받아야 하는 경우 Connection을 자주 맺고 끊는 HTTP 통신보다 소켓 통신이 적합니다. 소켓 통신은 계속해서 Connection을 들고 있기 때문에 HTTP 통신에 비해 많은 리소스가 소모됩니다.

소켓 실행 흐름

소켓 흐름표

서버의 입장

1. socket()

소켓 통신을 위해 가장 먼저 해야 할 일은 서버 소켓을 생성하는 것입니다. 최초 소켓이 만들어지는 시점에는 어떠한 "연결 대상"에 대한 정보도 들어 있지 않습니다. 껍데기 뿐인 소켓이 하나 만들어진 것 뿐이죠. 연결 대상 을 지정하고 연결 요청을 전달하기 위해서는, 여기서 생성한 소켓을 사용하여 connect() API를 호출해야 합니다.

2. bind()

일반적으로 socket은 고정된 포트번호를 사용합니다. 각 소켓은 시스템이 관리하는 포트(0 ~ 65535) 중 하나를 사용하게 됩니다. 만약 사용하는 포트가 다른 소켓이 사용하는 포트와 일치하다면 어떻게 될까요? 예를들어 100포트가 중복이 되었다고 가정해 봅시다. 네트워크에서 100번 포트에 데이터를 수신할대 어떤 포트에게 전달해 주어야 하는지 알수가 없어 오류가 나게 됩니다.

이러한 일을 방지하기위해 운영체제는 내부적으로 포트번호와 소켓연결정보를 가지고 있습니다. bind()는 사용하고자 하는 포트번호를 운영체제에 알리고 해당 포트를 이미 사용중이라면 에러를 던지게 됩니다.

3. listen()

서버 소켓에 포트번호를 bind 하고나면, 이제 우리는 클라이언트 소켓의 연결 요청을 받을 준비가 되었습니다. 이제는 클라이언트에서 요청이 올때까지 기다려야 하는데 이것이 바로 listen()입니다. 

서버소켓의 포트에 클라이언트의 연결요청이 알맞게 찾아오면 대기상태를 종료하게 됩니다. 대기상태가 종료되는것은 요청이 성공했거나, 실패했거나(close() 혹은 오류) 입니다. 

클라이언트의 요청은 큐(Queue)에 쌓이게 되는데, 이 시점에선 아직 대기상태 입니다. 큐에서 요청을 하나 꺼내어 온뒤 연결을 완료하기위해 Accept()를 호출해야 완료가 됩니다.

4. accept()

앞선 listen 에서 요청이 성공적이라고 해서 클라이언트와의 연결이 모두 완료된 것은 아닙니다. 실질적인 소켓 연결을 담당하는 것은 accept()입니다.

accept()는 요청을 받아들여 소켓간 연결을 수립하는 일을 합니다. 하지만 여기서 이제 우리는 지금까지 함께해왔던 서버 소켓을 보내주어야 합니다. 앞서 bind()와 listen()을 거쳐온 우리의 서버 소켓에 클라이언트 요청을 맵핑하지 않고, accept()에서 새롭게 만든 소켓에 맵핑을 하여 연결을 완료시키게 됩니다. 아쉽게도 서버 소켓은 이제 다른 요청을 받으려 다시 대기(listen)상태에 가거나 닫는(close())일만 남았습니다.

5. send() / recv()

연결은 이제 성공적으로 끝이 났습니다. 연결된 소켓을 통해 데이터를 보내는 경우에는 send(), 받는 경우에는 recv() API를 사용합니다. send()와 recv()를 통해 데이터의 송수신이 이루어지고 해당 과정이 완료가 되면 close()를 통해 소켓을 닫습니다.

6. close()

더이상 데이터 송수신이 필요없게 된다면 소켓을 닫기 위해 close()를 사용합니다. close()를 사용한 소켓은 더 이상 유효한 소켓이 아니기 때문에 다시 데이터 송수신을 할 수 없게 됩니다. 만약, 데이터 송수신을 다시 하고 싶다면 새로운 소켓을 만들어 앞선 과정을 다시 밟아야 합니다.

그런데 서버 소켓에서는 close()의 대상이 하나만 있는 것이 아니라는 것에 주의해야 합니다. 최초 socket() API를 통해 생성한 서버 소켓에 더해, accpet() API 호출에 의해 생성된 소켓도 관리해야한다는 의미입니다.

클라이언트의 입장

1. socket()

서버 소켓과 마찬가지로 클라이언트 소켓을 생성합니다. 과정과 내용은 서버의 socket()과 동일합니다.

2. connect()

connect() API는 IP주소와 포트 번호로 대상을 식별하고 식별된 대상 서버 소켓으로 연결 요청을 보냅니다. connect() API는 블럭(Block) 방식으로 동작합니다. 즉, 연결 요청에 대한 결과(성공, 거절, 시간 초과 등)가 결정되기 전에는 connect()의 실행이 끝나지 않습니다. 

3. send() / recv()

연결이 성공적으로 완료가 되었다면 서버와 마찬가지로 데이터를 정송할 때는 send(), 데이터를 수신할때는 recv()를 사용하게 됩니다.

4. close()

서버의 입장과 같은 맥락이지만 클라이언트 소켓은 단 하나의 소켓만 관리하면 됩니다. 

728x90

'기타' 카테고리의 다른 글

[webRTC, React, TypeScript] 간단하게 1:1 화상 통화를 만들어보자  (1) 2022.05.27
MQTT  (0) 2022.05.19
동영상 압축, MP4 와 H.264  (0) 2022.05.19
웹어셈블리 (WASM)?  (0) 2022.05.18
Web RTC?  (0) 2022.05.18

댓글