https://www.youtube.com/watch?v=WwseO8l8rZc&list=PLcXyemr8ZeoSGlzhlw4gmpNGicIL4kMcX&index=5

 

영상에서 다루는내용

(네트워크 프로그래밍의 관점에서, 즉 실제 구현했을때 어떻게 동작하는지의 관점에서) socket의 의미

프로토콜 표준에서 정의한 socket 과는 어떤 차이가 있는지

TCP/IP stack을 시스템 관점에서 본다면

TCP/IP stack은 인터넷이 발며되면서 함께 개발된 프로토콜 스택이다.

컴퓨터 시스템의 관점에서 보면,  2가지 layer로 나눌 수 있다.

1. application layer

시스템이 제공하는 네트워크 기능을 사용한다

애플리케이션 레벨에서 구현한다.

 

2. transport layer, internet layer, link layer

애플리케이션이 사용할 수 있도록 네트워크 기능을 지원한다.

시스템 레벨에서 구현한다.

 

실제로 시스템이 동작하는 관점에서 소켓이란?

애플리케이션이 시스템의 기능을 함부로 쓸 순 없다.

만약 어떤 애플리케이션이 시스템 기능을 활용하기 위해 System의 Kernel에 접근해서 사용하려다가, 시스템에 문제가 생긴다면, 시스템 위에서 동작하는 다른 모두 application 이 모두 문제가 가기에 System Code, Kernel에 접근불가하며,

반드시 interface, protocol를 통해 application이 system기능을 사용한다.

 

즉, 시스템은 애플리케이션이 네트워크 기능을 사용할 수 있또록 프로그래밍 인터페이스를 제공한다.

시스템이 제공하는 프로그래밍 인터페이스이 SOCKET 이다.

애플리케이션은 SOCKET을 통해 데이터를 주고 받는다.

이 SOCKET을 통해 프로그래밍을 할 수 있기에 프로그래밍 인터페이스라고한다.

개발자는 socket programming을 통해 네트워크 상의 다른 프로세스와 데이터를 주고 받을 수 있도록 구현한다.

 

C언어 구현 예제코드 server.c

int main(){
	sock = socket(AF_INFT, SOCK_STREAM, 0);
    ..
    bind( ~)
    ..
    listen()
    ..
    new_sock = accept(sock~~)
    ..
    read(new_socket, 
    ..
    write(
    ..
    close
    close

}

 

 

대부분의 시스템은 socket 형태로 네트워크 기능을 제공한다.

반드시 이 소켓을 사용해야만 어플리케이션은 네트워크 기능을 사용한다.

나는 지금까지 http로 개발했지만, Socket은 사용한 적이 없다는 개발자가 존재한다.

보통 개발자가 socket을 직접 조작해서 통신기능을 구현할일은 적다.

예를들어, application layer의 프로토콜은 보통 라이브러리나 모듈 형태로 해당 기능이 제공되는데, 이떄 내부를 열어보면 소켓을 활용해서 프로토콜을 구현했음을 알 수 있다.

 

 

실제 구현/동작의 관점에서 소켓 정의하기

Internet 상에서 컴퓨터 A, 컴퓨터 B는 SOcket을 통해 네트워크 통신한다.

port(number)는 socket을 식별하기 위해 부여되는 숫자이다.

실제 구현에서 socket은 <protocol, IP address, port number>로 정의된다.

 

소켓 프로그래밍 할떄의 코드이다.

sock = socket(AF_INET, SOCK_STREAM, 0); 
sockaddr.sin_family = AF_INET;
sockaddr.sin_addr.s_addr = inet_addr("111.0.0.2");
sockaddr.sin_port = htons(8080);
bind(sock, (struct sockaddr*)&sockaddr, sizeof(servaddr))

- SOCK_STREAM : TCP 프로토콜을 의미한다. 

- socket에 socket addr 주소를 부여한다. 여기서 말하는 ip address와 port number를 의미한다.

- sockaddr.sin_addr.s_addr을 지정한다.

- sockaddr.sin_port 을 지정한다.

- bind 를 통해 socket에 sockaddr에 binding 한다.

 

Server 프로그래밍은 포트넘버를 명시해야 CLient에서 데이터를 보여줄 수 있기에 명시해야하지만.

Client 쪽은 System, OS가 알아서 binding해서 요청합니다.

 

핵심은, 실제 구현 동작관점에서 이렇게 protocol, IP address, port number로 정의한다.

실제 소켓은 표준처럼 유니크하게 식별되는가?

왜 표준에서처럼 unique하게 식별된다고 말하지 않고 "정의"한다고 하는걸까?

프로토콜 표준에서 정의한것처럼 socket은 <protocol, IP address, port number>로 유니크하게 식별되는가?

프로토콜 스펙을 시스템 레벨에서 구현하면서 조금 달라진다.

UDP 같은경우 IP address,와 port number로 유니크하게 식별된다. protocol은 UDP로 고정이다.

TCP 는 불가능하다. 이유는 protocol이 TCP로 고정일떄 유니크하게 식별되지 않는다.

 

그럼 어떻게 TCP를 유니크하게 식별할까?

 

실제 TCP 소켓이 식별되는(동작하는) 방식

TCP 소켓이 어떻게 유니크하게 식별할 수 있을까에 대한 설명이다.

인터넷 통신을 하기위해 Socket을 연다.

호스트 A  Socket을 만든다. < 77.77.77.77, 49999> binding. Client역할로 한다.

호스트 B Socket을 만든다. < 50.50.50.50, 8080> binding. Server역할로 한다.

 

TCP는 먼저 커넥션을 맺고 나서 데이터를 주고받는다고 배웠다.

실제 구현에서는 어떻게 할까.

먼저 커넥션을 맺기 위해 Client쪽에서 Server족으로 요청을 보낸다.

Server쪽에서는 요청을 받을 수 있도록 기다리는 Socket이 필요하다. Connection 맺는 요청을 기다리는 Listening Socket이 잇다.

이제 Three-way 3 way handshake로 커넥션을 맺는다.

커넥션이 성립되고 나서 Server쪽에서 Listening Socket외에 또다른 Socket, 즉 실제로 데이터를 주고받는 Socket 을 만든다. 이 CLient 쪽에서는 새롭가 멘들어진 Socket과 함꼐 커넥션 위에서 데이터를 주고받는다. (Listenign Socket과는 다르다.)

 

만약 호스트 C Socket을 만든다. <33.33.33.33, 54321> 이 Client 역할이다.

호스트 B Server에 TCP 연결을 위해 TCP 커넥션 먼저 맺는다. Listening Socket에 요청을 보낸다. 이 사이에서 3way handshake로 커넥션을 맺는다. Server는 별도의 실제로 데이터를 통신하기 위한 Socket을 하나 더 만들어서 Connection 위에서 데이터를 주고 받는다.

이 Listening Socket에 바인딩된 IP 주소는 <50.50.50.50, 8080> 이다. 근데 지금 과정을 보면, Socket이 추가로 Socket이 생성되었는데 이 Socket의 IP주소와 Port 번호가 뭘까?

애네들 각각 모두가 동일한 Socket 인 것이다.

즉, 세개의 TCP socket이 모두 <IP addres, port Number>가 모두 동일하다.

의문이든다.

그러면 어떻게 이 Server의 Listenign Socket 1개, 나머지 통신을 위한 Socket 2개를 어떻게 구별하는건가?

각각의 데이터가 어디로 갈지 어떻게 아는것인가.

현재 Connection은 Client Socket - Listenign Socket 으로 커넥션이 2개 맺어져있다.

<77.77.77.77, 49999, 50.50.50.50, 8080>

<33.33.33.33, 54321, 50.50.50.50, 8080>

이렇게 두개가 있다.

 

실제 구현에서는

Connection 연결요청이 오는경우, 아직 TCP connection 맺기전에는 listening socket으로 데이터를 보낸다.

connection 이 성립된 이후에는, 추가적으로 <src IP, src port, dest IP, dest port>로 socket을 식별한다.

어디서부터 데이터가 왔는지 확인해서 Socket을 식별한다는것이다.

 

만약 호스트 C가 HEader정보에 src IP, src Port, dest IP, dest Port를 헤더에 담아 보낸다.

src IP : 33.33.33.33, dest IP: 50.50.50.50

src Port : 54321         dest port : 8080

 

data가 목적지에 도착했을떄 목적지에서는 데이터가 이미 커넥션이 맺어진 상태에서 온건지 아닌지 판단한다. ( 해당사항을 판단할 수 있다.)

커넥션 이후에 온것을 확인했기에, Listenign Socket이 아닌 2개의 나머지 소켓으로 간다. 그런데, 문제는 호스트 B에서 만들어진 Socket의 2개는 모두 IP주소도 같고 Port 번호도 같다는것이다.

그렇기에 dest ip : 50.50.50.50, dest port : 8080 으로는 알 수 없다.

 

보낸쪽의 src IP, src Port를 활용해야한다. 처음에 connection 을 맺은 < 33.33.33.33, 54321, 50.50.50.50, 8080> 에서 커넥션을 맺은 Socket을 활용해서 어디로 보낼지 판단한다.

 

TCP Server 쪽에서만 발생하는것인가.

아니면 Client 쪽에서도 같은 IP와 Port를 가지는 서로 다른 TCP 소켓이 생길 수 있을까?

 

호스트 C도 Socket이 현재 <33.33.33.33, 54321> 소켓이 있다.

다른 Socket 같은 <33.33.33.33, 54321> 동일한것이 존재할 수 있다.

몇몇 조건을 만족하면 서로 다른 socket이 동일한 IP와 port를 가지는것이 가능하다.

간단하게 설명하면, 아까 Client소켓은 직접 코드를 작성해서 주소를 바인딩하지않고 OS level에서 바인딩하도록 한다고하였는데, 특히 Port number를 어떻게 할당하냐면, 현재 사용하고 있지 않은 Port를 알아서 가져와서 사용한다.

만약, 모든 Port번호가 다 쓰인다면, 아주 간단히 설명하면 포트가 재사용될 수 있는 가능성이 있다.

그래서 우연히 호스트 C가 2개의 동일한 소켓을 가지고서 호스트 B에 커넥션 요청한다면, 이건 가능하지 않다.

이유는 이미 1개가 커넥션이 있는 상태라면, 똑같은 커넥션이 Unique해야하기에 같은 IP주소와 Port number를 가진 SOcket은 추가로 맺을 수 없다.

 

하지만, 이런 경우는 가능하다.

인터넷 상에 호스트 D Server Socket < 92.92.92.92,8080> 이 존재한다.

이떄, 호스트 C Client가 호스트 D Server에 커넥션 요쳥하여 커넥션이 <33.33.33.33, 54321, 92.92.92.92, 8080>이 Unique한 커넥션이 생성된다.

이댸 클라이언트는 4개의 값으로  <src ip, src port, dest ip, dest port>로 구분할 수 있다.

만약 호스트 Client C가 호스트 Server D에 값을 요청해서 이제 호스트 Server D에서 응답을 내려주려고한다.

그렇다면, 호스트 D Server 는 Header에 src IP : 92.92.92.92 , src Port는 8080, dest ip: 33.33.33.33, dest port : 54321를 담은 Data를 Body 에 담고 보낸다.

이 상황에서 데이터가 호스트 C에도착했다. 하지만, dest ip와 dest port로 현재 존재하는 호스트 C에 존재하는 두개의 소켓을 구별할 수 없다. 어디로 갈지 알 수없다.(같은 IP와 Port를 가지고있기에) 그렇기에 이떄 Header의 src IP와 src Port 8080 을 확인해서 어디 소켓으로 보낼지 정할 수 있다.

 

핵심은, TCP socket은 <ip, port>만으로는 유니크하게 식별할 수 없어 커넥션의 정보를 사용한다.

 

만약 TCP 표준대로 구현하려면, 여러대의 Socket이 같은 IP와 port 를 가지면 안된다.

하지만 기능 구현함에 있어서 명세대로 구현하기 어렵기에 이러한 사항을 구현햇다.

실제 UDP 소켓이 식별되는(동작하는) 방식

UDP는 위의 표준대로 구현되어있다. 즉, IP address와 port number만으로 유니크하게 식별가능하다.

대신, TCP와는 달리 커넥션 개념이 없다.

TCP가 커넥션이 필요한 이유는 TCP든 UDP든 IP Protocol위에서 작동하는것인데, IP Protocol은 unreliable하기에 신뢰를 주기 위해 TCP 를 커넥션을 통해 안정적으로 진행하기 위해 커넥션을 만든것이다.

UDP는 데이터가 소실되거나 순서대로 들어오지 않을 수 있다.

UDP 소켓이라면 하나의 소켓으로 어디든 보낼 수 있다는것인가? 맞다.

즉, UDP socket에서 데이터를 보낼때 어느 UDP socket으로 보낼지 저장할 수 있다.

 

port number 상세 설명

16 bits 로 이루어진 숫자이다. (  0 ~ 65535 )

포트넘버는 크게 3부분으로 나뉜다.

- 0 ~ 1023 : well-known ports, system ports ( HTTP(80), HTTPS(443), DNS(53) )

- 1024 ~ 49151 : registered ports (IANA에 등록된 번호)  ex) MYSQL DB 3306, Apache tomcat server 8080

: 49152 ~ 65535 : dynamic ports (등록안된번호, 임시로 혹은 자동할당될떄 사용한다.)

표준과 실제 동작의 비교정리

socket Programming을 실제 구현에 있어서 표준과 다른점들을 알 수 있었다.

미묘하게 다른 부분들을 이해할 수 있다.

 

프로토콜 표준

port (number) :

- 프로세스가 데이터를 주고받는 통로이다.

- 인터넷 상에서 port 식별을 위한 숫자

 

socket 

- port를 유니크하게 식별하는 주소

- port 자체를 의미하기도 한다.

 

socket 식별 방법(유니크)

- <protocol, IP, port>

 

TCP connection

- TCP에서 안정적인 데이터 송수신을 위해 필요한 기반이다.

- <src IP, src port, dest IP, dest port> 로 구성되고 유니크하게 식별

 

Socket Programming 실제 구현

port (number) :

- 인터넷 상에서 port 식별을 위한 숫자

 

socket 

- Programming interface

- 애플리케이션은 socket을 통해 데이터를 주고받는다.

 

socket 식별 방법(유니크)

UDP : <IP , Port>

TCP : 

- connection 전 : Listening Socket의 <IP, Port>

- connection 후 : <src IP, src port, dest IP, dest port>

 

TCP connection

- TCP에서 안정적인 데이터 송수신을 위해 필요한 기반이다.

- <src IP, src port, dest IP, dest port> 로 구성되고 유니크하게 식별

 

 

마무리

Socket의 의미와 백엔드 서버가 어떻게 동시에 많은 요청을 처리할 수 있을까. ( port는 66506 개 밖에 없는데 ) 더 많은 데이터를 어떻게 처리하는것인가에 대해 알 수 있다.

 

+ Recent posts