Hello
반갑습니다 😉 hello
반갑습니다 😉 hello
클라이언트 프로그램 클라이언트 프로그램은 1. 소켓 생성, 2. 서버의 인터넷 주소 설정, 3. 연결 요청, 4. 통신(읽기/쓰기), 5. 연결 종료 순서로 진행된다. 소켓 생성 1 2 3 4 5 6 7 8 9 10 11 12 13 #include <sys/types.h> #include <sys/socket.h> int main() { ... int ssock; if((ssock # socket(PF_INET, SOCK_STREAN, IPPROTO_TCP)) < 0) { perror("socket error : "); exit(1); } ... } 소켓을 생성한다. socket이라는 함수에 인자값을 주어 소켓 생성에 성공하면, 0보다 큰값의 디스크립션을 반환한다. 보통 3 이상의 값이 반환된다. 0은 표준입력, 1은 표준출력, 2는 표준에러로 예약되어 있다. 소켓 생성에 실패하면 음수값의 디스크립션을 반환한다. socket 함수 소켓 지정자 socket(인자 도메인, 소켓의 형태, 프로토콜의 종류) 해당 소켓을 생성하고 소켓의 디스크립션을 반환한다. 즉, 인자 값을 받아 소켓을 생성한 후에 해당 소켓의 지정자를 반환한다. 1 2 3 4 #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol) 인자 도메인 (domain) 네트워크의 종류를 나타낸다. (노벨IPX, ATM, X.25, IPv6, TCP/IP 등) 네트워크의 종류에 따라 프로토콜이 다르게 구성되어 있으며, 리눅스에서는 도메인이라는 개념을 사용해 구분한다. TCP/IP는 PF_INET 프로토콜 패밀리에 정의되어 있다. PF_INET은 주소값이다. IP주소를 사용한다. 프로토콜 패밀리는 <sys/socket.h> 에서 정의한다. 로컬 소켓을 사용해 소켓을 내부 프로세스가 통신하는 용도로 사용하려면 PF_UNIX나 PF_LOCAL를 사용한다. 내부 프로세스 통신을 위해 사용할 때는 데이터 전송을 위한 파일 경로가 들어가게 된다. 프로토콜 패밀리 설명 PF_UNIX 유닉스 도메인 소켓 PF_LOCAL PF_UNIX 소켓의 포직스 표현 PF_INET 인터넷 프로토콜(TCP/IP) PF_IPX 노벨 IPX PF_AX25 아마추어 라디오 AX.25 PF_APPLETALK 애플토크 DDP PF_INET6 IPv6 프로토콜 PF_ROSE 아마추어 라디오 X.25 PLP PF_X25 X.25 프로젝트를 위해 예약 PF_IRDA 적외선(IrDA) 소켓 PF_NETBEUI 802.2LLC 프로젝트를 위해 예약 PF_LLC 리눅스 LLC PF_BLUETOOTH 블루투스 소켓 소켓의 형태 (type) 소켓의 형태는 소켓의 연결 형식을 정의한다. PF_INET에서 주로 사용하는 소켓 연결 형식에는 SOCK_STREAM, SOCK_DGRAM, SOCK_RAW가 있다. SOCK_STREAM : TCP를 통해 전송되는 신뢰성 있는 연결 SOCK_DGRAM : UDP를 통해 전송되는 신뢰성 없는 연결. SOCK_RAW : 헤더를 직접 만들어서 사용해야 하는 연결 형식. SOCK_STREAM, SOCK_DGRAM의 헤더는 운영체제에서 자동으로 만들어준다. 프로토콜의 종류 (protocol) 소켓에서 사용될 프로토콜을 지정한다. 프로토콜 설명 0 도메인과 소켓의 형태에 따른 기본 프로토콜이 자동 결정된다 IPPROTO_IP IPPROTO_TCP TCP 프로토콜 사용 IPPROTO_UDP UDP 프로토콜 사용 IPPROTO_RAW IPPROTO_ICMP IPPROTO_ICMPV6 서버의 인터넷 주소 설정 1 2 3 4 5 6 7 8 ... struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family # AF_INET; /* # PF_INET */ server_addr.sin_addr.s_addr # inet_addr("127.0.0.1"); server_addr.sin_port # htons(2217); ... 접속할 서버의 주소를 설정한다. 프로토콜 패밀리와 IP 주소, Port 주소를 각각 정해준다. 네트워크 바이트 오더를 적용해야 하기 때문에 IP 주소와 Port 주소는 inet_addr(), htons() 함수를 통해서 값을 넣어주어야 한다. sockaddr_in 구조체는 INET 인터넷 프로토콜의 TCP 헤더를 구성한다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 typedef unsigned short sa_family_t; struct in_addr { __u32 s_addr; }; #define __SOCK_SIZE__ 16 struct sockaddr_in { sa_family_t sin_family; /*주소패밀리*/ unsigned short int sin_port; /*포트번호*/ struct in_addr sin_addr; /*IP주소*/ unsigned char __pad[__SOCK_SIZE - sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in_addr)]; /* Pad to size of 'struct sockaddr' */ }; inet_addr 함수 이진 바이너리 형식의 IP 주소 inet_addr(문자 형식의 IP 주소) 문자 형식의 IP 주소를 네트워크 바이트 오더를 적용한 이진 바이너리 코드로 바꾸어 변환한다. 리틀 엔디안(Little Endian)과 빅 엔디안(Big Endian) 이라는 바이트 오더의 개념을 알아야 한다. 네트워크 프로토콜 표준에서 사용하는 바이트 오더는 빅 엔디안이다. x86 호환 아키텍처에서는 리틀 엔디안을 사용한다. 1 2 3 4 5 #include <sys/types.h> #include <netinet/in.h> #include <arpa/inet.h> unsigned long int inet_addr(const char *cp) htons 함수 네트워크 바이트 오더가 적용된 이진 바이너리 16비트 값 htons (16비트 변수 값) 16비트의 unsigned short형 숫자 값에 네트워크 바이트 오더를 적용한 후 반환한다. 1 2 3 #include <netinet/in.h> uint16_t htons(uint16_t hostshort) 연결 요청 1 2 3 4 5 6 7 ... clen # sizeof(server_addr); if(connect(ssock, (struct sockaddr *)&server_addr, clen) < 0) { peror("connect error :"); exit(1); } 소켓 생성이 완료되면 생성된 소켓을 이용하여 서버에 연결해야 한다. 이때 connect() 함수를 사용한다. connect 함수 리턴 값 connect(소켓 디스크립션, 서버의 IP 주소와 포트번호, 길이) 소켓 연결을 시작한다. 생성된 소켓과 서버의 정보를 이용해서 해당 서버에 연결한 후 결과값을 리턴한다. 1이면 성공, -1이면 실패를 의미한다. 1 2 3 4 #include <sys/types.h> #include <sys/socket.h> int connect(int sockfd, const struct sockaddr *serv_addr, soclen_t addrlen); 통신(읽기/쓰기) 1 2 3 4 5 6 memset(buf, 0, MAXBUF); if(read(ssock, buf, MAXBUF) <# 0) { perror("read error :"); exit(1); } 서버에서 데이터를 읽어오려면 read() 함수를 사용한다. 데이터를 수신한 후 buf에 저장한다. read 함수 읽은 값의 길이 read(파일 디스크립터, 읽은 데이터를 저장할 버퍼, 읽을 데이터 최대 길이) 지정된 파일 디스크립터에서 데이터를 읽어서 지정된 버퍼에 데이터를 넣은 후 읽은 데이터의 길이를 반환한다. 오류가 발생하면 -1을 반환한다. 네트워크 프로그래밍에서 파일 디스크립터에 해당하는 것이 소켓 디스크립터이다. 1 2 3 #include <unistd.h> ssize_t read(int fd, void *buf, size_t count) 연결 종료 1 close(ssock); close 함수 성공 여부 반환 close(파일 디스크립터) close 함수는 파일 디스크립터를 닫는다. 닫힌 파일 디스크립터는 더 이상 참조되거나 사용될 수 없다. 닫기에 성공하면 0을 반환하고 오류가 발생하면 -1을 반환한다. 1 2 3 #include <unistd.h> int close(int fd) 서버 프로그램 서버 프로그램은 1. 소켓 생성, 2. 인터넷 주소 부여, 3. 연결 수신 대기, 4. 연결 수신, 5. 통신(읽기/쓰기), 6. 연결 수신 대기(이후 과정 반복) 순서로 진행된다. ...