Skip to content

Latest commit

 

History

History
60 lines (31 loc) · 6.87 KB

socketp.md

File metadata and controls

60 lines (31 loc) · 6.87 KB

Socket Programming

네트워크를 다뤄본다면 소켓이라는 용어는 그리 낯설지만은 않은 용어일 것이다.

소켓은 사전저긍로 구멍, 연결, 콘센트 등의 의미를 갖는데 주로 전기 부품을 규격에 따라 연결할 수 있게 만들어진 구멍 형태의 연결부를 일컫는 다어로 가정에서 흔히 볼 수 있는 콘센트 구멍을 떠올릴 수 있다. 다시 한 번 풀어서 쓰자면 전기를 필요로하는 디바이스 또는 부품들이 전기를 공급받을 수 있도록 전기 공급 인프라 환경에 연결할 수 있게 만들어진 연결부가 소켓이다.

네트워크 프로그래밍에서도 비슷하게 사용되는데 데이터를 송수신할 수 있도록 네트워크 환경에서 연결할 수 있게 추상화된 연결부가 바로 네트워크 소켓이다.

물론 이러한 네트워크 소켓도 명확한 표현은 아니다. 왜냐면 네트워크에 연결하기 위해 프로토콜에 맞게 만들어야 하기 때문에 tcp 소켓, tcp/ip 소켓, udp 소켓 등등 다양하게 불리는데 보통 네 번째 계층인 tcp에서 동작하는 소켓을 주로 사용한다.

소켓은 근데 그냥 간단하게 정규 유닉스 파일 기술자를 이용해 다른 프로그램과 정보 교환을 하는 방법이다. (굉장히 어깨에 힘이 잔뜩 들어간 표현)

유닉스는 모든것이 파일로 이루어져있는데 소켓도 유닉스에서는 파일로 취급한다. 그리고 이런 프로그램들은 입출력을 할때 file descriptor를 것을 통해서 하는데 여기서 파일 디스크립터는 열려진 파일을 의미하는 정수(인덱스) 번호이고 Socket Descriptor라는 것은 소켓을 만들고 얻은 파일 기술자라는 것을 뜻한다.

쉽게 말해 내가 서버랑 소켓 통신을 하고 싶다면 socket()을 통해 생성하고 함수를 호출하면 내부적으로 소켓으로 사용할 파일을 하나 열고 index번호를 리턴해 그 번호로 send() recv()등을 하는거다.

한마디로 네트워크 연결을 파일 레벨에서 추상화한것이 소켓이라고 말할 수 있다.

그래서 만약 무한대로 소켓을 만들면 파일이 부족해져 열지못해 소켓 생성 에러도 날 수 있을 것이다. index는 정수형으로 되어있고 a라는 소켓을 만들고 socket descriptor가 3이라면 b는 4 .. 이렇게 생각하면 된다.


TCP/IP 소켓 프로그래밍

소켓 프로그래밍에서는 소켓으로 네트워크 통신 기능을 구현하기 위해 소켓을 만드는 것, 데이터를 주고받는 절차에 대한 이해가 필요하다. 그리고 운영체제 및 프로그래밍 언어에 종속적으로 제공되는 소켓 api 사용법을 숙지해야한다.

덤으로 케이블 분리로 인한 네트워크 단절, 트래픽 증가에 따른 전송 지연, 시스템 리소스 관리 문제로 인한 에러등 네트워크 환경에서 발생할 수 있는 다양한 예외사항에 대해서도 처리가 필요하기 때문에 소켓 프로그래밍이 초보 개발자에게는 더욱 어럽게 느껴질수밖에 없을 것이다.

TCP/IP 는 간단하게 말하면 IP와 TCP프로토콜을 같이 사용하는 방식이라고 생각하면 되고 ip는 데이터 경로를 제공해주고 tcp가 전송할 데이터들을 매니징한다고 생각하면 편하다. (tcp가 데이터 순서와 같은 데이터 신뢰성을 위한 관리, 연결(3, 4 way hand shake) 흐름제어, 혼잡제어 등등에 관한 다양한 것들을 함.)


client socket, server socket

두 개의 시스템에서 소켓을 통해 connection을 맺기 위해서는 최초 어느 한 곳에서 그 대상이 되는 곳으로 연결 요청을 해야하고 ip port로 해당 번호로 식별되는 대상에게 자신이 데이터 송수신을 위한 네트워크 연결을 수립할 의사가 있음을 알리는 것이다.

그런데 최초 한 곳에서 무작정 연결을 시도한다고 되는 것이 아니고 그 요청이 받아들여지고 커넥션이 만들어질 준비가 되어야만 만들어진다 그렇기에 어떤 연결 요청을 받아들일것인지 미리 시스템에 등록해 수신되어있을때 해당 요청을 처리할 수 있도록 준비해야한다.

어찌됐든 이 두개의 시스템(혹은 프로세스)에서 연결을 만들기 위해 요청을 보내는지 받아들이는지에 따라 client, server + socket으로 나뉘게 된다.

근데 client, server socket이 다르다고 착각하면 안되고 동일한데 역할과 구현 절차만 다르게 부르는 것일뿐 같은 형태의 소켓이다. 단지 역할 즉 호출되는 api함수가 다른거라.. 착각 ㄴㄴ하자

client, server socket들은 데이터를 연결후에 주고받는다고 생각하지 마라. 서버 소켓은 클라이언트 소켓의 연결 요청을 받아들이는 역할만 수행할 뿐 직접적인 데이터 송수신은 서버 소켓의 연결요청 수락의 결과로 만들어지는 새로운 소켓을 통해 처리된다.

보통 서버 소켓 파일을 열고 ip port에 bind해서 (0~65535)중 하나의 포트 번호를 사용한다. (중복되게 사용은 못함). 그리고 listen()을 통해 클라이언트의 요청을 기다리고 connect가 오면 연결을 맺고 그 이후에 send recv를 주고받은후 연결을 끊을때 close()를 한다. 커넥션의 연결 요청은 일반적으로 queue에 쌓이고 만약 연결이 되지 안흥ㄴ 상태면 NOT ESTABLISHED state 대기 상태다.

만약 클라이언트와 연결 수립 상태가 되고싶다면 listen() 켜놓고 conenct() 받은후 accept() 해야된다.
근데 여기서 accept()한 애는 bind, listen한 서버 소켓이 아니라는 신기한 점이 있다.

"응? 이게 무슨소리야" 라고 할 수 있겠지만 결론저긍로 최종적으로 클라이언트 소켓과 연결이 만들어지는 소켓은 앞서 사용한 서버 소켓이 아니라 accept api 내부에 있는 새로 만들어지는 소켓이다.

ㅋㅋ 앞에서도 언급했지만 서버 소켓의 중요 역할은 클라이언트 연결 요청을 수신하는 것이고 그래서 bind, listen등의 작업을 진행했고 소켓에 포트번호를 바인딩하고 요청 대기 큐를 생성해 요청을 대기하고 accpet가 되면 데이터 송수신을 위한 새로운 소켓을 만들고 대기 큐에 쌓여있는 첫 번째 연결 요청을 매핑시킨다. 그리고 그 이후 데이터 주고받는건 그친구랑 하시겠죠?

그러니까 서버소켓의 역할은 listen, close 라는 것입니다.

그리고 처리 과정이 다 긑나면 close를 하시면 됩니다. api를 통해 생성한 서버 소켓에 더해 accept로 호출한 것들도 관리해줘야겠죠?

이렇게 소켓에 대해서 정리해보았습니다.