[네트워크 프로그래밍] 3. UDP

유기태·2023년 11월 24일
0

Server

// Server
#include<WinSock2.h>
#include<mswsock.h>
#include<ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")

void HandleError(const char* cause)
{
	int32 err = WSAGetLastError();
	cout << cause << err << " : error exists";
}

int main()
{
	WSADATA wsaData;
	int32 err;
	err = ::WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (err != 0)
	{
		cout << "Winsock Initialize Failed\n" << err << " : error exists";
		return 0;
	}

	SOCKET serverSocket = ::socket(AF_INET, SOCK_DGRAM, 0);
	if (serverSocket == INVALID_SOCKET)
	{
		HandleError("Socket Failed");
		return 0;
	}

	SOCKADDR_IN serverAddr;
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.s_addr = ::htonl(INADDR_ANY);
	serverAddr.sin_port = ::htons(7777);

	err = ::bind(serverSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
	if (err == SOCKET_ERROR)
	{
		HandleError("Bind failed");
		return 0;
	}

	while (true)
	{
		char recvBuffer[1000];
		SOCKADDR_IN clientAddr;
		int addrLen = sizeof(clientAddr);
		::memset(&clientAddr, 0, sizeof(clientAddr));
		int32 recvLen = ::recvfrom(serverSocket, recvBuffer, sizeof(recvBuffer), 0, (SOCKADDR*)&clientAddr, &addrLen);

		if (recvLen <= 0)
		{
			HandleError("RecvFrom Failed");
			return 0;
		}

		cout << "Recv Data! Data = " << recvBuffer << endl;
		cout << "Recv Data! Len=" << recvLen << endl;

		err = ::sendto(serverSocket, recvBuffer, sizeof(recvBuffer), 0, (SOCKADDR*)&clientAddr, sizeof(clientAddr));
		if (err == SOCKET_ERROR)
		{
			HandleError("Send Failed");
			return 0;
		}
	}

	return 0;
}

Client

#include "pch.h"
#include <CorePch.h>

#include <WinSock2.h>
#include <mswsock.h>
#include <ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")

void HandleError(const char* cause)
{
	int32 err = WSAGetLastError();
	cout << cause << err << " : error exists";
}

int main()
{

	// 전체적인 흐름
	// wsastartup(초기화) -> socket 준비 -> socket addr 준비 -> connect -> wsacleanup()
	WSADATA wsData;
	// winsock을 사용할 준비가 되었다(ws2_32 라이브러리 초기화)
	// parameter
	// 1. winsock 버전
	// 2. winsock 관련 정보가 wsData에 채워짐
	// 성공시 return 값이 0임
	int err = ::WSAStartup(MAKEWORD(2, 2), &wsData);
	if (err != 0)
	{
		cout << "WSAStartUp initialize failed\n" << err << " : error exists";
		return 0;
	}

	// 전화를 걸 전화기 생성 ( 이 socket을 이용해 데이터 전송 )
	// parameter
	// 1. 주소체계(IPv4 / IPv6) -> 네트워크 주소 할당의 문제로 새로운 주소 체계 편입
	// AF_INET(IPv4 주소 체계)
	// AF_INET(IPv6 주소 체계)
	// 2. socket type (TCP / UDP)
	// SOCK_STREAM(TCP활용) / SOCK_DGRAM(UDP활용)
	// 신뢰성 / 비신뢰성(패킷 소실의 위험성이 있음)
	// 왠만하면 TCP 사용
	// 3. protocol은 0으로 입력(default값)
	// return : descriptor를 return 함
	SOCKET clientSocket = ::socket(AF_INET, SOCK_DGRAM, 0);

	if (clientSocket == INVALID_SOCKET)
	{
		HandleError("Socket Failed");
		return 0;
	}

	// 식당 번호 입력
	SOCKADDR_IN serverAddr; // IPv4 용
	// SOCKADDR_IN6 IPv6용
	::memset(&serverAddr, 0, sizeof(serverAddr));
	// IPv4용이기때문에 항상 AF_INET을 설정해야함
	serverAddr.sin_family = AF_INET;
	// 주소체계는 1바이트씩 끊어서 사용 2^8 -> 256까지
	// inet_addr은 너무 구식
	// serverAddr.sin_addr.S_un.S_addr = ::inet_addr("192.168.123.100");
	// 127.0.0.1 루프백 주소(내 자신의 컴퓨터 ip)
	// 나중에는 DNS를 활용
	::inet_pton(AF_INET, "127.0.0.0", &serverAddr.sin_addr);
	// 포트 번호 연결할 목적지는? ( IP주소 + Port )-> IP아파트 Port 동
	// 일부 번호는 예약 되어있기 때문에 port는 이왕이면 10000번대를 넘어서 등록하면 좋다
	// htons
	// host to network short
	// network to host short 
	// Little-Endian vs Big-Endian
	// ex) 0x12345678 4바이트 정수
	// [0x78][0x56][0x34][0x12] <- little
	// [0x12][0x34][0x56][0x78] <- big
	// 요즘 대부분은 리틀엔디안 사용(intel corp.)
	// network에서는 빅엔디안을 사용함
	serverAddr.sin_port = ::htons(7777);

	while (true)
	{
		// TODO

		// 어떤 핸드폰으로 무엇을 보낼지!
		// parameter
		// 1. socket
		// 2. buf(실제 데이터)
		// 3. 버퍼 크기
		// 4. flag (default 0 다른 옵션 가능)
		char sendBuffer[100];

		cin >> sendBuffer;

		int32 resultCode = ::sendto(clientSocket, sendBuffer, sizeof(sendBuffer), 0, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
		if (resultCode == SOCKET_ERROR)
		{
			int32 errCode = ::WSAGetLastError();
			cout << "Send ErrCode : " << errCode << endl;
			return 0;
		}

		cout << "Send Data! Len = " << sizeof(sendBuffer) << endl;


		char recvBuffer[1000];
		int addrLen = sizeof(serverAddr);
		err = ::recvfrom(clientSocket, recvBuffer, sizeof(recvBuffer), 0,(SOCKADDR*)&serverAddr,&addrLen);
		if (err == SOCKET_ERROR)
		{
			err = ::WSAGetLastError();
			cout << "Recv ErrorCode : " << err << endl;
			return 0;
		}

		cout << "Echo Recv Data! Len = " << err << endl;
		cout << "Echo Recv Data! Data = " << recvBuffer << endl;
	}

	// 소켓 리소스 반환
	::closesocket(clientSocket);

	// winsock 해제
	::WSACleanup();
}

Unconnected UDP

recvfrom()
sendto()

Connected UDP

::connect() 함수 사용(주소 등록)
recv()
send()

profile
게임프로그래머 지망!

0개의 댓글

Powered by GraphCDN, the GraphQL CDN