Department of Computer Science and Engineering TCP Server/Client Department of Computer Science and Engineering Kyung Hee University. Choong Seon Hong
주의 : 모든 데이터는 네트워크 바이트 순서로 저장 해야 한다. IPv4의 주소체계를 나타내는 구조체 클라이언트 또는 서버의 구체적인 주소를 표현을 위해 사용 주소체계 IP 주소 포트번호 struct sockaddr_in { sa_family_t sin_family; // 주소 체계 uint16_t sin_port; // 16비트 포트번호 struct in_addr sin_addr; // 32 비트 IP 주소 char sin_zero[8]; // 사용되지 않음 }; struct in_addr { uint32_t s_addr; // 32비트 IP 주소를 저장하는 구조체 }; 주의 : 모든 데이터는 네트워크 바이트 순서로 저장 해야 한다.
인터넷 주소 초기화 Template 1: struct sockaddr_in addr; 2: char *serv_ip=“163.180.118.99"; 3: char *serv_port=“9999"; 4: memset(&addr, 0, sizeof(addr_len)); 5: addr.sin_family = AF_INET; 6: addr.sin_addr.s_addr = inet_addr(serv_ip); 7: addr.sin_port = htons(atoi(serv_port)); //스트링 정수 1: struct sockaddr_in addr; 2: char *serv_port="9190"; 3: memset(&addr, 0, sizeof(addr_len)); 4: addr.sin_family = AF_INET; 5: addr.sin_addr.s_addr = htons(INADDR_ANY); 6: addr.sin_port = htons(atoi(serv_port));
주소 정보 할당하기 #include <sys/type.h> #include <sys/socket.h> int bind(int sockfd, struct sockaddr * myaddr, int addrlen); sockfd : 주소를 할당하고자 하는 소켓의 파일 디스크립터를 인자로 전달 myaddr : 할당하고자 하는 주소 정보를 지니고 있는 sockaddr_in 구조체 변수의 포인터를 인자로 전달 addrlen : 인자로 전달될 주소 정보 구조체의 길이를 전달 함수 호출이 성공하면 sockfd가 가리키는 소켓에 myaddr이 가리키는 주소 정보가 할당되고 성공 시 0, 실패 시 -1 반환
소켓주소 구조체 프로토콜 체계에 따라 주소 체계가 다름 socket 함수와 bind 함수는 특정 프로토콜 체계를 위한 함수가 아님 프로토콜에 독립적 따라서, 일반적으로 선언되어야 함 Local Unix 프로토콜을 위한 sockaddr_un 구조체의 포인터도 인자값으로 사용할 수 있어야 함 struct sockaddr { sa_family sin_family; // address_family char sa_data[14]; // 주소 };
프로그램 예제 확인 프로그램 예제 bind_sock.c 실행결과.
TCP Server Program Procedure TCP Server socket() 소켓 생성 소켓번호와 소켓주소의 결합 bind() listen() 연결 대기 연결수락 accept() 클라이언트의 요구 처리 read() 서비스 처리, write() close()
TCP Server Program socket() bind() socket(PF_INET, SOCK_STREAM,0) 소켓의 생성 bind() socket()으로 생성된 소켓은 그 응용 프로그램 내에서 유일한 번호인 소켓번호를 배정받는다. 그러나 이 번호는 응용 프로그램만 알고 있는 번호이므로 이 프로그램이 컴퓨터 외부와 통신하려면 이 소켓번호와 소켓주소(IP 주소 + 포트번호)를 연결해 두어야 하며 이를 위해 bind()가 사용된다. socket(PF_INET, SOCK_STREAM,0) int bind(int sockfd, struct sockaddr * myaddr, int addrlen);
TCP Server Program bind() 호출 시 소켓번호와 소켓주소의 관계 socket() bind() 소켓번호 연결 소켓번호 1. 프로토콜 소켓 인터페이스 2. 자신의 IP 주소 3. 자신의 포트번호 4. 상대방 IP 주소 5. 상대방 포트번호 TCP/IP 네트워크
‘연결 요청 대기 상태'로의 진입 listen 함수는 전달되는 인자의 소켓을 ‘서버 소켓’이 되게 한다. #include <sys/type.h> int listen(int s, int backlog); s : ‘연결 요청 대기 상태’에서 클라이언트의 연결 요청을 받아들이는 역할을 하게 될 소켓의 파일 디스크립터를 인자로 전달 서버 소켓 backlog : ‘연결 요청 대기 큐(Queue)’의 크기를 나타냄. 인자로 5가 들어오면, 큐의 크기가 5가 되어 클라이언트의 연결 요청을 5개까지 대기시킬 수 있게 된다. 함수호출 성공 시에는 0, 실패 시에는 -1이 리턴
서버의 역할과 연결 요청 대기 상태 Server socket is kind of a ‘gatekeeper’. Server 서버로의 연결 요청 서버소켓 대 기 실 client data 두 번째 인자 첫 번째 인자
연결 요청 수락하기 연결요청 대기 큐(queue)에 존재하는 클라이언트의 연결 요청 수락 #include <sys/type.h> #include <sys/socket.h> int accept(int s, struct sockaddr * addr, int * addrlen); s : 서버 소켓의 파일 디스크립터를 인자로 전달 addr : 연결 요청을 수락할 클라이언트의 주소 정보를 저장할 변수의 포인터. 함수 호출이 성공하면 addr이 가리키는 변수에는 클라이언트의 주소 정보로 채워지게 됨. addrlen : 함수 호출 시 인자로 전달된 addr 포인터가 가리키는 구조체의 크기를 저장하고 있는 변수의 포인터를 넘겨줌. 서버는 *addr를 통해 클라이언트의 IP 주소를 알 수 있음. 성공 시 소켓의 새로 생성된 파일 디스크립터를, 실패 시 -1 리턴
TCP Server Program accept() 호출 시 얻는 소켓주소 정보와 새로운 소켓 TCP/IP 소켓번호 socket() bind() listen() accept() 새로운 소켓번호 소켓번호 1. 프로토콜 소켓 인터페이스 2. 자신의 IP 주소 3. 자신의 포트번호 4. 상대방 IP 주소 5. 상대방 포트번호 TCP/IP 네트워크
연결 요청 수락 상태 서버소켓 1 2 3 새로운 소켓 Client1 Client2 Client3 연결 요청 연결 요청 대기 큐 Accept 함수 호출 연결 요청 수락 연결 완료! 데이터 송 수신 진행 accept() 함수의 수행이 성공하면 접속된 클라이언트와의 통신에 사용할 새로운 소켓이 만들어지고 이 소켓번호가 리턴, 실패 시에는 -1을 리턴 서버는 이 클라이언트와 통신하기 위하여 accept()가 리턴하여 새로 만들어진 소켓번호를 사용
Remind of “Hello World!” Server 프로그램 예제 helloworld_server.c 실행하기 포트 번호는 123+각자 아이디 Ex) ID : ip25 = 12325
클라이언트의 기본적인 함수 호출 순서 Procedure TCP Client socket() 소켓 개설 sockaddr_in 구성 서버의 IP 주소와 포트번호 지정 connect() 서버로 연결 요구 read(), write() 데이터 송수신 close()
연결 요청 함수 소켓과 목적지 주소에 대한 정보를 마련한 후 연결 요청을 시도 한다. 서버에 연결 요청 #include <sys/type.h> int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); 서버에 연결 요청 sockfd : 미리 생성해 놓은 소켓의 파일 디스크립터 serv_addr : 연결 요청을 보낼 서버의 주소 정보를 지닌 구조체 변수의 포인터 addrlen : serv_addr 포인터가 가리키는 주소 정보 구조체 변수의 크기
TCP Client Program connect() 호출시 소켓번호와 소켓주소의 관계 socket() connect() 1. 프로토콜 소켓 인터페이스 2. 자신의 IP 주소 3. 자신의 포트번호 4. 상대방 IP 주소 5. 상대방 포트번호 TCP/IP 네트워크
Remind of “Hello World!” Client 프로그램 예제 helloworld_client.c 실행하기 포트 번호는 123+각자 아이디 Ex) ID : ip25 = 12325
소켓 사용 절차 TCP (연결형) 소켓 프로그래밍 절차 서 버 클라이언트 socket() socket() bind() 서 버 클라이언트 socket() socket() bind() listen() connect() 연결요청 accept() 데이터 송수신 read() write() write() read() 종료 close() close()
Iterative 서버의 구현 Iterative TCP Server Finished ? socket() bind() listen() accept() read() 서비스 처리, write() closed() N Y 소켓 개설 소켓번호와 소켓주소의 결합 연결을 기다림 연결수락 클라이언트의 요구를 처리한 후 결과
Iterative 서버의 코드 Template for( ; ; ){ clnt_addr_size=sizeof(clnt_addr); clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_size); if(clnt_sock==-1) { error_handling("accept() error"); break; } /* 데이터 전송 후 종결 */ write(clnt_sock, message, sizeof(message)); close(clnt_sock);
예제 확인 helloworld_server2.c, helloworld_client.c
에코(echo) 서버/클라이언트의 구현 에코 서버/클라이언트의 기능 Server Client Hello! Hello! 버퍼(배열) … Hello! message Hello!
예제 확인 프로그램 예제 echo_server.c, echo_client.c 실행 결과
TCP 기반의 데이터 전송 특징 Server Client 한번의 데이터 전송함수 호출(write, send)이 늘 하나의 패킷을 형성하는 것은 아니다. Server Client 버퍼(배열) … ABCD A B … D C A, B 먼저 도착
다시 구현하는 TCP기반의 에코 클라이언트 프로그램 예제 echo_client2.c
경계가 없는 TCP기반의 데이터 전송 데이터 송수신 함수의 호출 횟수는 큰 의미를 지니지 않는다. Client Server 두 번에 걸쳐 메시지 전송 MSG 1 MSG 2 한번에 메시지 수신 후 한번에 메시지 전송 MSG 1 + MSG 2 네 번에 걸쳐서 메시지 수신
예제 확인 프로그램 예제 bnd_server.c, bnd_client.c 실행결과
실습#1 daytime_tcp_server.c, daytime_tcp_client.c Daytime service를 제공하는 서버 프로그램과 클라이언트 프로그램을 작성하시오.(TCP 이용) Hint #include<stdio.h> #include<stdlib.h> #include<time.h> Int main(int argc, char *argv[ ]) { time_t tim; tim =time(NULL); printf(“현재 시각은 %s”, ctime(&tim)); return 0; }
실습#2 hostname_tcp_server.c, hostname_tcp_client.c Hint struct hostent, gethostbyname()