얇지만 얇지 않은 TCP/IP 소켓 프로그래밍 C 2판

Slides:



Advertisements
Similar presentations
Network Programming:
Advertisements

이름과 주소 변환 DNS 해결사 함수 정보통신대학 컴퓨터 학과 도희성 Chap. 11.
TCP 서버/클라이언트 동작 원리 - (1) TCP 서버/클라이언트 예 웹 서버 웹 클라이언트 웹 클라이언트
Java Socket 통신 이개혁 정대준.
Understanding of Socket and File I/O
TCP/IP Network Experimental Programming [IPv6에 의한 통신 실험]
13장 소켓.
TCP/IP Socket Cover Slide 조태문.
Network Lab. Young-Chul Hwang
TCP/IP 소켓 프로그래밍 - C 버전 중에서
Department of Computer Engineering
4장. 소켓 유형과 프로토콜 Network Lab. 이 원 구 1.
PHP 웹 프로그래밍 (PHP Web Programming) 네트워크 프로그래밍 문양세 강원대학교 IT대학 컴퓨터과학전공.
TCP/IP Socket Cover Slide 조태문.
인공지능실험실 석사 2학기 김승겸 TCP/IP Socket Programming… 제 10장 멀티태스킹 기반의 서버구현 인공지능실험실 석사 2학기 김승겸
Chapter 03. 소켓 주소 구조체 다루기.
Department of Computer Engineering
얇지만 얇지 않은 TCP/IP 소켓 프로그래밍 C 2판
TCP Client/Server Program
Network Lab. Seoung Hyeon, Lee
컴퓨터 네트워크 PART 03 프로그래밍 (chapter 01 Socket 프로그래밍) 임효택
호스트이름과 네트워크이름 찾기 (Hostname and Network Name Lookups)
Internet Address Conversion Functions
3장. 소켓 주소 구조체 다루기 소켓 주소 구조체의 정의와 초기화 방법을 익힌다.
6장 비연결형 지향 프로토콜 Database Lab 강 우 석.
11 소켓 프로그래밍 기초.
인터넷 주소 변환 School of Electronics and Information. Kyung Hee University.
14장 소켓.
제 12장 I/O멀티플렉싱(Multiplexing)
Using Standard I/O on Sockets
Department of Computer Engineering
Chapter 02. 윈도우 소켓 시작하기.
한남대학교 컴퓨터공학과 컴퓨터 네트워크 실험실
데이터베이스 실험실 석사 2학기 김기훈 TCP/IP Socket Programming… 제 17장 멀티쓰레드 기반의 서버구현 데이터베이스 실험실 석사 2학기 김기훈
Department of Computer Engineering
인공지능실험실 석사 2학기 이희재 TCP/IP Socket Programming… 제 7장 소켓 연결의 우아한 종료 인공지능실험실 석사 2학기 이희재
(Web Programming & Practice)
Socket Address Structure and Byte Ordering Functions
Department of Computer Engineering
Socket Address Structure and Byte Ordering Functions
Homework 6… 12월 2일(금) 11:59pm까지 자신의 이름과 학번을 출력해 주는 유닉스/리눅스 네트워크 소켓 서버 프로그램 과 클라이언트 프로그램 을 작성해 보세요 참고 (실습1) Hello 프로그램 helloserver.c helloclient.c 컴파일.
Internet Address Conversion Functions
7장. UDP 서버-클라이언트 UDP 서버-클라이언트의 기본 구조와 동작 원리를 이해한다.
Chapter 8 연결형 프로토콜 서버 발표자 : SE Lab 황 성 하
Department of Computer Engineering
Advanced Socket Programming
School of Electronics and Information. Kyung Hee University.
Department of Computer Engineering
Chapter 03. 소켓 주소 구조체 다루기.
Internet Address Conversion Functions
7장. UDP 서버-클라이언트 UDP 서버-클라이언트의 기본 구조와 동작 원리를 이해한다.
소켓의 옵션 School of Electronics and Information. Kyung Hee University.
Internet Address Conversion Functions
School of Electronics and Information. Kyung Hee University.
1 학습 목표 네트워크의 기초 네트워크 관련 기초 용어를 익힌다.
네트워크 프로그래밍의 이해 School of Electronics and Information.
윤성우의 열혈 TCP/IP 소켓 프로그래밍 윤성우 저 열혈강의 TCP/IP 소켓 프로그래밍 개정판
Chapter 16 Socket Interface.
Department of Computer Engineering
Department of Computer Engineering
윤성우의 열혈 TCP/IP 소켓 프로그래밍 윤성우 저 열혈강의 TCP/IP 소켓 프로그래밍 개정판
인터넷 주소변환 School of Electronics and Information. Kyung Hee University.
제 16장 입력과 출력 스트림의 완벽 분리 TCP/IP Socket Programming… 데이터베이스 실험실
Department of Computer Engineering
인공지능실험실 박사 1학기 장성만 TCP/IP Socket Programming… 제 8장 도메인 이름과 인터네 주소 인공지능실험실 박사 1학기 장성만
실습과제 1번 생성된 파일 basic.txt를 프로젝트 폴더에서 메모장으로 열고 내용을 확인
argc, argv 의 사용방법 #include <stdio.h>
Chapter 03. 소켓 주소 구조체 다루기.
소켓의 생성과 프로토콜의 설정 School of Electronics and Information.
Department of Computer Engineering
Presentation transcript:

얇지만 얇지 않은 TCP/IP 소켓 프로그래밍 C 2판 (TCP/IP Sockets in C 2/e, Morgan Kaufmann) 마이클 도나후(Michael J. Donahoo) 케네스 칼버트(Kenneth L. Calvert)

Chapter 03 Of Names and Address Families 제 3장 도메인 네임 서비스와 주소 패밀리(IPv4-IPv6 서비스) 3.1 도메인 네임 주소를 숫자 주소로 매핑하기 3.2 IP 버전에 무관한 주소-범용 코드의 작성 3.3 숫자 주소에서 도메인 네임 주소 획득하기

변환(도메인 이름IP주소) 함수1 #include <netdb.h> struct hostent* gethostbyname(const char* name);

int main(int argc, char **argv) { struct hostent *host; struct sockaddr_in addr; int i; memset(&addr, 0, sizeof(addr)); addr.sin_addr.s_addr=inet_addr(argv[1]); host=gethostbyaddr((char*)&addr.sin_addr, 4, AF_INET); printf("Officially name : %s \n\n", host->h_name); puts("Aliases-----------"); for(i=0;host->h_aliases[i]; i++){ puts(host->h_aliases[i]); } printf("Address Type : %s \n", host->h_addrtype==AF_INET? "AF_INET":"AF_INET6"); puts("IP Address--------"); for(i=0; host->h_addr_list[i]; i++){ puts( inet_ntoa( *(struct in_addr*)host->h_addr_list[i] )); return 0;

Struct hostent struct hostent { char* h_name; char **h_aliases; int h_addrtype; int h_length; char **h_addr_list; } Official name Alias list Host address type Length of address List of address

Struct hostent 구조체 변수 in_addr 구조체

변환(IP주소도메인 이름) 함수2 #include <netdb.h> in_addr 구조체 #include <netdb.h> struct hostent* gethostbyaddr(const char* addr, int len, int type);

int main(int argc, char **argv){ int i; struct hostent *host; host=gethostbyname(argv[1]); printf("Officially name : %s \n\n", host->h_name); puts("Aliases-----------"); for(i=0;host->h_aliases[i]; i++){ puts(host->h_aliases[i]); } printf("Address Type : %s \n", host->h_addrtype==AF_INET? "AF_INET":"AF_INET6"); puts("IP Address--------"); for(i=0; host->h_addr_list[i]; i++){ puts( inet_ntoa( *(struct in_addr*)host->h_addr_list[i] )); return 0;

기존 IPv4전용, IPv6전용 코드의 취약성 전용주소 코드(IPv4 only, IPv6 only)의 의미 IPv4 전용 코드는 IPv4 형식의 IPv4만 취하고 IPv6 전용 코드는 IPv6 주소 형식만 취한다. 상대방의 IP 주소 버전을 모를 경우, 두 가지 버전을 모두 준비해야 함 IPv4, IPv6 범용 코드 실행 시간에 주소 버전을 확인하여 IPv4, IPv6 주소 타입에 관계없이 동작하게 하는 코드 내부적으로는 이름-주소 변환 함수인 getaddrinfo() 함수를 사용하여 동작 getaddrinfo()는 /etc/hosts, DNS 시스템에 질의하여 가능한 모든 IPv4(A record), IPv6(AAAA record) 주소를 리스트화 하여 반환 이름 주소-> IP주소로 변환하는 네임 시스템 API 하나의 코드로 IPv4, IPv6에 모두 대비

도메인 네임 시스템 도메인 네임 시스템(Domain Name System)이란? 인터넷에서 호스트를 구분하기 위하여 IP 대신 네임(이름 주소)을 사용할 수 있도록 하는 서비스 네임주소 - IP 주소를 매핑하는 DB를 활용하여 서비스 로컬 DB 활용 : /etc/host(linux) or windows/system32/dirvers/etc/hosts(windows) 분산 DB 활용 : DNS(domain Name Service)

도메인 네임 시스템 장점 읽기, 쓰기, 기억의 편의성 고정된 주소 값 제공 부하 분배(load balancing) 특징 인터넷에서 호스트는 IP 주소로 구분이 가능 숫자 형태보다, 계층화된 이름 주소가 더 좋은 사용 편의성을 제공 고정된 주소 값 제공 IP 주소는 특성상 위치 이동 시 변경되나 네임 주소는 이를 클라이언트에 숨겨주어 다른 사람에게 항상 같은 주소를 제공한다 부하 분배(load balancing) 하나의 네임주소에 여러 개의 IP 주소 매핑이 가능하며 결과적으로 서로 다른 물리적인 서버가 클라이언트의 요청에 대응하게 할 수 있다 특징 DNS가 TCP/IP 프로그래밍의 필수요소는 아님

IPv4, IPv6 통합 네임 서비스 API int getaddrinfo (const char *hostStr, const char *serviceStr, const struct addrinfo *hints, struct addrinfo **results) 기능 : 프로토콜 버전에 상관없이 네임 주소 -> IP 주소 해석을 해주는 함수 호스트 주소(IP 혹은 도메인 네임)와 서비스(서비스 이름 혹은 port 번호)을 전달하면 위 정보에 연결가능한 주소 정보(addrinfo) 리스트를 반환한다 호스트 연결 시 도메인 네임, IPv4 주소, IPv6 주소를 모두 사용가능 hostStr: 네임 주소 혹은 IP 주소 serviceStr: 서비스 이름 혹은 port 번호 hints: 반환을 원하는 주소 정보의 형태 IPv4 및 IPv6 선택, 프로토콜 종류 등의 선택이 가능 results: 반환되는 주소들의 결과 리스트

IPv4, IPv6 통합 네임 서비스 API struct addrinfo{ int ai_flags;// 제어 정보 해설을 위한 flag int ai_family;//Family:AF_INET,AF_INET6,AF_UNSPEC int ai_socktype;//Socket type:SOCK_STREAM,SOCK_DGRAM int ai_protocol;//Protocol:0(default)or IPPROTO_XXX socklen_t ai_addrlen;// 소켓 주소인 ai_addr의 길이 struct sockaddr *ai_addr;//소켓 주소 char *ai_canonname;//Canonical 네임 struct addrinfo *ai_next;//연결리스트에서 다음 addrinfo의 위치 };

네임 Resolve 예제 (1/2) GetAddrInfo.c 1 // ... include files here . 7 int main(int argc, char *argv[]) { 8 if (argc != 3) // 인자의 개수가 알맞은지 확인 10 DieWithUserMessage("Parameter(s)", "<Address/Name> <Port/Service>"); 11 12 char *addrString = argv[1]; // 서버의 IP/도메인 네임 13 char *portString = argv[2]; // 서버의 포트/ 서비스 이름 14 15 // 반환 받을 주소의 형태를 지정 16 struct addrinfo addrCriteria; // 주소 형태 구조체 17 memset(&addrCriteria, 0, sizeof(addrCriteria)); // ‘0’으로 초기화 18 addrCriteria.ai_family = AF_UNSPEC; //임의의 주소 버전 반환(IPv4, IPv6모두) 19 addrCriteria.ai_socktype = SOCK_STREAM; // 스트림 프로토콜 반환 요청 20 addrCriteria.ai_protocol = IPPROTO_TCP; // TCP 프로토콜 반환 요청 21 22 // 주어진 주소/서비스에 대한 주소 반환을 요청 23 struct addrinfo *addrList; // 반환 받을 주소가 저장될 리스트 24

네임 Resolve 예제 (2/2) 25 int rtnVal = getaddrinfo(addrString, portString, &addrCriteria, &addrList); 26 if (rtnVal != 0) 27 DieWithUserMessage("getaddrinfo() failed", gai_strerror(rtnVal)); 28 29 // 반환된 주소 정보를 출력 30 for (struct addrinfo *addr = addrList; addr != NULL; addr = addr->ai_next) { 31 PrintSocketAddress(addr->ai_addr, stdout); 32 fputc('\n', stdout); 33 } 34 35 freeaddrinfo(addrList); // getaddrinfo()에 의해 할당된 메모리를 해제 36 37 exit(0); 38 }

네임 Resolve 실행 예시 <= 로컬 DB resolve <= 분산 DB(DNS) resolve <= IPv6 resolve <= 분산 DB(DNS) resolve, 등록된 모든 IP반환

getaddrinfo()를 활용한 주소 범용(Generic) 코드 주소 버전(IPv4, IPv6)에 관계없이 동작하는 코드 기존 코드의 문제점 주소 구조체를 지정하여 사용할 경우, 사용자의 각기 다른 주소 버전의 입력에 유연하게 대처하지 못함 IPv4 코드는 IPv4 주소만 처리하고 IPv6 코드는 IPv6 주소만 처리 이유 : 각 주소 버전에 맞는 구조체가 코드에 묶임 해결 방안 addrInfo를 처리하는 getaddrinfo 함수를 사용하여 resolving한 결과를 처리 사용자 주소 입력(IPv4 or IPv6 or DNS) getaddrinfo를 수행하여 가용한 주소 전부 반환 각 개별 주소에 대하여 연결 혹은 연결 대기 시도

SetupTCPClientSocket(): 서버와 연결을 수행하고 연결된 소켓을 반환 //서버 호스트의 주소(IPv4, IPv6, DNS) 및 서비스 이름을 입력하면 서버와 연결된 소켓을 반환 int SetupTCPClientSocket(const char *host, const char *service) { struct addrinfo addrCriteria; // 반환받을 주소의 형태를 담을 구조체 memset(&addrCriteria, 0, sizeof(addrCriteria)); // ‘0’으로 초기화 addrCriteria.ai_family = AF_UNSPEC; // IPv4와 IPv6 모두 반환 요청 addrCriteria.ai_socktype = SOCK_STREAM; // 스트리밍 소켓만 반환 요청 addrCriteria.ai_protocol = IPPROTO_TCP; // TCP 프로토콜만 반환 요청 struct addrinfo *servAddr; // 서버의 주소를 반환 받을 구조 구조체 int rtnVal = getaddrinfo(host, service, &addrCriteria, &servAddr); if (rtnVal != 0) DieWithUserMessage("getaddrinfo() failed", gai_strerror(rtnVal)); int sock = -1; for (struct addrinfo *addr = servAddr; addr != NULL; addr = addr->ai_next) { // TCP를 이용하여 안정된 소켓을 생성 sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if (sock < 0) continue; // 소켓 생성 실패, 다음 주소로 시도 // 에코 서버에 연결 시도 if (connect(sock, addr->ai_addr, addr->ai_addrlen) == 0) break; // 소켓 연결 성공, 반복문을 탈출하고 소켓을 반환 close(sock); // 소켓 연결 실패, 다음 주소로 다시 시도 sock = -1; } freeaddrinfo(servAddr); // getaddrinfo()의 결과로 반환된 메모리를 회수 return sock;

SetupTCPServerSocket(): 서버의 주소를 획득하고 bind 및 listen수행(1/2) 1 static const int MAXPENDING = 5; // 최대 연결 대기 수 2 3 int SetupTCPServerSocket(const char *service) { 4 // 서버 주소 구조체의 생성 5 struct addrinfo addrCriteria; 6 memset(&addrCriteria, 0, sizeof(addrCriteria)); 7 addrCriteria.ai_family = AF_UNSPEC; // IPv4, IPv6 주소 모두 받아들임 8 addrCriteria.ai_flags = AI_PASSIVE; 9 addrCriteria.ai_socktype = SOCK_STREAM; 10 addrCriteria.ai_protocol = IPPROTO_TCP; 11 12 struct addrinfo *servAddr; 13 int rtnVal = getaddrinfo(NULL, service, &addrCriteria, &servAddr); 14 if (rtnVal != 0) 15 DieWithUserMessage("getaddrinfo() failed", gai_strerror(rtnVal)); 16 17 int servSock = -1; 18 for (struct addrinfo *addr = servAddr; addr != NULL; addr = addr->ai_next) { 19 // TCP 소켓 생성 20 servSock = socket(servAddr->ai_family, servAddr->ai_socktype, 21 servAddr->ai_protocol); 22 if (servSock < 0) 23 continue; // 소켓 생성 실패, 다음주소로 재시도

SetupTCPServerSocket(): 서버의 주소를 획득하고 bind 및 listen수행(2/2) 25 26 if ((bind(servSock, servAddr->ai_addr, servAddr->ai_addrlen) == 0) && 27 (listen(servSock, MAXPENDING) == 0)) { 28 // 소켓의 지역 주소를 출력 29 struct sockaddr_storage localAddr; 30 socklen_t addrSize = sizeof(localAddr); 31 if (getsockname(servSock, (struct sockaddr *) &localAddr, &addrSize) < 0) 32 DieWithSystemMessage("getsockname() failed"); 33 fputs("Binding to ", stdout); 34 PrintSocketAddress((struct sockaddr *) &localAddr, stdout); 35 fputc('\n', stdout); 36 break; 37 } 38 39 close(servSock); // 소켓을 종료하고 다시 시도 40 servSock = -1; 41 } 42 43 44 freeaddrinfo(servAddr); 45 46 return servSock; 47 }

AcceptTCPConnection(): 클라이언트의 연결을 처리 // 클라이언트의 연결을 처리하고 연결된 소켓을 반환 1 int AcceptTCPConnection(int servSock) { 2 struct sockaddr_storage clntAddr; // 클라이언트 주소 3 // 클라이언트 주소 구조체 길이 설정(입출력 파라미터) 4 socklen_t clntAddrLen = sizeof(clntAddr); 5 6 // 클라이언트의 연결을 대기 7 int clntSock = accept(servSock, (struct sockaddr *) &clntAddr, &clntAddrLen); 8 if (clntSock < 0) 9 DieWithSystemMessage("accept() failed"); 10 11 // 이때 clntSock는 클라이언트에 연결됨 12 13 fputs("Handling client ", stdout); 14 PrintSocketAddress((struct sockaddr *) &clntAddr, stdout); 15 fputc('\n', stdout); 16 17 return clntSock; 18 }

IPv4-IPv6 상호 연결 상호 연결 조건 듀얼 스택(dual stack) 시스템 IPv4 전용 프로그램의 경우

소켓 연결의 우아한 종료 저자 윤 성 우 ripeness21@empal.com

입력 및 출력 스트림 입력 스트림 : 데이터 수신을 위한 스트림 출력 스트림 : 데이터 전송을 위한 스트림 출력 스트림

Close 함수의 호출 : 입력 출력 스트림 완전 종료. 2. 일방적인 방식의 완전종료는 경우에 따라서 문제가 될 수 있다. 소켓 연결 종료의 문제점 Close 함수의 호출 : 입력 출력 스트림 완전 종료. 2. 일방적인 방식의 완전종료는 경우에 따라서 문제가 될 수 있다.

Half-close : 입력 및 출력 스트림 중 하나의 스트림만 종료하는 행위.

Half-close 기능의 함수 #include <sys/socket.h> int shutdown(int s, int how); 상수값 모드 정의 SHUT_RD 입력 스트림 종료 1 SHUT_WR 출력 스트림 종료 2 SHUT_RDWR 입 출력 스트림 종료

출력 스트림의 종료의 필요성 출력 스트림을 종료하게 되면, 연결되어 있던 호스트로 EOF 메시지 전달. EOF 전송 시, 상대 호스트의 데이터 수신 함수(read, recv)는 0을 리턴.