1 / 28

Chapter 04. TCP 서버 / 클라이언트

Chapter 04. TCP 서버 / 클라이언트. * 학습목표. TCP 서버 / 클라이언트의 기본 구조 와 동작 원리 를 이해함 TCP 애플리케이션 작성에 필요한 소켓 함수 를 익힘 애플리케이션 프로토콜의 필요성 을 이해 하고 , 메시지 설계 기법 을 익힘. TCP 서버 / 클라이언트 동작 원리 - (1). TCP 서버 / 클라이언트 예. GET / HTTP/1.1 Accept: image/gif,. <HTML> <HEAD>...</HEAD>. 웹 서버. 웹 클라이언트.

Download Presentation

Chapter 04. TCP 서버 / 클라이언트

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Chapter 04. TCP 서버/클라이언트 * 학습목표 • TCP 서버/클라이언트의 기본 구조와 동작 원리를 이해함 • TCP 애플리케이션 작성에 필요한 소켓 함수를 익힘 • 애플리케이션프로토콜의 필요성을 이해하고, 메시지 설계 기법을 익힘

  2. TCP 서버/클라이언트 동작 원리 - (1) • TCP 서버/클라이언트 예 GET / HTTP/1.1 Accept: image/gif, ... <HTML> <HEAD>...</HEAD>... 웹 서버 웹 클라이언트 웹 클라이언트

  3. TCP 서버 TCP 클라이언트 listen 네트워크 accept connect recv send send recv TCP 서버/클라이언트 동작 원리 - (2) • TCP 서버/클라이언트 동작 방식 • TCP 서버/클라이언트 동작 방식 ① 서버는 먼저 실행하여 클라이언트가 접속하기를 기다린다(listen). ② 클라이언트가 서버에게 접속(connect)하여 데이터를 보낸다(send). ③ 서버는 클라이언트 접속을 수용하고(accept), 클라이언트가 보낸 데이터를 받아서(recv) 처리한다. ④ 서버는 처리한 데이터를 클라이언트에게 보낸다(send). ⑤ 클라이언트는 서버가 보낸 데이터를 받아서(recv) 자신의 목적에 맞게 사용한다.

  4. TCP 서버 대기 TCP 서버 클라이언트 접속 TCP 클라이언트 #1 TCP 서버/클라이언트 동작 원리 - (3) • TCP 서버/클라이언트 동작 원리 (1) 서버는 소켓을 생성 후 클라이언트를 기다림 포트번호 : 9000 (2) 클라이언트 접속함 (연결설정)

  5. TCP 서버 대기 통신 통신 TCP 서버 TCP 클라이언트 #1 TCP 클라이언트 #2 대기 통신 TCP 클라이언트 #1 TCP 서버/클라이언트 동작 원리 - (4) • TCP 서버/클라이언트 동작 원리(계속) (3) 클라이언트 새로운 소켓을 생성 (4) 1명의 클라이언트가 새로 접속하여 새로운 소켓을 생성한 상태

  6. TCP 서버 fgets() send() recv() printf() TCP 클라이언트 TCP 서버 . . . . . . 대기 printf() recv() send() TCP 클라이언트 #1 . . . . . . TCP 클라이언트 #n TCP 서버/클라이언트 동작 원리 - (5) • TCP 서버/클라이언트 동작 원리(계속) (5) N명의 클라이언트가 새로 접속하여 새로운 소켓을 생성한 상태 (1 : 1 통신 구조) • TCP 서버/클라이언트 예제 동작 방식 화면 화면 데이터 데이터

  7. 네트워크 서버 클라이언트 애플리케이션 지역 IP 주소 지역 IP 주소 지역 포트 번호 지역 포트 번호 원격 IP 주소 원격 IP 주소 운영체제 원격 포트 번호 원격 포트 번호 ••• ••• TCP 서버/클라이언트 분석 • TCP/IP 소켓 통신을 위해 필요한 요소 ① 프로토콜 • 소켓을 생성할 때 결정 ② 지역(local) IP 주소와 지역 포트 번호 • 서버 또는 클라이언트 자신의 주소 ③ 원격(remote) IP 주소와 원격 포트 번호 • 서버 또는 클라이언트가 통신하는 상대방의 주소 • 소켓 데이터 구조체

  8. TCP 서버 TCP 클라이언트 socket() socket() bind() listen() 네트워크 accept() connect() recv() send() send() recv() closesocket() closesocket() TCP 서버 함수 - (1) • TCP 서버 함수

  9. TCP 서버 함수 - (2) • bind() 함수 • 서버의 지역 IP 주소와 지역 포트 번호를 결정 int bind ( SOCKET s, // 소켓생성 결과값 const struct sockaddr* name, // 소켓구조체(주소, 포트번호, 프로토콜타입) int namelen // 소켓구조체 크기 ) ; 성공: 0, 실패: SOCKET_ERROR • bind() 함수 사용 예 (예제 1 참조) 050 SOCKADDR_IN serveraddr; 051 ZeroMemory (&serveraddr, sizeof(serveraddr)); 052 serveraddr.sin_family = AF_INET; 053 serveraddr.sin_port = htons(9000); 054 serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); 055 retval = bind(listen_sock, (SOCKADDR *)&serveraddr, sizeof(serveraddr)); 056 if(retval == SOCKET_ERROR) err_quit("bind()");

  10. TCP 서버 함수 - (3) • listen() 함수 • 소켓과 결합된 TCP 포트 상태를 LISTENING으로 변경 int listen ( SOCKET s, // 소켓생성 결과값 int backlog // 연결큐의 길이 (최대 접속자수) ) ; 성공: 0, 실패: SOCKET_ERROR • listen() 함수 사용 예 059 retval = listen (listen_sock, SOMAXCONN); 060 if(retval == SOCKET_ERROR) err_quit("listen()");

  11. TCP 서버 함수 - (4) • accept() 함수 • 접속한 클라이언트와 통신할 수 있도록 새로운 소켓을 생성하여 리턴 • 접속한 클라이언트의 IP 주소와 포트 번호를 알려줌 SOCKET accept ( SOCKET s, // 소켓(클라이언트전용) 생성 결과값 struct sockaddr* addr, // 클라이언트의 IP주소와 포트번호 지정된 메모리에 저장 int* addrlen // 지정된 메모리 주소값 ) ; 성공: 새로운 소켓, 실패: INVALID_SOCKET • accept() 함수 사용 예 062 // 데이터 통신에 사용할 변수 063 SOCKET client_sock; 064 SOCKADDR_IN clientaddr; 065 int addrlen; ... 068 while(1){ 069 // accept( ) 070 addrlen = sizeof(clientaddr); 071 client_sock = accept (listen_sock, (SOCKADDR *)&clientaddr, &addrlen); 072 if(client_sock == INVALID_SOCKET){ 073 err_display("accept()"); 074 continue; 075 }

  12. TCP 서버 함수 - (5) • accept() 함수 사용 예 (계속) 076 printf("\n[TCP 서버] 클라이언트 접속: IP 주소=%s, 포트 번호=%d\n", 077 inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port)); 078 079 // 클라이언트와 데이터 통신 080 while(1){ ... 101 } 102 103 // closesocket() 104 closesocket(client_sock); 105 printf("[TCP 서버] 클라이언트 종료: IP 주소=%s, 포트 번호=%d\n", 106 inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port)); 107 }

  13. 실습 예제 – (1) • 소요시간 : 1시간 30분. • 직접 코딩해서 실습할 것. • 매우 중요한 예제임. • 각 라인별로 소스를 분석하시오.

  14. TCP 서버 TCP 클라이언트 socket() socket() bind() listen() 네트워크 accept() connect() recv() send() send() recv() closesocket() closesocket() TCP 클라이언트 함수 - (1) • TCP 클라이언트 함수

  15. TCP 클라이언트 함수 - (2) • connect() 함수 • 서버에게 접속하여 TCP 프로토콜 수준의 연결 설정 int connect ( SOCKET s, // 서버와 통신을 하기 위해 만든 소켓 const struct sockaddr* name, // 서버 주소, 포트번호 -> 특정 주소값에 저장 int namelen // 소켓 주소 구조체 변수의 크기 ) ; 성공: 0, 실패: SOCKET_ERROR • connect() 함수 사용 예 070 SOCKADDR_IN serveraddr; 071 serveraddr.sin_family = AF_INET; 072 serveraddr.sin_port = htons(9000); 073 serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 074 retval = connect(sock, (SOCKADDR *)&serveraddr, sizeof(serveraddr)); 075 if(retval == SOCKET_ERROR) err_quit("connect()");

  16. 네트워크 서버 클라이언트 애플리케이션 지역 IP 주소 지역 IP 주소 지역 포트 번호 지역 포트 번호 원격 IP 주소 원격 IP 주소 운영체제 원격 포트 번호 원격 포트 번호 수신 버퍼 송신 버퍼 ••• ••• 데이터 전송 함수 - (1) • 소켓 데이터 구조체

  17. 데이터 전송 함수 - (2) • send() 함수 • 애플리케이션 데이터를 송신 버퍼에 복사함으로써 궁극적으로 하부 프로토콜 (Ex. TCP/IP)에 의해 데이터가 전송 int send ( SOCKET s, // 통신할 대상과 연결된 소켓 const char* buf, // 보낼 데이터를 담고 있는 애플리케이션 버퍼 주소 int len, // 보낼 데이터 크기 int flags // send( ) 함수의 동작을 바꾸는 옵션 (보통 0) ); 성공: 보낸 바이트 수, 실패: SOCKET_ERROR • recv() 함수 • 수신 버퍼에 도착한 데이터를 애플리케이션 버퍼로 복사 int recv ( SOCKET s, // 통신할 대상과 연결된 소켓 char* buf, // 받은 데이터를 저장할 애플리케이션 버퍼의 주소 int len, // 수신 버퍼로부터 복사할 최대 데이터 크기 int flags // recv( ) 함수의 동작을 바꾸는 옵션 (보통 0) ); 성공: 받은 바이트 수 또는 0 (연결 종료 시), 실패: SOCKET_ERROR

  18. 데이터 전송 함수 - (3) • recvn() 함수: 만약 수신할 전체 크기를 알고 있다면 037 int recvn (SOCKET s, char *buf, int len, int flags) 038 { 039 int received; 040 char *ptr = buf; 041 int left = len; // left : 보낼 총 바이트 수 042 043 while (left > 0){ 044 received = recv (s, ptr, left, flags); 045 if (received == SOCKET_ERROR) 046 return SOCKET_ERROR; 047 else if (received == 0) 048 break; 049 left -= received; 050 ptr += received; 051 } 052 053 return (len - left); 054 }

  19. buf len left ptr buf len left ptr 읽은 데이터 데이터 전송 함수 - (4) • recvn( ) 함수 동작 원리

  20. 데이터 전송 함수 - (5) • 데이터 전송 함수 사용 예 – TCP 클라이언트 078 char buf[BUFSIZE+1]; 079 int len; ... 082 while(1){ 083 // 데이터 입력 084 ZeroMemory(buf, sizeof(buf)); 085 printf("\n[보낼 데이터] "); 086 if(fgets(buf, BUFSIZE+1, stdin) == NULL) // 사용자로부터 문자열 입력 087 break; 088 089 // '\n' 문자 제거 090 len = strlen(buf); 091 if(buf[len-1] == '\n') 092 buf[len-1] = '\0'; 093 if(strlen(buf) == 0) 094 break;

  21. 데이터 전송 함수 - (6) • 데이터 전송 함수 사용 예 – TCP 클라이언트 (계속) • 096 // 데이터 보내기 • 097 retval = send(sock, buf, strlen(buf), 0); • 098 if(retval == SOCKET_ERROR){ • 099 err_display("send()"); • 100 break; • 101 } • 102 printf("[TCP 클라이언트] %d바이트를 보냈습니다.\n", retval); • 103 • 104 // 데이터 받기 • 105 retval = recvn(sock, buf, retval, 0); • 106 if(retval == SOCKET_ERROR){ • 107 err_display("recv()"); • 108 break; • 109 } • 110 else if(retval == 0) • break; • 113 // 받은 데이터 출력 • 114 buf[retval] = '\0'; // 맨 끝에 0을 입력함. • 115 printf("[TCP 클라이언트] %d바이트를 받았습니다.\n", retval); • 116 printf("[받은 데이터] %s\n", buf); • 117 }

  22. 데이터 전송 함수 - (7) • 데이터 전송 함수 사용 예 – TCP 서버 066 char buf[BUFSIZE+1]; ... 080 while(1){ 081 // 데이터 받기 082 retval = recv (client_sock, buf, BUFSIZE, 0); 083 if(retval == SOCKET_ERROR){ 084 err_display("recv()"); 085 break; 086 } 087 else if (retval == 0) 088 break; 090 // 받은 데이터 출력 091 buf[retval] = '\0'; 092 printf("[TCP/%s:%d] %s\n", inet_ntoa(clientaddr.sin_addr), 093 ntohs(clientaddr.sin_port), buf); 095 // 데이터 보내기 096 retval = send(client_sock, buf, retval, 0); 097 if(retval == SOCKET_ERROR){ 098 err_display("send()"); 099 break; 100 } 101 }

  23. 실습 예제 – (1) • 마무리 하시오.

  24. 네트워크 애플리케이션 프로토콜과 메시지 설계 - (1) • 애플리케이션 프로토콜 • 애플리케이션 수준에서 주고 받는 데이터의 형식과 의미, 처리 방식 등을 정의한 프로토콜 • 애플리케이션 프로토콜 예

  25. 애플리케이션 프로토콜과 메시지 설계 - (2) • 메시지 정의 ① - 직선을 그리기(타입 없음) • 메시지 정의 ② - 원 그리기(타입 없음) struct DrawMessage1 { int x1, y1; // 선의 시작점 int x2, y2; // 선의 끝점 int width; // 선 두께 int color; // 선 색상 }; struct DrawMessage2 { int x1, y1; // 원의 중심 좌표 int r; // 원의 반지름 int fillcolor; // 내부 색상 int width; // 선 두께 int color; // 선 색상 };

  26. 애플리케이션 프로토콜과 메시지 설계 - (3) • 메시지 정의 ③ - 직선 및 원 그리기(타입 존재) struct DrawMessage1 { int type; // = LINE int x1, y1; // 선의 시작점 int x2, y2; // 선의 끝점 int width; // 선 두께 int color; // 선 색상 }; struct DrawMessage2 { int type; // = CIRCLE int x1, y1; // 원의 중심 좌표 int r; // 원의 반지름 int fillcolor; // 내부 색상 int width; // 선 두께 int color; // 선 색상 };

  27. 메시지 설계 시 고려 사항 • 경계 구분 [송신자] ① 항상 고정 길이 데이터를 보낸다. ② 경계 구분을 위해 특별한 표시(EOR; End Of Record)를 삽입한다. ③ 보낼 데이터 길이를 고정 길이 데이터로 보낸 후, 가변 길이 데이터를 이어서 보낸다. [수신자] ① 항상 고정 길이 데이터를 받는다. ② EOR이 나올 때까지 데이터를 읽은 후 처리한다. ③ 고정 길이 데이터를 읽어 뒤따라올 데이터의 길이를 알아낸다. 이 길이만큼 데이터를 읽어 처리한다. • 바이트 정렬 • 빅 엔디안 방식으로 통일 • 멤버 정렬 • 구조체(공용체, 클래스 포함) 멤버의 시작 주소에 대한 제약 사항 • #pragma pack 컴파일러 명령을 사용

  28. 실습 예제 – (2) • 소요시간 : 1시간 30분. • 직접 코딩해서 실습할 것. • 앞 예제랑 비교하면서 코드 분석할 것.

More Related