[TCP/IP] 에코서버 & 클라이언트 – IO multiplexing

서버

/*
## 소켓 서버 : 1 v n - IO multiplexing
1. socket()			: 소켓생성
2. bind()			: 소켓설정
3. listen()			: 수신대기열생성
*. fd_set()			: 소켓관리셋생성
*. select()			: 변화가 있는 파일 감지 & 관리
4. accept()			: 연결대기
5. read()&write()
	WIN recv()&send	: 데이터 읽고쓰기
6. close()
	WIN closesocket	: 소켓종료
*/

#include "stdafx.h"
#include <winsock2.h>

#pragma comment(lib, "Ws2_32.lib")

#define MAX_BUFFER		1024
#define SERVER_PORT		3500

int _tmain(int argc, _TCHAR* argv[])
{
	// Winsock Start - windock.dll 로드
	WSADATA WSAData;
	if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)
	{
		printf("Error - Can not load 'winsock.dll' file\n");
		return 1;
	}

	// 1. 소켓생성	
	SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (listenSocket == INVALID_SOCKET)
	{
		printf("Error - Invalid socket\n");
		return 1;
	}

	// 서버정보 객체설정
	SOCKADDR_IN serverAddr;
	memset(&serverAddr, 0, sizeof(SOCKADDR_IN));
	serverAddr.sin_family = PF_INET;
	serverAddr.sin_port = htons(SERVER_PORT);
	serverAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
	
	// 2. 소켓설정
	if (bind(listenSocket, (struct sockaddr*)&serverAddr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
	{
		printf("Error - Fail bind\n");
		// 6. 소켓종료
		closesocket(listenSocket);
		// Winsock End
		WSACleanup();
		return 1;
	}

	// 3. 수신대기열생성
	if (listen(listenSocket, 5) == SOCKET_ERROR)
	{
		printf("Error - Fail listen\n");
		// 6. 소켓종료
		closesocket(listenSocket);
		// Winsock End
		WSACleanup();
		return 1;
	}

	// * fd_set - 소켓관리셋생성
	fd_set fdSet, tempFdSet;
	int fdNum;
	// - fd_set 초기화
	FD_ZERO(&fdSet);
	// - fd_set에 listen 소켓 지정번호를 추가
	FD_SET(listenSocket, &fdSet);

	// 연결대기 정보변수 선언
	SOCKADDR_IN clientAddr;
	int addrLen = sizeof(SOCKADDR_IN);
	memset(&clientAddr, 0, addrLen);
	SOCKET clientSocket;

	while (1)
	{
		tempFdSet = fdSet;
		// * select - 변화가 있는 파일 감지
		fdNum = select(0, &tempFdSet, NULL, NULL, NULL);
		// - fd에 데이터 변경이 있는지 검사
		if (FD_ISSET(listenSocket, &tempFdSet))
		{
			// 4. 연결대기			
			clientSocket = accept(listenSocket, (struct sockaddr *)&clientAddr, &addrLen);
			if (clientSocket == INVALID_SOCKET)
			{
				printf("Error - Fail accept\n");
				continue;
			}
			// - fd_set에 client 소켓 지정번호를 추가
			FD_SET(clientSocket, &fdSet);
			continue;
		}

		// 소켓관리셋 전체를 확인하여 처리		 
		for (unsigned int i = 0; i < tempFdSet.fd_count; i++)
		{
			// listen 소켓(연결을 관리하는 소켓)은 처리하지 않음
			if (tempFdSet.fd_array[i] == listenSocket)
				continue;

			SOCKET savedSocket = tempFdSet.fd_array[i];

			// 5-1. 데이터 읽기
			char messageBuffer[MAX_BUFFER];
			int receiveBytes = recv(savedSocket, messageBuffer, MAX_BUFFER, 0);
			if (receiveBytes > 0)
			{
				printf("TRACE - Receive message : %s (%d bytes)\n", messageBuffer, receiveBytes);
				// 5-2. 데이터 쓰기
				int sendBytes = send(savedSocket, messageBuffer, strlen(messageBuffer), 0);
				if (sendBytes > 0)
				{
					printf("TRACE - Send message : %s (%d bytes)\n", messageBuffer, sendBytes);
				}
			}
			else
			{
				// 6-1. 클라이언트 소켓종료
				closesocket(clientSocket);
				// - fd_set에서 fd를 삭제
				FD_CLR(savedSocket, &tempFdSet);
			}
		}		
	}

	// 6-2. 리슨 소켓종료
	closesocket(listenSocket);

	// Winsock End
	WSACleanup();

	return 0;
}

클라이언트

/*
## 소켓 서버 : 1 v n - IO multiplexing
1. socket()			: 소켓생성
2. connect()		: 연결요청
3. read()&write()
	WIN recv()&send	: 데이터 읽고쓰기
4. close()
	WIN closesocket	: 소켓종료
*/

#include "stdafx.h"
#include <winsock2.h>

#pragma comment(lib, "Ws2_32.lib")

#define MAX_BUFFER		1024
#define SERVER_IP		"127.0.0.1"
#define SERVER_PORT		3500

int _tmain(int argc, _TCHAR* argv[])
{	
	// Winsock Start - winsock.dll 로드
	WSADATA WSAData;
	if (WSAStartup(MAKEWORD(2, 0), &WSAData) != 0)
	{
		printf("Error - Can not load 'winsock.dll' file\n");
		return 1;
	}

	// 1. 소켓생성
	SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (listenSocket == INVALID_SOCKET)
	{
		printf("Error - Invalid socket\n");
		return 1;
	}

	// 서버정보 객체설정
	SOCKADDR_IN serverAddr;
	memset(&serverAddr, 0, sizeof(SOCKADDR_IN));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(SERVER_PORT);
	serverAddr.sin_addr.S_un.S_addr = inet_addr(SERVER_IP);

	// 2. 연결요청
	if (connect(listenSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
	{
		printf("Error - Fail to connect\n");
		// 4. 소켓종료
		closesocket(listenSocket);
		// Winsock End
		WSACleanup();
		return 1;
	}
	else
	{
		printf("Server Connected\n* Enter Message\n->");
	}
	
	while (1)
	{		
		// 메시지 입력
		char messageBuffer[MAX_BUFFER];
		int i, bufferLen;
		for (i = 0; 1; i++)
		{
			messageBuffer[i] = getchar();
			if (messageBuffer[i] == '\n')
			{
				messageBuffer[i++] = '\0';
				break;
			}
		}
		bufferLen = i;
		
		// 3-1. 데이터 쓰기
		int sendBytes = send(listenSocket, messageBuffer, bufferLen, 0);
		if (sendBytes > 0)
		{
			printf("TRACE - Send message : %s (%d bytes)\n", messageBuffer, sendBytes);
			// 3-2. 데이터 읽기
			int receiveBytes = recv(listenSocket, messageBuffer, MAX_BUFFER, 0);
			if (receiveBytes > 0)
			{
				printf("TRACE - Receive message : %s (%d bytes)\n* Enter Message\n->", messageBuffer, receiveBytes);
			}			
		}
		
	}		

	// 4. 소켓종료
	closesocket(listenSocket);

	// Winsock End
	WSACleanup();
	
	return 0;
}

댓글 남기기