TCP, UDP 차이점
- TCP
- 연결을 위해 할당되는 논리적인 경로가 존재
- 전송 순서가 보장
- 분실이 일어나면 책임지고 다시 전송(신뢰성이 좋다)
- 고려할 것(흐름 혼잡 제어)이 많아 속도가 느리다
- UDP
- 연결이라는 개념이 없다
- 전송 순사가 보장되지 않음
- 경계(boundary)의 개념이 있다 -> Hello / World를 보내면 Hello / World로 들어옴(TCP는 어떻게 들어올지 모름)
- 분실에 대한 책임이 없다(신뢰성이 낮다)
- 단순하기에 속도가 빠르다
UDP 서버
#include "pch.h"
#include <iostream>
#include "CorePch.h"
#include <atomic>
#include <mutex>
#include <windows.h>
#include <future>
#include "ThreadManager.h"
#include <winsock2.h>
#include <mswsock.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
void HandleError(const char* cause)
{
int32 errCode = ::WSAGetLastError();
cout << cause << " ErrorCode : " << errCode << endl;
}
int main()
{
WSAData wsaData;
if (::WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
return 0;
// UDP는 서버소켓을 하나만 만들고 그 소켓을 통해 데이터를 받음.
SOCKET serverSocket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (serverSocket == INVALID_SOCKET)
{
HandleError("Socket");
return 0;
}
SOCKADDR_IN serverAddr;
::memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = ::htonl(INADDR_ANY);
serverAddr.sin_port = ::htons(7777);
if (::bind(serverSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
{
HandleError("Bind");
return 0;
}
while (true)
{
SOCKADDR_IN clientAddr;
::memset(&clientAddr, 0, sizeof(clientAddr));
int32 addrLen = sizeof(clientAddr);
this_thread::sleep_for(1s);
char recvBuffer[1000];
// UDP는 Listen이 없고 바로 recv를하게 된다
int32 recvLen = ::recvfrom(serverSocket, recvBuffer, sizeof(recvBuffer), 0,
(SOCKADDR*)&clientAddr, &addrLen);
if (recvLen <= 0)
{
HandleError("RecvFrom");
return 0;
}
cout << "Recv Data! Data = " << recvBuffer << endl;
cout << "Recv Data! Len = " << recvLen << endl;
// 보낼때도 sendto로 보낸다
int32 errorCode = ::sendto(serverSocket, recvBuffer, recvLen, 0,
(SOCKADDR*)&clientAddr, sizeof(clientAddr));
if (errorCode == SOCKET_ERROR)
{
HandleError("SendTo");
return 0;
}
cout << "Send Data! Len = " << recvLen << endl;
}
// 윈속 종료
::WSACleanup();
}
UDP 클라이언트
#include "pch.h"
#include <iostream>
#include <winsock2.h>
#include <mswsock.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
void HandleError(const char* cause)
{
int32 errCode = ::WSAGetLastError();
cout << cause << " ErrorCode : " << errCode << endl;
}
int main()
{
WSAData wsaData;
if (::WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
return 0;
SOCKET clientSocket = ::socket(AF_INET, SOCK_DGRAM, 0);
if (clientSocket == INVALID_SOCKET)
{
HandleError("Socket");
return 0;
}
SOCKADDR_IN serverAddr;
::memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
::inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
serverAddr.sin_port = ::htons(7777);
// Connected UDP
::connect(clientSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
// UnConnected UDP는 connect자체가 필요없음
// ---------------------------
while (true)
{
char sendBuffer[100] = "Hello World!";
// 나의 IP 주소 + 포트 번호 설정
// Unconnected UDP
/*int32 resultCode = ::sendto(clientSocket, sendBuffer, sizeof(sendBuffer), 0,
(SOCKADDR*)&serverAddr, sizeof(serverAddr));*/
// Connected UDP
int32 resultCode = ::send(clientSocket, sendBuffer, sizeof(sendBuffer), 0);
if (resultCode == SOCKET_ERROR)
{
HandleError("SendTo");
return 0;
}
cout << "Send Data! Len = " << sizeof(sendBuffer) << endl;
SOCKADDR_IN recvAddr;
::memset(&recvAddr, 0, sizeof(recvAddr));
int32 addrLen = sizeof(recvAddr);
char recvBuffer[1000];
// Unconnected UDP
//int32 recvLen = ::recvfrom(clientSocket, recvBuffer, sizeof(recvBuffer), 0,
// (SOCKADDR*)&recvAddr, &addrLen);
int32 recvLen = ::recv(clientSocket, recvBuffer, sizeof(recvBuffer), 0);
if (recvLen <= 0)
{
HandleError("RecvFrom");
return 0;
}
cout << "Recv Data! Data = " << recvBuffer << endl;
cout << "Recv Data! Len = " << recvLen << endl;
this_thread::sleep_for(1s);
}
// ---------------------------
// 소켓 리소스 반환
::closesocket(clientSocket);
// 윈속 종료
::WSACleanup();
}