삽질의 현장/- ETC

[삽잡이::Socket] Socket 프로그래밍 구조 (server)

shovelman 2013. 9. 15. 23:59

TCP 서버의 기본적인 함수 호출 순서.

- TCP(Transmission Control Protocol)란? 데이터 전송과정의 컨트롤.

 

 1. 소켓의 생성 (ex) 전화기 구입

 

#include <sys/socket.h>

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

 

- domain : 소켓이 사용할 프로토콜 체계(Protocol Family)전달.

 

프로토콜 체계

- IP_INET( IPv4 인터넷 프로토콜 체계)

- IP_INET6( IPv6 인터넷 프로토콜 체계)

- IP_LOCAL( 로컬 통신을 위한 UNIX 프로토콜 체계)

- IP_PACKET( Low Level 소켓을 위한 프로토콜 체계)

- IP_IPX (IPX 노벨 프로토콜 체계)

- type : 소켓의 데이터 전송방식에 대한 정보 전달.

- SOCK_STREAM( 연결지향성 소켓)

- SOCK_DGRAM( 비 연결지향성 소켓)

- protocol : 두 컴퓨터간 통신에 사용되는 프로토콜 정보 전달.

= 프로토콜의 최종 선택

- socket 함수의 첫 번째, 두 번째 전달인자를 통해서도 충분히 원하는 유형의 소켓을 생성할 수 있다. 따라서 대부분의 경우, 세 번째 인자로 그냥 0을 넘겨줘도 무방하다.

 

2. 소켓에 인터넷 주소 할당하기 (ex) 전화번호 할당

 

#include <sys/socket.h>

int bind(int sockfd, struct socketaddr *myaddr, socklen_t addrlen);

 

-sockfd : 주소정볼(IP와 PORT를) 할당할 소켓의 파일 스크립터.

-myaddr : 할당하고자 하는 주소정보를 지니는 구조체 변수의 주소 값.

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

struct sockaddr_in

{

sa_family     sin_family // 주소 체계 (Adress Family)

unit16_t     sin_port // 16비트 TCP/UDP PORT번호

struct in_addr     sin_addr; //32비트 IP주소

char     sin_zero[8]; // 사용되지 않음.

}

struct in_addr

{

int_addr_t     s_addr; //32비트 IPv4 인터넷 주소

}

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

-sin_family

- AF_INET ( IPv4 인터넷 프로토콜에 적용하는 주소체계)

- AF_INET6 (IPv6 인터넷 프로토콜에 적용하는 주소체계)

- AF_LOCAL (로컬 통신을 위한 유닉스 프로토콜의 주소체계)

- sin_port

-16 비트 PORT번호를 저장한다. PORT 번호를 저장한다는 사실보다 네트워크 바이트 순서로 저장해야 한다.

- sin_addr

- 32 비트 IP 주소정보를 저장한다. 네트워크 바이트 순서로 저장해야 한다.

- 이 멤버를 이해하기 위해서는 in_addr구조체도 봐야하는데 in_addr은 32비트 정수자료형으로 인식한다. 

- sin_zero

 - 구조체 sockaddr_in의 크기를 구조체 sockaddr와 일치시키기 위해삽입된 멤버.

+네트워크 바이트 순서

- 네트워크를 통해서 데이터를 전송할 때에는 통일된 기준으로 데이터를 전송해야한다.

- CPU에 따라서 메모리 공간에 저장하는 방식이 달라질 수 있다. 따라서 이 부분을 고려하지 않고서 데이터를 송수신한다면 문제가 발생할 수 있다.

- 바이트 순서의 변환

unsigned short htons(unsigned short); ex) host to network

unsigned short ntohs(unsigned short);

unsigned long htonl(unsigned long);

unsigned short ntohl(unsigned long);

+ 인터넷 주소의 초기화

struct socket_in addr;

memset(&addr, 0, sizeof(addr)); // 구조체 변수 addr의 모든 멤버 0으로 초기화

addr.sin_family = AF_INET; // 주소체계 지정

addr.sin_addr.s_addr = inet_addr(INADDR_ANY); // 문자열 기반의 IP주소 초기화

addr.sin_port = htons(atoi(argc[2])); // 문자열 기반의 PORT번호 초기화

-memset 함수는 동일한 값으로 바이트 단위 초기화를 할 때 호출하는 함수이다.

*INADDR_ANY : 소켓의 IP주소를 INADDR_ANY로 초기화 할 경우 소켓이 동작하는 컴퓨터의 IP주소가 자동으로 할당되기 때문에 IP주소를 직접 입력하는 수고를 덜 수 있다. 컴퓨터 내에 두 개 이상의 IP를 할당받아서 사용하는 경우, 할당 받은 IP중 어떤 주소를 통해서 데이터가 들어오더라도 PORT번호만 일치하면 수신할 수 있게 된다.

- addrlen : 두 번째 인자로 전달된 구조체 변수의 길이정보.

 

3. 연결요청 대기상태로의 집입 (ex) 케이블선 연결

 

#include <sys/socket.h>

int listen(int sock, int backlog);

 

- sock : 연결요청 대기상태에 두고자 하는 소켓의 파일 스크립터 전달, 이 함수의 인자로 전달된 디스크립터의 소켓이 서버 소켓(리스닝 소켓)이 된다.

(ex) 연결요청을 맞이하는 , 일종의 문지기 or 문의 역할을 함.

- backlog : 연결요청 대기 큐(Queue)의 크기정보 전달, 5가 전달되면 큐의 크기가 5가되어 클라이언트의 연결요청을 5개까지 대기시킬 수 있다.

 

4. 클라이언트의 연결요청 수락 (ex) 전화 받기

 

#include <sys/socket.h>

int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);

 

- sock : 서버 소켓의 파일 디스크립터 전달

- addr : 연결요청 한 클라이언트의 주소정보를 담을 변수의 주소 값 전달, 함수호출이 완료되면 인자로 전달된 주소의 변수에는 클라이언트의 주소정보가 채워진다.

- addrlen : 두 번째 매개변수 addr에 전달된 주소의 변수 크기를 바이트 단위로 전달, 단 크기정보를 변수에 저장한 다음에 변수의 주소 값을 전달한다. 그리고 함수호출이 완료되면 크기정보로 채워져 있던 변수에는 클라이언트의 주소정보 길이가 바이트 단위로 계산되어 채워진다.

- accept 함수는 '연결요청 대기 큐'에서 대기중인 클라이언트의 연결요청을 수락하는 기능의 함수이다.

- accept 함수는 호출성공 시 내부적으로 데이터 입출력에 사용할 소켓을 생성하고, 그 소켓의 파일 디스크립터를 반환한다. 소켓은 자동 생성되어, 연결요청을 한 클라이언트 소켓에 연결까지 이루어 진다.

 

<참조 : 열혈 TCP/IP 소켓 프로그래밍>