[Network] TCP/IP

park9910·2022년 5월 15일
0

윤성우의 열혈 TCP/IP 소켓 프로그래밍을 보며 내용과 생각을 정리하는 글입니다.

네트워크 프로그래밍?

소켓 을 기반으로 둘 이상의 컴퓨터 사이에서 데이터 를 송수신 하는 프로그램의 작성을 의미

여기서 말하는 소켓 이란

  • 네트워크(인터넷)의 연결 도구
  • 운영체제에 의해 제공되는 소프트웨어 장치

라고 할 수 있는데, 네트워크 통신에 필요한 기본적인 준비를 이 소켓이라는 형태(개념)로 구현을 해 놓음으로써, 개발자가 네트워크 통신을 하는데 발생하는 공통적인 코드를 짤 필요가 없도록 만든 것이다.

따라서 개발자가 네트워크 통신을 하고자 한다면 소켓을 생성하고, 정해진 규약에 맞게 데이터를 넣어만 준다면, 데이터 송수신의 내부적인 처리는 신경쓸 필요가 없어지는 이점이 있다.

데이터의 송수신 방법 에 따라 소켓의 종류가 나뉘는데 대표적으로 크게 TCP 와 UDP 로 나눌 수 있다.


TCP

TCP 는 Transmission Control Protocol 의 약자로 이름 그대로 전송을 제어하는 프로토콜을 의미한다.

프로토콜은 우선은 일종의 통신 규약이라고 생각하면 편할 것 같다

UDP 에 비해 통신의 방식이 다소 까다로운 TCP 는 일전에 포스팅 했던 3-way handshake 를 통해 다른 소켓과 연결을 하고, 4-way handshake 를 통해 연결을 해지한다.

대표적인 특징으로는

  • 서버 소켓은 소켓 간 연결만을 담당한다
  • 중간에 데이터가 소멸되지 않는다
  • 전송 순서대로 데이터가 수신된다
  • 데이터의 경계가 존재하지 않는다
  • 소켓 대 소켓의 연결은 1 대 1 구조이다

TCP 통신은 데이터의 경계가 없다

패킷 단위가 데이터의 경계라고 생각할 수 있다.

하지만 여기서 말하는 데이터의 경계란 수신자의 입장에서 이야기를 하는건데, 가령 TCP 방식의 통신에서는 송신자가 데이터를 100번 나눠서 보내도 수신자가 한번에 해당 데이터를 다 받을 수 있다는 것이다. 즉 데이터의 경계의 구분 없이 데이터를 수신할 수 있다는 의미다

echo 서버/클라이언트의 문제점

데이터의 경계가 없다보니 내가 수신한 데이터가 상대방이 송신한 데이터의 전문이 맞는지 확인할 길이 없다.

따라서 클라이언트와 서버는 사전에 더욱 심오한 약속을 해야하는데
가령 송수신 데이터의 크기는 100바이트로 고정을 하는 방식으로 서로 100바이트 크기의 데이터가 날아오기 전까지는 계속해서 socket 으로부터 데이터를 읽는 방식으로 구현을 하여 문제를 해결할 수 있다

int socket(int domain, int type, int protocol)

위와 같은 코드를 통해 소켓을 생성할 수 있고, 각각의 파라미터를 설명하자면

domain : 어떤 영역(domain) 에서 통신을 수행할지를 이야기한다. PF_INET, PF_INET6 와 같은 값이 들어갈 수 있는데, AF_INET, AF_INET6 와도 값이 같아서 혼용되기는 하나, 의미상 프로토콜의 체계를 명시하는 것이 바람직할 것 같다.

type : socket 의 통신 종류를 명시하는 것으로, TCP 는 SOCK_STREAM, UDP 는 SOCK_DGRAM 으로 명시한다,

protocol : 통신 종류에 따른 프로토콜을 명시한다 IPPROTO_TCP, IPPROTO_UDP 로 명시한다.

최초 설계 당시 하나의 주소 체계가 여러 프로토콜을 지원할 수 있는 방식을 고려해서 프로토콜과 주소 체계를 분리해놓았지만 실제로 그렇게 개발되진 않았다고 한다.

. . .

여기까지 왔으면 이제 소켓이 생성되었다. 이 소켓은 현재 사용자가 다른 소켓과 어떻게 통신할지를 정해준 것이고, 다음으로 명시해야하는 것은 소켓의 정보 (주소, 주소 체계, 포트 번호) 이다.

int bind(int sockfd, struct sockaddr *myaddr socklen_t addrlen)

sockfd : socket 의 file descriptor number
myaddr : socket 의 정보가 들어있는 데이터
addrlen : myaddr 의 크기

소켓간 통신을 하기 위해서는 네트워크 상에서 소켓의 위치를 나타내는 주소(IP) 와 소켓의 위치를 나타내는 포트 번호 를 지정해줘야한다.

int listen(int sockfd, int backlog)

TCP 소켓은 다른 소켓으로 부터 연결 요청을 받을 수 있는데, listen 은 연결 요청을 받는 상태로 소켓을 변경하는 메소드이다.

sockfd : socket 의 file descriptor number
backlog : 연결 요청이 온 socket 들의 waiting queue 길이

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)

accept 메소드를 통해 연결요청이 온 소켓을 연결한다 (내부적으로 3-way handshake 가 일어난다)

addr : 연결요청이 온 client socket 의 정보를 담는 공간
addrlen : client socket 을 담는 공간의 크기를 적고, 실제 넘어온 client socket 의 크기로 값이 변경된다. (값이 아닌 변수를 넘겨줘야함)

accept 의 결괏값은 서버소켓 측에서 연결한 소켓의 fd num 인데 이것이 서버 소켓은 단지 연결만을 담당한다는 것을 의미하는 부분이다

이렇게 client 의 연결 요청을 받고, 데이터를 송수신 하는 소켓을 server socket 이라고 한다.

반대로 client socket 은 bind 까지의 과정은 동일하고 (socket 의 정보를 저장해야하니)

그 뒤에는 바로 server socket 과 연결을 요청한다.

int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen)

serv_addr : 연결요청을 할 server socket 정보
addrlen : server socket 의 크기


TCP/IP

보통 이렇게 두가지 프로토콜을 묶어서 부르곤 하는데, 그 이유가 이 두가지 프로토콜이 인터넷 기반의 데이터 송수신을 목적으로 설계된 기술이기 때문이다.

실제로 이 둘은 같은 OSI 7계층 내에서 IP 는 Network(식별) 계층에 속하고, TCP 는 transport(전송법) 계층에 속할 수 있다.

인터넷 프로토콜

위에서 프로토콜 이란 일종의 데이터 통신 규약이라고 설명을 했다.

이러한 프로토콜에는 여러가지가 있지만 우리가 대표적으로 사용하는 프로토콜로 인터넷 프로토콜 이 있다.

IPv4 의 8비트 수(unsigned int) 4개의 조합, 255.255.255.255 와 같이 표현가능한 주소를 사용해서 기기의 위치를 식별하고 통신을 한다.

PF_INET : IPv4 인터넷 프로토콜 체계
PF_INET6 : IPv6 인터넷 프로토콜 체계
PF_LOCAL : 로컬 통신을 위한 UNIX 프로토콜 체계
PF_PACKET : Low Level 소켓을 위한 프로토콜 체계
PF_IPX : IPX 노벨 프로토콜 체계

등 인터넷 프로토콜을 제외하고 몇가지 특수한 방식의 통신 규약이 있다.

인터넷 프로토콜은 패킷 혹은 데이터그램과 같은 데이터를 호스트 끼리 송수신 하는 구조, 그 과정에서 주소를 사용 흔히 IP 주소 라고 한다

TCP 와 같은 프로토콜은 IP 의 상위 프로토콜 즉 IP 의 데이터 통신 방식에 특정한 약속을 더하는 것을 의미한다. 위에서 설명한 연결성을 확보하는 과정이라던지 패킷의 전송순서를 보장하는 방식을 채택함

통신이라는 것이 상황에 따라서 목적이 다르기 때문에 당연히 데이터를 통신하는 규약을 다르게 선택할 수 있을 것이다.

대표적으로 TCP 는 좀 더 신뢰성 있는(무손실성) 통신을 지향하고, UDP 는 끊기지 않는(신속성) 데이터 통신을 지향한다고 볼 수 있다.

인터넷 주소(IP 주소)

IP 주소 체계에는 IPv4 와 IPv6 가 존재하는데 각각 4바이트, 6바이트 주소 체계를 가진다.

주소는 다시 네트워크 주소호스트 주소 로 나뉘는데, 네트워크 주소를 통해서 네트워크(같은 네트워크 환경에 존재하는 기기들)를 찾고, 그 안에서 호스트(기기)를 찾는다.

주소 체계에서, 종류별로 A/B/C/D/E 클래스로 분류가 되는데, 이렇게 분류하는 이유는 네트워크 내에서 호스트의 수가 가변적이므로 상황에 맞게 네트워크 대역을 선택할 수 있도록 하기 위함이라고 한다.

클래스는 가장 앞의 1바이트 숫자만을 보고도 구별이 가능한데 그 이유는

클래스별 첫 번째 바이트가

A 클래스는 0~127 의 범위를 000..
B 클래스는 128~191 의 범위를 100..
C 클래스는 192~223 의 범위를 110..

D 와 E 는 각각 Multicast 와 Reserved Address 로 할당되어서 우선 생략한다.

Port Number

IP 가 호스트(컴퓨터) 를 구분해주는 주소였다면, Port 는 호스트 내에서 실질적으로 데이터를 송수신하는 주체인 소켓을 구분해주는 번호이다.

16비트로 표현하기 때문에 0~65535 사이의 번호를 가진다.

바이트 순서

간혹가다 cpu 가 데이터를 저장하고 해석하는 방식의 차이 때문에 문제가 생기기도 하는데 빅 엔디안리틀 엔디안 을 잘 이해하고 있어야한다.

빅 엔디안 : 데이터의 상위 바이트가 메모리의 하위 주소부터 저장되는 방식
리틀 엔디안 : 데이터의 하위 바이트가 메모리의 하위 주소부터 저장되는 방식

우리가 생각하는 4바이트 데이터가 있으면 1바이트씩 잘라서 저장될 때 앞쪽부터 잘라서 넣느냐 뒤쪽부터 잘라서 넣느냐의 차이를 생각해보면 된다.

네트워크 통신에서는 바이트 순서로 빅 엔디안 방식을 사용하고 있으며, htons/htonl 등의 메소드로 데이터의 구조를 빅 엔디안 방식으로 바꿀 수 있다

대표적인 빅 엔디안으로 저장해야하는 데이터

  • 소켓의 IP 주소

  • 소켓의 포트 번호

    네트워크 바이트 순서가 다르기 때문에 inet_aton/inet_ntoa 등으로 주소(a)를 (to) 네트워크(n) 바이트 순서로 변환해주는 메소드가 존재한다


profile
https://ppaksang.tistory.com/ 옮겼습니다 !!

0개의 댓글