TCP 10/23

with MK·2020년 10월 23일
0

소켓 프로그래밍

목록 보기
10/13

소켓의 타입과 프로토콜의 설정

프로토콜이란 무엇인가

  • 컴퓨터 상호간의 대화에 필요한 통신규약

소켓의 생성

#include <sys/socket.h>
int socket(int domain, int type, int protocol);
  • 해당 함수는 성공 시 파일 디스크립터, 실패 시 -1을 반환한다
  • domain은 소켓이 사용할 프로토콜 체계 정보를 전달한다
  • type은 소켓의 데이터 전송방식에 대한 정보를 전달한다
  • protocol은 두 컴퓨터간 통신에 사용되는 프로토콜 정보를 전달한다

프로토콜 체계(Protocol Family)

  • 소켓이 사용할 프로토콜의 부류정보를 말한다. PF_INET, PF_INET6 등이 있다.

소켓의 타입

  • 데이터 전송방식을 의미한다.

소켓의 타입 1: 연결지향형 소켓(SOCK_STREAM)

  • int tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
  • 중간에 데이터가 소멸되지 않고 목적지로 전송된다.
  • 전송 순서대로 데이터가 수신된다.
  • 전송되는 데이터의 경계가 존재하지 않는다.
  • 소켓 대 소켓의 연결은 반드시 1대 1이어야 한다.
  • 신뢰성 있는 순차적인 바이트 기반의 연결지향 데이터 전송 방식의 소켓
    버퍼에 수신된 데이터를 한번의 read 함수 호출로 데이터 전부를 읽어 들일수도, 반대로 여러번의 read 함수 호출을 통해서 읽어 들일수도 있다. 즉, read 함수의 호출횟수와 write 함수의 호출횟수는 연결지향형 소켓의 경우 큰 의미를 갖지 않는다.

소켓의 타입 2: 비 연결지향형 소켓(SOCK_DGRAM)

  • int udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  • 전송된 순서에 상관없이 가장 빠른 전송을 지향한다.
  • 전송된 데이터는 손실의 우려가 있고, 파손의 우려가 있다.
  • 한번에 전송할 수 있는 데이터의 크기가 제한된다.
  • 데이터의 경계가 존재한다는 것은 데이터를 전송할 때 두 번의 함수 호출이 수반되었다면, 데이터를 수신할 때에도 구 번의 함수 호출이 수반되어야 함을 의미한다.

주소체계와 데이터 정렬

소켓에 할당되는 IP주소와 PORT 번호

라우터와 스위치

  • 네트워크를 구성하려면 외부로부터 수신된 데이터를 호스트에 전달하고, 호스트가 전달하는 데이터를 외부로 송신해주는 물리적 장치가 필요하다. 이를 가리켜 라우터 또는 스위치라 하는데, 이것도 그냥 컴퓨터에 지나지 않는다. 다만 특수한 목적을 가지고 설계 및 운영되는 컴퓨터이기 때문에 별도의 이름을 붙인 것이다.

소켓의 구분에 활용되는 PORT 번호

  • IP는 컴퓨터를 구분하기 위한 목적으로 존재한다. 때문에 IP만 있다면 목적지 컴퓨터로 데이터를 전송할 순 있다. 그러나 최종 목적지인 응용프로그램에까지 데이터를 전송하기 위해서는 포트 번호가 필요하다.
  • NIC(네트워크 인터페이스 카드)라 불리는 데이터 송수신장치가 컴퓨터에 하나씩 달려있다. IP는 데이터를 NIC를 통해 컴퓨터 내부로 전송하는데 사용된다. 그러나 컴퓨터 내부로 전송된 데이터를 소켓에 적절히 분배하는 작업은 운영체제가 담당한다. 이 때 운영체제는 PORT 번호를 활용한다. 즉 NIC를 통해 수신된 데이터 안에는 PORT 번호가 새겨져 있는데 운영체제는 이 정보를 참조해 일치하는 PORT 번호의 소켓에 데이터를 전달한다.
  • PORT 번호는 2바이트로 표현되며, 0 ~ 1023은 Well - known PORT로 이미 예약이 되어있다. UDP와 TCP의 경우 소켓이 다르기 때문에 포트 번호가 중복되어도 상관이 없다.
  • 즉, IP 주소 뿐만 아니라 PORT 번호도 포함이 되어야 최종 목적이인 응용프로그램의 소켓까지 데이터를 전달할 수 있다.

주소정보의 표현

struct sockaddr_in{
    sa_family sin_family; // 주소 체계
    uint16_t sin_port;
    struct in_addr sin_addr; // 32비트 IP주소
    char sin_zero[8];
};

struct sockaddr{
    sa_family_t sin_family; // 주소 체계
    char sa_data[14]; // 주소 정보
};

struct sockaddr_in serv_addr;
if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1)...
  • sockaddr 구조체 변수의 주소 값은 여러 정보를 담기에 다소 불편하게 정의되어 있다. 따라서 sockaddr_in 구조체를 통해 쉽게 주소를 설정하고 이를 변환해야 하며 14바이트를 채우기 위해 sin_zero인 구조체 변수를 둔 것이다.

네트워크 바이트 순서

  • 네트워크 상 데이터를 전송할 때는 데이터의 배열을 빅 엔디안 기준으로 변경해서 송수신 한다.
    빅 엔디안의 경우 상위 바이트의 값을 작은 번지수에 저장하는 방식이다. 즉, 눈에 보이는 그대로 넣는 방식이다.

바이트 순서의 변환

  • unsigned short htons(unsigned short); // or long
  • unsigend short ntohs(unsigned short); // or long
    여기서 h는 host를 n은 네트워크를 의미한다. 즉 htons는 short형 데이터를 네트워크 바이트 순서에서 호스트 바이트 순서로 변환, htonl은 long형 데이터를 변환하는 것을 의미한다.

INADDR_ANY

  • addr.sin_addr.s_addr = htonl(INADDR_ANY);
    IP 주소를 자동으로 할당 해 준다.
    일반적으로 라우터가 할당 받은 IP 중 어떤 주소를 통해서 데이터가 들어오더라도 PORT 번호만 일치하면 데이터를 수신할 수 있게된다. 즉, 서버 프로그램의 구현에서 많이 사용된다.

서버와 클라이언트 실행 시 차이점

  • ./hserver 9190
    서버 소켓의 생성 시 PORT 번호만 전달하며 프로그램을 실행하였다. 그 이유는 INADDR_ANY를 통한 IP주소의 초기화에서 찾을 수 있다.
  • ./hclient 127.0.0.1 9190
    반면에 클라이언트의 경우 아이피 주소 또한 제공해 주고 있다.

0개의 댓글