Windows 소켓 통신

Yongs12 ㅣ 2024. 6. 6. 12:49

1. winsock 초기화

소켓 통신을 하기 위해서 WSADATA 객체를 만들고 WSAStartup() 함수를 통해 초기화를 시켜준다.
MAKEWORD(2, 2)는 winsock의 버전을 지정해주고 다음 인자로 만든 WSADATA 객체의 주소를 넘겨준다.
 

2. Socket 생성

 
socket()를 통해 Socket을 생성하는데 인자로 IP 주소 방식, TCP/UDP 등 소켓 방식 마지막으로 프로토콜을 설정한다.
마지막 인자에 0을 넣게 되면 프로토콜을 windows가 자동으로 선택해준다.

socket함수의 원형

 

socket 함수의 첫번째 인자
socket 함수의 두번째 인자

 

socket함수의 세번째 인자 보통 0으로 지정하여 windows에게 결정을 맡긴다.

 
 

3. Server 주소 설정

서버의 IP, Port를 설정한다.

 
INADDR_ANY는 특정 IP 주소가 아닌 모두 허용이다.
 

4. Bind = > Socket과 설정 된 정보를 묶어준다.

 
bind()를 통해 첫번째 인자로 생성한 Socket을 넣고 두번째로 SOCKADDR_IN으로 생성하고 정보를 입력한 객체의 주소를 SOCKADDR*로 형변환을 해서 읽을 수 있게 해준다.
마지막 인자로 생성한 SOCKADDR_IN의 사이즈를 넘겨주면 된다.
 

5. Listen => 대기상태로 설정

 
앞서 생성한 Socket은 이제 서버의 문지기가 되어 클라이언트가 접속을 시도하면 받아줄 준비를 한다.
listen()를 통해 설정한 socket을 첫번째 인자로 넣고 두 번째는 연결 요청을 받을 큐의 크기이지만 SOMAXCONN 매크로를 넣어 windows가 만들 수 있는 최대 크기를 설정할 수 있게 해준다.
 
 

6. Accept => 클라이언트 접속 허용

 
마지막으로 클라이언트가 접속을 시도했을 때 허용할 수 있게 accept()를 사용해 listen하고 있던 소켓에 들어온 클라이언트를 처리할 새로운 Socket에 담아주고 recv() 함수를 통해 클라이언트가 보내는 데이터를 수신하고 send()를 통해 클라이언트에게 데이터를 송신할 수 있게 된다.
 
 

최종 결과물

 
 
 


 

이러한 에러가 뜨게 된다면

// 경고 시 이 매크로를 상단에 작성해준다.
#define _WINSOCK_DEPRECATED_NO_WARNINGS

 
 
 

클라이언트 코드

#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <mswsock.h>
#include <windows.h>

#pragma comment(lib, "ws2_32")

#include <iostream>
using namespace std;

#define MAX_BUFFER_SIZE 1024

int main()
{
	Sleep(1);

	WSADATA wsaData;

	// 윈속 초기화 작업이 필수
	if (::WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	{
		cout << "초기화 실패" << endl;
		return 0;
	}

	SOCKET clientSocket = ::socket(AF_INET, SOCK_STREAM, 0);


	if (clientSocket == INVALID_SOCKET)
	{
		cout << "소켓 생성 실패" << endl;
		return 0;
	}

	SOCKADDR_IN addr = { 0 };
	addr.sin_family = AF_INET;
	addr.sin_port = htons(9414);
	addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

	if (::connect(clientSocket, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR)
	{
		cout << "서버 연결 에러" << endl;
		closesocket(clientSocket);
		WSACleanup();

		return 0;
	}

	char buffer[MAX_BUFFER_SIZE] = { 0 };

	while (true)
	{
		cout << "나 : ";
		gets_s(buffer);
		cout << endl;
		if (strcmp(buffer, "EXIT") == 0)
		{
			break;
		}

		::send(clientSocket, buffer, strlen(buffer) + 1, 0);

		memset(buffer, 0, sizeof(buffer));

		::recv(clientSocket, buffer, sizeof(buffer), 0);

		cout << "Server : " << buffer << endl;
		cout << endl;

	}

	shutdown(clientSocket, SD_BOTH);
	closesocket(clientSocket);
	WSACleanup();

    return 0;
}

'Socket 관련' 카테고리의 다른 글

WSAEventSelect Model  (0) 2024.06.08
Select Model  (0) 2024.06.07
winsock2 라이브러리 추가하기  (0) 2024.06.05
TCP, UDP  (0) 2024.06.02
Big Endian, Little Endian  (0) 2024.06.01