흔히 소켓이라고 하면 콘센트에 꼽는 것을 소켓이라고 합니다. 어떤 것을 연결해서 꽂아서 하는 것을 데이터를 주고 받는 것을 의미합니다.
그래서 소켓프로그래밍이라는 것도 비슷한데요. 실제로 네트워킹이라는건 NIC에서 일어납니다.
쉽게 말해서 랜카드인데요. 이것을 통해서 데이터가 들어갔다 나갔다 하게 됩니다.
네트워크 인터페이스 컨트롤러 - 위키백과, 우리 모두의 백과사전
네트워크 인터페이스 컨트롤러(network interface controller, NIC)는 컴퓨터를 네트워크에 연결하여 통신하기 위해 사용하는 하드웨어 장치이다.[1] 네트워크 카드(network card), 랜 카드(문화어: 망카드, 망
ko.wikipedia.org
컴퓨터에선 하드웨어와 OS가 있는데 OS가 하는 주된 일이 이 하드웨어를 관리하는 일입니다.
예전 WIndows, Mac 이전 세대는 하드웨어를 다이렉트로 연결해서 그 인터페이스를 외부에 공개를 했습니다.
개발자들이 어떤 하드웨어를 제어하고 싶을 때 그 하드웨어를 다이렉트로 연결해서 제어했는데 그렇게 하다 보니 하드웨어별로 다른 제어를 해야하는 문제가 생겼습니다.
네트워크 카드 하나만 봐도 Broadcom에서 만든 것이냐, intel에서 만든 것이냐에 따라 다 다르게 프로그래밍해야하는 문제가 있었는데요. 이렇게 하는게 불편해서 OS에서 어떤 추상화 Layer를 HAL이라고 하는데 이걸 제공합니다.
그래서 이 하드웨어가 서로 다른 브랜드의 하드웨어들이 연결되어 있다고 하더라도 그 위에 추상화 Layer를 하나 올려서 그 위를 깨끗하게 만들어 줘서 프로그램 입장에서는 어떤 브랜드의 하드웨어 부분인지 상관없이 똑같이 코딩할 수 있도록 만들어 줍니다.
그걸 HAL이라고 합니다.
어댑팅이라고 볼 수 있는데 만약 구불구불한 도로가 있고, 그 위에 자동차가 달리려고 한다면 표면이 울퉁불퉁해서 달리기 힘든 상태인데요. 그래서
그 표면과 똑같이 생긴것을 만들어 놓고 뒤집어서 그 위를 반듯하게 깎아버리면 바퀴가 달린 자동차는 잘 달릴 수 있을 것입니다.
이것을 어댑팅한다고 하는데 울퉁불퉁한 부분을 적응해서 골고루 평평하게 만들어준다고 하는데 이것을 Adapter 패턴 이라고도 합니다.
그래서 HAL도 이런 Adapter패턴이고, 이런 Adapter패턴은 프로그래밍 할 때 많이 사용 되는 패턴 중에 하나이죠.
여기까지 정리하면 OS가 HAL을 제공해서 그 아래 부분인 하드웨어 부분들을 감춰줘서 하드웨어가 어떻게 만들어졌는지 상관없이
그 윗부분에서는 똑같은 인터페이스로 코딩할 수 있다는 것입니다.
그래서 이 두 접점을 연결하는 것을 네트워크 프로그래밍에서는 소켓 프로그래밍이라고 볼 수 있습니다.
그리고 프로그램에서 NIC를 통해서 데이터를 주고 받는 것을 제어하는 것을 '소켓(Socket)'이라고 하고, 이런 소켓을 이용해서 프로그래밍하는 것을 '소켓 프로그래밍(Socket Programming)'이라고 합니다.
소켓 프로그래밍을 할 때 이것도 결국엔 I/O인데 프로그램 관점에서는 데이터가 인터넷을 통해 오든, 파일로 오든, 키보드 입력값으로 오든 뭘 하든 간에 데이터가 들어오고, 나가는 과정입니다.
프로그램 입장에서는 I/O Process인데 이 I/O 과정에서 중요한 기능 두개가 Read/Write입니다.
그래서 소켓 프로그램이라는 것은 Read하는 기능, Write하는 기능 2개가 있다고 보면 됩니다.
물론 소켓 프로그램이 복잡하지만 궁국적으로 추구하는 것은 읽고 쓰는 I/O Process라고 보면 됩니다.
그래서 Read와 Write를 하는데 크게 보면 2가지 방식으로 나뉘는데요.
동기식 방식(Synchronous)이 있고 비동기식 방식(Asynchronous)이 있습니다.
먼저 동기식 방식은 데이터 Read()를 요청을 했다 했을 때 그 요청이 완료될 때 까지 Read()는 끝이 나지 않고, Read()에서 멈춰있게 되어 프로그램이 더 이상 진행되지 않게 됩니다.
예를 들면 어떤 코드를 만들었는데
for {
data := Read()
Print(data)
이렇게 for문에서 데이터를 가져오는 코드를 만들고, data를 Print하는 코드를 작성했다고 쳐보죠.
동식 방식에서는 data := Read()
이 부분에서 데이터가 실제로 들어올 때 까지 계속 기다립니다.
그리고 데이터가 실제로 들어오면 그 때 되서야 그 다음줄로 넘어가는 방식입니다.
실질적으로 data변수에는 항상 어떤 data가 들어있다고 가정할 수 있습니다.
그런데 Read()
를 보게 되면
NIC를 통해서 데이터가 들어오게 되고, 소켓을 통해서 프로그램으로 전달이 되고, 프로그램에서 Read()를 요청하게 되면 데이터가 들어올 때까지 기다리게 되는데 이 데이터는 랜카드를 통해 들어오고, 인터넷에 들어오게 되는데 이 데이터는 언제올지 모른다는 것입니다.
이 데이터가 레이턴시(latency)도 있고, 데이터를 보내야 오게 되는 것인데, 언제 보낼지도, 언제 올지도 모르는 상황인데요.
언제 올지 모르는 상황에서 데이터가 올 때 까지 계속 기다리고 있는 것입니다.
그래서 동기식의 문제는 프로그램이 진행이 안되기 때문에 그 쓰레드는 거기서 멈춥니다. 그래서 동기식 방식은 서버에서 이용하기가 어렵죠.
왜냐하면 서버에서는 하나의 커넥션만 핸들링 하는게 아니기 때문인데요. 그래서 이렇게 하면 안되고, Read Request를 날려놓고 바로 빠져 나간 다음에 실제 데이터가 왔을 때 처리 할 수 있어야 합니다.
이러한 방식을 비동기 방식이라고 합니다.
동기식 방식(Synchronous) | 비동기식 방식(Asynchronous) | |
---|---|---|
특징 | 요청이 완료될 때 까지 다음으로 넘어가지 않는다. | 요청을 날려놓고 바로 빠져나가서 요청한 데이터가 오면 처리한다. |
비동기식 방식을 크게 네트워크에서 두 가지로 나눌 수 있는데 버에서는 비동기식으로 사용한다고 생각하면 되는데 네트워킹에서는 Select방식과 윈도우에서 제공하는 IOCP방식이 있습니다.
Select방식은 PreRequest방식이고, IOCP방식은 PostRequest방식입니다.
요즘 프로그래밍은 이런것을 몰라도 크게 지장이 없어요. 특히 Golang같은 경우엔 라이브러리가 잘 되어 있는데 net package에서 제공하는 구조가 워낙 잘 되어 있어서 내부가 어떻게 동작하는지 몰라도 코딩하는데 크게 문제는 없지만 알아두면 좋죠.
Select방식은 예를들어 설명하면 공중 전화기가 한 대 있고, 어떤 사람들이 그 전화기를 쓰고 싶어서 여러명이 줄을 서 있다고 할 때 매번 그 안에 사람이 있나 없나 쳐다보는 것입니다.
전화기를 쳐다보고 사용하고 있으면 나오고, 딴 일하다가 돌아와서 다시 쳐다보고 또 쓰고 있으면 다시 나와서 딴일하고를 공중전화박스에서 사람이 전화를 다 쓸 때까지 반복하죠.
그러다 전화부스가 비어있으면 그 때 들어가서 사용합니다.
그래서 Select 방식이라는 것은 Read/Write의 요청이 있는데 자리가 비었는지 매번 확인해서 사용을 허락을 받으면 그 때가서 쓰는 방식입니다.
IOCP방식은 어떤 택배를 보내고 싶다고 가정해보죠. 우체국에 담당직원에게 택배를 보내달라고 직원에게 요청을 해주면 직원이 택배를 보냈다고 알려주게 됩니다.
그러면 그 택배가 실제로 갔는지는 보낸 사람은 상관하지 않고 다른 볼 일을 보러 가면 됩니다.
이것과 비슷하게 내가 택배를 받아야 되는 상황이 왔는데 내가 바구니를 직원에게 줘서 택배가 오면 담아달라고 요청을 하고, 다른일을 하러 갑니다.
그 사이에 직원이 바구니에 택배를 담아두게 될 것이고, 내가 다른일을 보고 돌아오면 바구니에 물건이 차 있는 것을 확인하게 되고, 물건만 꺼내면 됩니다.
바구니만 남아있으니까 또 물건이 오면 직원이 거기에 바구니를 담아 놓는 형식입니다.
이런 것을 IOCP방식이라 생각하면 됩니다.
이 두 가지 방법의 차이점을 보면 Select방식은 일은 내가 합니다. 내가 전화하고, 내가 데이터를 잇는 등, 일의 주체는 '나'입니다.
그래서 이 일을 내가 할 수 있는지 없는지를 살펴보는 방식이고
IOCP는 일의 주체가 '나'가 아니죠. 다른 사람이 나 대신 일을 해줍니다. 나는 그 사람에게 요청(Request)만하고 다른일을 하러 가면됩니다.
그러면 그 사람이 일을 다 한 음에 결과를 큐(Queue)에 쌓아놓고 있다가 내가 결과가 왔는지만 확인하면 됩니다.
여기선 나 대신 OS가 대신 일을 합니다. OS가 나 대신 데이터를 읽고, 쓰고, 담고를 다 해주죠.
그래서 OS가 귀찮은 일들을 대신 해주기 때문에 IOCP방식이 훨씬 효율적이라고 볼 수 있습니다.
그런데 Select 방식의 장점은 IOCP방식 보다는 좀 더 쉽게 구현할 수 있다는 점입니다.
IOCP는 OS를 써야 하기 때문에 커널을 들어가서 무언가를 해야하는 부분들이 있는데 Select방식은 그럴 필요가 없어요.
둘 다 자주 쓰는 방식이지만 윈도우즈에서는 IOCP방식이 성능이 훨씬 잘 나옵니다. 그래서 커넥션 수가 100개가 넘어간다면 IOCP를 100개가 안되면 Select방식을 쓰는 게 낫다는 정도의 수준에서 보면 됩니다.
그런데 아까도 말했지만 요즘 언어(Go, Java, .net)들은 이미 라이브러리에서 네트워크 기능들을 잘 지원해주기 때문에 굳이 IOCP를 썼는지, Select를 썼는지 몰라도 문제 없이 코딩 할 수 있습니다.
Select 방식 | IOCP 방식 | |
---|---|---|
차이점 | 1. 일의 주체는 '나'이기 때문에 내가 일을 처리한다. 2. 커넥션 수가 100개 이하일 때 사용한다. |
1. 일의 주체는 '나'가 아님. OS에게 일을 요청해서 그 결과를 큐(Queue)에 쌓아놓고 나는 결과 확인만 해준다. 2. 커넥션 수가 100개 이상일 때 사용. 3. 윈도우즈에서 성능이 더 잘 나옴. |
장점 | IOCP방식 보다는 훨씬 구현이 쉽다. | OS가 대신 일을 하기 때문에 효율적이다. |
공통 |
---|
요즘 언어(Go, Java, .net)들은 이미 라이브러리에서 네트워크 기능들을 잘 지원해주기 때문에 굳이 알지 않아도 문제 없이 코딩 할 수 있다. |
ckdqja135/Typescript-restful-starter
Contribute to ckdqja135/Typescript-restful-starter development by creating an account on GitHub.
github.com
'Networking' 카테고리의 다른 글
[바미] MMORPG 서버 구조에 대해 알아보자.(2)(싱글프로세스 vs 멀티프로세스) (1) | 2020.12.19 |
---|---|
[바미] MMORPG 서버 구조에 대해 알아보자! (1) (3) | 2020.12.18 |
[바미] Server Authority에 대해 알아보자! (0) | 2020.12.18 |
[바미] Deterministic 과 해킹에 대해 알아보자! (0) | 2020.12.18 |
[바미] 홀펀칭에 대해 알아보자! (0) | 2020.12.18 |