Study/Network
[열혈 TCP/IP 소켓 프로그래밍] Chapter2. 내용 확인문제
게임 만드는 나무꾼
2022. 9. 19. 19:50
01. 프로토콜이 무엇인가?
- 프로토콜이란, 데이터의 전송 방식을 결정하는 규약이다.
- 두 컴퓨터 간 프로토콜을 정의해야 데이터 전송 방식을 서로 알고 해석할 수 있다.
02. 연결지향 소켓 TCP의 전송 특성 3가지
- 데이터의 손실이 없음이 보장된다.
- 데이터의 경계가 없다
- 데이터의 전송 순서가 보장된다.
03. 비연결지향 소켓 UDP의 전송 특성
- 데이터의 손실이 있을 수 있다.
- 빠른 전송을 목표로 한다.
- 한 번의 전송에 데이터의 크기가 제한된다.
- 연결이라는 개념이 존재하지 않는다.
04. 유형별 적합한 타입의 소켓은?
- 실시간 스트리밍 : UDP 소켓. 빠른 전송이 목표가 되어야 하고, 데이터가 손실되더라도 최신의 데이터를 계속 받는 것이 더 중요하다.
- 텍스트 파일 전송 : TCP 소켓. 순서가 무조건 보장되어야 하고 데이터의 손실이 없어야 한다.
- 인터넷 뱅킹 : 데이터의 손실이 절대 있어서는 안 된다.
05. 데이터의 경계가 존재하지 않는 소켓은? 그리고 이러한 소켓을 통해 데이터를 수신할 때 주의점
- 데이터의 경계가 존재하지 않는 소켓은 TCP 소켓이다.
- 수신할 때 주의할 점은, 소켓 내부의 버퍼에 데이터가 저장되고, read 함수 호출을 통해 버퍼에 있는 데이터를 비우는 방식이기 때문에 버퍼가 가득 차게 된다면 더 이상 데이터를 수신할 수 없다.
- 데이터가 손실되지는 않지만 데이터를 더 이상 받을 수 없기 때문에 주의해야 한다.
06. 서버에서 데이터를 쪼개서 보내보기
서버 코드
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
void ErrorHandling(char* Message);
int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET hServerSock, hClntSock;
SOCKADDR_IN servAddr, clntAddr;
int szClntAddr;
char message[] = "Hello World!";
if (argc != 2)
{
printf("Usage %s <port>\n", argv[0]);
exit(1);
}
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
ErrorHandling("WSAStartUp() error");
}
hServerSock = socket(PF_INET, SOCK_STREAM, 0);
if (hServerSock == INVALID_SOCKET)
{
ErrorHandling("socket() error");
}
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(atoi(argv[1]));
if (bind(hServerSock, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR)
{
ErrorHandling("bind() error");
}
if (listen(hServerSock, 5) == SOCKET_ERROR)
{
ErrorHandling("listen() error");
}
szClntAddr = sizeof(clntAddr);
hClntSock = accept(hServerSock, (SOCKADDR*)&clntAddr, &szClntAddr);
if (hClntSock == INVALID_SOCKET)
{
ErrorHandling("accept() error");
}
int len = strlen(message);
for (int i = 0; i < len; ++i)
{
send(hClntSock, &message[i], sizeof(char), 0);
}
closesocket(hClntSock);
closesocket(hServerSock);
WSACleanup();
}
void ErrorHandling(char* Message)
{
fputs(Message, stderr);
fputc('\n', stderr);
exit(1);
}
클라이언트 코드
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
void ErrorHandling(char* Message);
int main(int argc, char* argv[])
{
WSADATA wsaData;
SOCKET hSocket;
SOCKADDR_IN servAddr;
char message[30];
if (argc != 3)
{
printf("Usage : %s <IP> <port>\n", argv[0]);
exit(1);
}
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
ErrorHandling("WSAStartup() error");
}
hSocket = socket(PF_INET, SOCK_STREAM, 0);
if (hSocket == INVALID_SOCKET)
{
ErrorHandling("socket() error");
}
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)
{
ErrorHandling("connect() error");
}
// busy - waiting
for (int i = 0; i < 3000; ++i)
{
printf("Wait Time : %d\n", i);
}
recv(hSocket, message, 12, 0);
message[12] = '\0';
printf("Message From Server : %s", message);
closesocket(hSocket);
WSACleanup();
return 0;
}
void ErrorHandling(char* Message)
{
fputs(Message, stderr);
fputc('\n', stderr);
exit(1);
}