dev-miri

[computer network] 네트워크 프로그래밍과 소켓 (1) 본문

카테고리 없음

[computer network] 네트워크 프로그래밍과 소켓 (1)

miri-dev 2023. 4. 3. 00:14

1. 네트워크 프로그래밍과 소켓의 이해

네트워크 프로그래밍이란?

  • 소켓을 기반으로 프로그래밍을 하기 때문에 소켓 프로그래밍이라고도 함
  • 네트워크로 연결된 둘 이상의 컴퓨터 사이에서의 데이터 송수신 프로그램의 작성

소켓에 대한 간단한 이해

  • 네트워크(인터넷)의 연결 도구
  • 운영체제에 의해 제공이 되는 소프트웨어적인 장치
  • 소켓은 프로그래머에게 데이터 송수신에 대한 물리적, 소프트웨어적 세세한 내용을 신경 쓰지 않게 한다

소켓은 어떤 과정을 통해 생성되는가?

TCP 소켓은 전화기에 비유될 수 있다!

 

전화 받는 소켓의 생성(Listening Socket)

 

1. 전화기 장만하기

소켓은 socekt 함수의 호출을 통해서 생성된다. 

소켓의 생성은 전화기의 장만에 비유할 수 있다. 

#include <sys/socket.h>
int socket(int domain, int type, int protocol)
//성공 시 파일 디스크립터, 실패 시 -1 반환

 

2. 전화번호의 부여

전화기에 전화번호가 부여되듯이 소켓에도 주소 정보가 할당된다.

소켓의 주소 정보는 IP와 PORT번호로 구성 된다. 

#include <sys/socekt.h>
int bind(int sockfd, struct sockaddr *myaddr, socklen_t addrlen);
//성공 시 0, 실패 시 -1 반환

 

3. 전화기의 연결

연결 요청이 가능한 상태의 소켓 : 걸려오는 전화를 받을 수 있는 상태

일반 소켓 - 전화 걸 수 있음

listen 함수 호출 후 소켓 - 걸려오는 전화를 받을 수 있게 됨! -> 서버 소켓으로 바꾸어줌

#include <sys/socket.h>
int listen(int sockfd, int backlog)
//성공 시 0, 실패 시 -1 반환

 

4. 수화기를 드는 상황

연결 요청의 수락 : 연결 요청이 수락되어야 데이터의 송수신이 가능하다

수락 된 이후에 데이터의 송수신은 양방향으로 가능하다

#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//성공 시 파일 디스크립터, 실패 시 -1 반환

첫 번째 매개변수인 sockfd는 처음 상대방의 요청을 받은 소켓이다. 

accept 함수는 종료 후 새로운 소켓을 리턴한다. 

 

전화 거는 소켓의 구현(Client)

연결을 요청하는 소켓의 구현

  • 전화를 거는 상황에 비유할 수 있다
  • 리스닝 소켓과 달리 구현 과정이 매우 간단하다
  • ‘소켓의 생성’과 ‘연결의 요청’으로 구분된다
#include <sys/socket.h>
int connect(int sockfd, struct sockaddr *serv_addr, socklen_t addrlen);
//성공 시 0, 실패 시 -1 반환

Connect 함수로 상대방 서버에 접속한다. 

2번째 매개변수 sockaddr은 상대방의 소켓 주소(웹 서버의 포트번호, ip주소)등을 의미한다. 

 

2. 소켓의 프로토콜과 그에 따른 데이터 전송 특성

프로토콜이란?

  • 개념적으로 약속의 의미를 담고 있다
  • 컴퓨터 상호간의 데이터 송수신에 필요한 통신규약
  • 소켓을 생성할 때 기본적인 프로토콜을 지정해야 한다
#include <sys/socket.h>

int socket(int domain. int type, int protocol);
->성공시 파일 디스크립터, 실패 시 -1 반환
  • 매개변수 domain, type, protocol이 모두 프로토콜 정보와 관련이 있다
    • domain : 소켓이 사용할 프로토콜 체계(protocol family) 정보 전달
    • type : 소켓의 데이터 전송방식에 대한 정보 전달
    • protocol : 두 컴퓨터간 통신에 사용되는 프로토콜 정보 전달

프로토콜 체계(Protocol Family)

  • 프로토콜도 그 종류에 따라 부류가 나뉘는데, 그 부류를 가리켜 프로토콜 체계라 한다.
  • 프로토콜 체계 PF_INET은 IPv4 인터넷 프로토콜 체계를 의미한다.

소켓의 타입

  • 데이터 전송 방식을 의미함
  • 소켓이 생성될 때 소켓의 타입도 결정되어야 한다
  • 프로토콜 체계 PF_INET의 대표적인 소켓 타입 둘
    • 연결 지향형 소켓 타입 TCP
    • 비 연결 지향형 소켓 타입 UDP

프로토콜의 최종선택

-IPv4 인터넷 프로토콜 체계에서 동작하는 연결지향형 데이터 전송 소켓

int tcp_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

//tcp_socket : fd값
//PF_INET : IPv4
//SOCK_STREAM, IPPROTO_TCP : TCP 의미

-IPv4 인터넷 프로토콜 체계에서 동작하는 비 연결지향형 데이터 전송 소켓

int udp_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)

 

3. 주소체계와 데이터 정렬

인터넷 주소란? (IP주소)

  • 인터넷상에서 컴퓨터를 구분하는 목적으로 사용되는 주소
  • 4바이트 주소체계인 IPv4와 16바이트 주소체계인 IPv6가 존재한다
    • 대부분 IPv4 사용
  • 소켓을 생성할 때 기본적인 프로토콜을 지정해야 한다
  • 네트워크 주소와 호스트 주소로 나뉜다. 네트워크 주소를 이용해서 네트워크를 찾고, 호스트 주소를 이용해서 호스트를 구분한다.

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

  • application에 부여되는 번호
  • port 번호 - socket 1대 1 매핑
  • port 번호는 16비트로 표현. 따라서 그 값은 0이상 65535 이하
  • 0~1023은 잘 알려진 PORT(well-known PORT)라 해서 이미 용도가 결정되어있다
    • 1024~ : 우리가 사용

4. 주소 정보의 표현

IPv4 기반의 주소표현을 위한 구조체

struct sockaddr_in
{
	sa_family_t      sin_family; //주소체계(IPv4 or IPv6)
	uint16_t         sin_port; //PORT번호
	struct in_addr   sin_addr; //32비트 IP 주소
	char             sin_zero[8]; //사용되지 않음
};

구조체 sockaddr_in의 멤버에 대한 분석

  • 멤버 sin_family : 주소체계 정보 저장
    • AF_INTE : IPv4 인터넷 프로토콜에 적용하는 주소체계(대부분 사용)
  • 멤버 sin_port
    • 16비트 PORT 번호 저장
    • 네트워크 바이트 순서로 저장
  • 멤버 sin_addr
    • 32비트 IP주소정보 저장
    • 네트워크 바이트 순서로 저장
    • 멤버 sin_addr의 구조체 자료형 in_addr 사실상 32비트 정수 자료형
  • 멤버 sin_zero
    • 특별한 의미를 지니지 않는 멤버
    • 반드시 0으로 채워야 한다
  • clinet : server의 ip, port를 구조체에 넣음 → 구조체를 connect 함수에 전달(서버에 연결 요청 함수)
  • server : 자기 ip, port를 구조체에 넣음
struct in_addr
{
	in_addr_t   s_addr;
};  //32비트 IPv4 인터넷 주소
//in_addr_t : 32비트 unsigned 정수

구조체 sockaddr_in의 활용의 예

struct sockaddr_in serv_addr;
.......
if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1)
	error_handling("bind() error");
  • 구조체 변수 sockaddr_in은 bind 함수의 인자로 전달되는데, 매개변수 형이 sockaddr이므로 형 변환을 해야한다.
  • bind : socket에 ip와 port번호 할당하는 서버에서 쓰는 함수
  • 구조체 sockaddr_in 에 ip와 port 번호를 넣어서 bind 함수에서 사용
struct sockaddr
{
	sa_family_t  sin_family;     //주소체계(address family)
	char         sa_data[14];    //주소정보
};
  • 구조체 sockaddr은 다양한 주소체계의 주소정보를 담을 수 있도록 정의되었다. 그래서 IPv4의 주소정보를 담기가 불편하다.
    • 이에 동일한 바이트 열을 구성하는 구조체 sockaddr_in이 정의되었으며, 이를 이용해서 쉽게 IPv4의 주소정보를 담을 수 있다.

5. 네트워크 바이트 순서와 인터넷 주소 변환

CPU에 따라 달라지는 정수의 표현

: cpu에 따라서 상위 바이트를 하위 메모리 주소에 저장하기도 하고, 상위 바이트를 상위 메모리 주소에 저장하기도 한다. 즉, CPU마다 데이터를 표현 및 해석하는 방식이 다르다

 

바이트 순서(Order)와 네트워크 바이트 순서

-빅 엔디안(Big Endian) : 상위 바이트 값을 작은 번지수에 저장

-리틀 엔디안(Little Endian/intel 계열) : 상위 바이트 값을 큰 번지수에 저장

 

  • 호스트 바이트 순서 : CPU별 데이터 저장방식을 의미함
  • 네트워크 바이트 순서
    • 통일된 데이터 송수신 기준을 의미
    • 빅 엔디안이 기준!
      • 정수 전달 시 문제가 발생할 수 있으므로 빅 엔디안으로 통일
unsigned short htons(unsigned short);
unsigned short ntohs(unsigned short);
unsigned long htonl(unsigned long);
unsigned long ntohl(unsigned long);
  • short : 16bit - 포트번호
  • long : 32bit - IP주소
  • h는 호스트 바이트 순서를 위미
  • n은 네트워크 바이트 순서를 의미
  • s는 자료형 short를 의미
  • l은 자료형 long을 의미

6. 인터넷 주소의 초기화와 할당

-문자열 정보를 네트워크 바이트 순서의 정수로 변환(inet_addr)

#include <arpa/inet.h>

in_addr_t inet_addr(const char * string);
 ->성공 시 빅 엔디안으로 변환된 32비트 정수 값, 
	실패 시 INADDR_NODE 반환

“211.214.107.99”와 같이 점이찍힌 10진수로 표현된 문자열을 전달하면, 해당 문자열 정보를 참조해서 IP 주소 정보를 32비트 정수형으로 반환!

 

inet_aton

#include <arpa/inet.h>

int inet_aton(const char * string, struct in_addr * addr);
	 -> 성공 시 1(true), 실패 시 0(false) 반환
  • askii to network
  • string IP 주소 → 32bit 정수형 주소
  • string : 변환할 IP주소 정보를 담고 있는 문자열의 주소 값 전달
  • addr : 변환된 정보를 저장할 in_addr 구조체 변수의 주소값 전달
  • 기능상으로 inet_addr 함수와 동일하다. 다만 in_addr형 구조체 변수에 변환의 결과가 저장된다는 점에서 차이를 보인다.

inet_ntoa

#include <arpa/inet.h>

char * inet_ntoa(struct in_addr adr);
  -> 성공 시 변환된 문자열의 주소 값, 실패 시 -1 반환
  • network to askii
  • inet_aton 함수의 반대기능 제공
  • 네트워크 바이트 순서로 정렬된 정수형 IP주소 정보를 우리가 눈으로 쉽게 인식할 수 있는 문자열의 형태로 변환

 

인터넷 주소의 초기화

  • 서버에서 주소정보를 설정하는 이유
    • IP 211.217.168.13, PORT 9190으로 들어오는 데이터는 내게로 다 보내라!
  • 클라이언트에서 주소정보를 설정하는 이유
    • IP 211.217.168.13, PORT 9190으로 연결을 해라!
Comments