서버/TCPIP

TCP/IP 에코서버 구현

HSH12345 2024. 10. 21. 23:41

서버

#include <iostream>
#include <string>
#include <WinSock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;

#define BUFFER_SIZE 1024
#define SERVER_IP "127.0.0.1"
#define MAX_CLIENT_COUNT 5

void HandleError(const char* message)
{
	cout << message << " Error: " << WSAGetLastError() << "\n";
	WSACleanup();
	exit(1);
}

int main(int argc, char* argv[])
{
	WSADATA wsaData;
	SOCKET serverSocket;
	SOCKET clientSocket;
	char message[BUFFER_SIZE];
	int strLen;

	SOCKADDR_IN serverAddr;
	SOCKADDR_IN clientAddr;
	int clientAddrSize;

	if (argc != 2)
	{
		cout << "Usage: " << argv[0] << " <port>\n";
		exit(1);
	}

	int wsaResultNum = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (wsaResultNum != 0)
	{
		HandleError("WSAStartup() Error");
	}

	serverSocket = socket(PF_INET, SOCK_STREAM, 0);
	if (serverSocket == INVALID_SOCKET)
	{
		HandleError("socket() Error");
	}

	memset(&serverAddr, 0, sizeof(serverAddr));	
	serverAddr.sin_family = AF_INET;
	int ptonResultNum = inet_pton(AF_INET, SERVER_IP, &(serverAddr.sin_addr.s_addr));
	if (ptonResultNum == 0)
	{
		HandleError("inet_pton() Error");
	}

	serverAddr.sin_port = htons(atoi(argv[1]));
	if (serverAddr.sin_port == 0)
	{
		HandleError("atoi() Error");
	}

	int bindResultNum = bind(serverSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr));	
	if (bindResultNum == SOCKET_ERROR)
	{
		HandleError("bind() Error");
	}

	int listenResultNum = listen(serverSocket, 5);
	if (listenResultNum == SOCKET_ERROR)
	{
		HandleError("listen() Error");
	}

	clientAddrSize = sizeof(clientAddr);
	for (int i = 0; i < MAX_CLIENT_COUNT; i++)
	{
		// 클라이언트의 주소 길이는 런타임에 결정되므로 참조타입 변수 필요
		clientSocket = accept(serverSocket, (SOCKADDR*)&clientAddr, &clientAddrSize);
		if (clientSocket == SOCKET_ERROR)
		{
			HandleError("accept() Error");
		}
		else
		{
			cout << "Connected client " << i + 1 << "\n";
		}

		while ((strLen = recv(clientSocket, message, BUFFER_SIZE, 0)) != 0)
		{
			send(clientSocket, message, strLen, 0);
		}

		closesocket(clientSocket);
	}

	closesocket(serverSocket);
	WSACleanup();
	return 0;
}

 

 

클라이언트

#include <iostream>
#include <string>
#include <WinSock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
using namespace std;

#define BUFFER_SIZE 1024

void HandleError(const char* message)
{
	cout << message << " Error: " << WSAGetLastError() << "\n";
	WSACleanup();
	exit(1);
}

int main(int argc, char* argv[])
{
	WSADATA wsaData;
	SOCKET clinetSocket;
	char message[BUFFER_SIZE];
	int strLen;
	SOCKADDR_IN serverAddr;

	if (argc != 3)
	{
		cout << "Usage: " << argv[0] << " <IP> <PORT>\n";
		exit(1);
	}

	int wsaResultNum = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (wsaResultNum != 0)
	{
		HandleError("WSAStartup()");
	}

	clinetSocket = socket(PF_INET, SOCK_STREAM, 0);
	if (clinetSocket == INVALID_SOCKET)
	{
		HandleError("socket()");
	}

	memset(&serverAddr, 0, sizeof(serverAddr));
	serverAddr.sin_family = AF_INET;
	int ptonReseultNum = inet_pton(AF_INET, argv[1], &serverAddr.sin_addr.s_addr);
	if (ptonReseultNum == 0)
	{
		HandleError("inet_pton()");
	}

	serverAddr.sin_port = htons(atoi(argv[2]));
	if (serverAddr.sin_port == 0)
	{
		HandleError("atoi() Error");
	}

	int connectResultNum = connect(clinetSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
	if (connectResultNum == SOCKET_ERROR)
	{
		HandleError("connect()");
	}

	while (true)
	{
		cout << "Input message(Q to quit): ";
		cin.getline(message, BUFFER_SIZE);
		if (!strcmp(message, "Q") || !strcmp(message, "q"))
		{
			break;
		}

		send(clinetSocket, message, strlen(message), 0);
		strLen = recv(clinetSocket, message, BUFFER_SIZE - 1, 0);
		if (strLen == -1)
		{
			HandleError("recv()");
		}
		else if (strLen == 0)
		{
			// 서버에서 연결이 끊어진 상태를 처리
			break;
		}

		// 널문자 추가로 문자열의 마지막 처리
		message[strLen] = 0;
		cout << "Message from server: " << message << "\n";
	}

	closesocket(clinetSocket);
	WSACleanup();
	return 0;
}

 

 

결과