-
[열혈 TCP/IP 소켓 프로그래밍] Chapter4. 내용 확인문제Study/Network 2022. 10. 8. 17:45
01. TCP/IP 프로토콜 스택을 4계층으로 구분하고, TCP소켓이 거치는 계층구조와 UDP 소켓이 거치는 계층구조의 차이점 설명
- TCP/IP 프로토콜 스택은 LINK - IP - TCP/UDP - APPLICATION 계층으로 구분되어 있다.
- TCP 소켓은 TCP 스택을 거치고, UDP 소켓은 UDP 스택을 거친다. (당연한듯;;)
02. LINK계층과 IP계층이 담당하는 역할, 관계
- LINK 계층은 물리적인 연결에 대한 프로토콜을 정의한다.
- IP 계층은 데이터의 송수신 경로에 대한 프로토콜을 정의한다. (IP계층에서는 송수신의 오류발생에 대한 대비가 되어있지 않다.)
- IP계층은 LINK계층의 물리적 연결 프로토콜 위에서 동작한다
03. TCP/IP 프로토콜 스택이 4가지로 나뉘는 이유를 개방형 시스템과 연결지어 설명
- 네트워크는 물리적 연결, 데이터 송수신, 경로 선택 등 복잡한 구조이다.
- 각 문제를 영역별로 쪼개어 해결함으로서 유지/보수가 용이해진다.
- 또한, 각 계층에 대한 표준이 정해짐(개방형 시스템)으로서 하드웨어, 소프트웨어적 관점에서의 호환성이 증대된다. 이를 통해 빠른 기술 발전이 이루어질 수 있었다.
04. 클라이언트는 서버의 어떤 함수 호출 이후부터 connect() 함수를 호출할 수 있는가?
- 서버가 listen() 함수를 호출한 이후부터
05. 연결 요청 대기 큐가 생성되는 순간은 언제이고, 무슨 역할을 하는가? accept 함수와의 관계는?
- 서버에서 listen()함수를 호출하면서 연결 요청 대기 큐가 생성된다.
- 연결 요청 대기 큐는 클라이언트가 connect() 함수를 통해 서버와의 연결을 요청하였을 때 클라이언트의 연결 요청을 받아들이고, 대기시키는 역할을 한다.
- 이후, 서버에서 accept()함수를 호출함으로서 연결 요청 대기 큐에서 연결 요청 하나를 가져와 데이터를 송수신한다.
06. 클라이언트에서 bind함수호출이 불필요한 이유와, IP주소와 PORT 번호가 할당되는 시점?
- connect함수를 호출했을 때, 운영체제(커널)에서 자동으로 할당하기 때문이다.
- IP는 컴퓨터의 IP주소, PORT번호는 운영체제에서 무작위로 할당한다.
07. Hello World 예제 Iterative Server/Client구조로 변경해보기
#define _WINSOCK_DEPRECATED_NO_WARNINGS #include <cstdio> #include <cstdlib> #include <winsock.h> #pragma comment(lib, "ws2_32.lib") #define QUEUE_SIZE 5 #define BUF_SIZE 1024 const char* serverMessage = "Hello World!\n"; void main(int argc, char* argv[]) { WSADATA wsaData = {}; SOCKET hServSock, hClntSock; SOCKADDR_IN servAddr, clntAddr; int clntAddrSize; if (argc != 2) { printf("Usage : %s <port>\n", argv[0]); exit(1); } // WSA library 2.2 버전으로 초기화 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("WSAStartUp() Error"); exit(1); } // IPv4, TCP 소켓 생성 hServSock = socket(PF_INET, SOCK_STREAM, 0); if (hServSock == INVALID_SOCKET) { printf("socket() Error"); exit(1); } // 주소 정보 초기화 memset(&servAddr, 0, sizeof(SOCKADDR_IN)); servAddr.sin_family = AF_INET; // IPv4기반의 주소 체계 사용 servAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 현재 컴퓨터의 IP주소를 IP주소로 사용, host to Network Byte Order servAddr.sin_port = htons(atoi(argv[1])); // IP, PORT 할당 if (bind(hServSock, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR) { printf("bind() Error"); exit(1); } // 연결 요청 대기상태 진입 (연결 요청 대기 큐 size : 5) if (listen(hServSock, QUEUE_SIZE) == SOCKET_ERROR) { printf("listen() Error"); exit(1); } clntAddrSize = sizeof(clntAddr); int clntStrLen = 0; char clntMessage[BUF_SIZE] = {}; // 최대 5개의 클라이언트 요청까지 처리 for (int i = 0; i < QUEUE_SIZE; ++i) { // 연결 요청 수락 hClntSock = accept(hServSock, (SOCKADDR*)&clntAddr, &clntAddrSize); if (hClntSock == INVALID_SOCKET) { printf("accept() Error"); exit(1); } else { printf("Client [%d] Connected.\n", i + 1); } do { // 수신 데이터가 있을 때까지 대기 clntStrLen = recv(hClntSock, clntMessage, BUF_SIZE, 0); if (clntStrLen == 0) break; // Hello World 송신 send(hClntSock, serverMessage, strlen(serverMessage), 0); } while (clntStrLen != 0); closesocket(hClntSock); } closesocket(hServSock); printf("Close Server.\n"); WSACleanup(); }
서버 코드
#define _WINSOCK_DEPRECATED_NO_WARNINGS #include <cstdio> #include <cstdlib> #include <winsock.h> #pragma comment(lib, "ws2_32.lib") #define BUF_SIZE 1024 void main(int argc, char* argv[]) { WSADATA wsaData = {}; SOCKET hSocket; if (argc != 3) { printf("Usage : %s <IP> <PORT>", argv[0]); exit(1); } if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { printf("WSAStartUp() Error"); exit(1); } hSocket = socket(PF_INET, SOCK_STREAM, 0); if (hSocket == INVALID_SOCKET) { printf("socket() Error"); exit(1); } SOCKADDR_IN servAddr = {}; memset(&servAddr, 0, sizeof(servAddr)); servAddr.sin_family = AF_INET; servAddr.sin_addr.s_addr = inet_addr(argv[1]); servAddr.sin_port = htons(atoi(argv[2])); if (connect(hSocket, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR) { printf("connect() Error"); exit(1); } else { printf("Connected..................\n"); } char message[BUF_SIZE] = {}; int recvLen = 0; while (true) { fputs("Input Message (Q to Quit) : ", stdout); fgets(message, BUF_SIZE, stdin); if (!strcmp(message, "q\n") || !strcmp(message, "Q\n")) { break; } send(hSocket, message, strlen(message), 0); recvLen = recv(hSocket, &message[0], BUF_SIZE - 1, 0); message[recvLen] = '\0'; printf("Message From Server : %s", message); } closesocket(hSocket); printf("Quit Client.\n"); }
클라이언트 코드
'Study > Network' 카테고리의 다른 글
[열혈 TCP/IP 소켓 프로그래밍] Chapter3. 내용 확인문제 (1) 2022.09.22 [열혈 TCP/IP 소켓 프로그래밍] Chapter2. 내용 확인문제 (0) 2022.09.19 [열혈 TCP/IP 소켓 프로그래밍] Chapter1. 내용 확인문제 (0) 2022.09.15