Coding Memo

[C++, C#, Java] 소켓 (Socket) 본문

etc

[C++, C#, Java] 소켓 (Socket)

minttea25 2023. 7. 2. 21:47

소켓이란?

 

네트워크를 통해 두 프로그램이나 프로세스 간의 통신을 위한 끝 점(EndPoint) 이다.

 

두 프로그램은 이 소켓을 통해 네트워크에서 데이터를 서로 주고 받을 수 있다.

IP 주소와 포트 넘버을 소켓에 지정하여 컴퓨터의 주소와 프로그램을 식별할 수 있다.

소켓 생성은 OS에 의해 실행된다. (시스템 호출로 소켓 생성 시, context-switching이 일어난다.)

프로그램이 종료되면, OS에 의해 사용했던 소켓에 할당된 리소스를 해제한다.

자주 사용하는 TCP 타입과 UDP 타입 외에도 다양한 소켓 타입이 있다.


소켓 프로그래밍

 

소켓 프로그래밍 시에 공통적인 사항이 있다.

1. 소켓 생성 시 소켓 타입, 프로토콜 등을 지정한다.

2. 엔드포인트 (소켓 주소) 생성 시, 호스트(ip주소 등)와 포트 번호를 지정한다.

 

***TCP***

서버에서는...

소켓과 엔드포인트 생성 -> 소켓에 엔드포인트를 Bind -> 소켓을 오픈 (Listen) -> 연결 요청 대기

 

클라이언트에서는...

소켓과 엔드포인트 생성 -> 생성된 소켓으로 엔드포인트에 Connect -> 엔드포인트(서버)의 응답 대기

 

서버에서의 엔드포인트는 서버를 오픈할 자신의 컴퓨터가 될 것이고,

클라이언트에서의 엔드포인트는 연결을 할 서버에 대한 엔드포인트가 될 것이다.

 

TCP 연결

 

Note: 서버와 클라이언트가 연결되는 과정에서 서버와 클라이언트 사이에 3 way-handshake가 발생하고 연결이 형성된다.

 

Note: TCP의 포트번호 중 일부는 특정 어플리케이션 용으로 예약되어 있다.

 

 

***UDP***

UDP는 Connectionless 프로토콜이므로 서버와 클라이언트 간에 직접적인 연결을 하지 않고 일방적으로 통신한다.

소켓 문을 열어놓고 들어오는 Datagram 패킷을 받아 처리한다. TCP에 비해 간단하다.

 

 

 

프로그래밍 언어별로 사용법이 다양하다. 

"간단하게" 언어별로 소켓을 어떻게 생성하고 ip주소와 포트 번호를 어떻게 맵핑하는지 알아보자.


C++

 

C++은  <winsock2.h> 헤더와 ws2.32.lib 라이브러리를 사용하여 소켓 프로그래밍을 할 수 있다.

추가적으로 TCP/IP 통신의 경우 <ws2tcpip.h> 헤더도 사용한다.

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

 

복잡하고 low-level 다운 언어 답게 socket에 대해 설정해주어야 할 것이 꽤 많다.

 

C++에서 소켓을 생성하고 listen하기 위해 다음과 같은 과정이 필요하다.

1. winsock 초기화 (=ws2_32 dll 초기화)

2. AddressFamily (IPv4, IPv6, ...), 소켓 타입(STREAM, DGRAM, ...), 프로토콜 타입(TCP, UDP, ...)을 지정하여 소켓 생성

3. sockaddr설정: SOCKADDR_IN이나 SOCKADDR_IN6에 AddressFamily, 포트 번호, ip 주소를 지정하여 생성

4. 생성한 소켓과 sockaddr를 bind or connect

 

소켓 생성에 대한 다양한 설정 값은 다음 문서를 참고하자.

https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket

 

socket function (winsock2.h) - Win32 apps

The socket function creates a socket that is bound to a specific transport service provider.

learn.microsoft.com


C#

 

C#에서 소켓프로그래밍을 위해서 System에서 제공하는 Net, Socket등을 사용할 수 있다.

using System;
using System.Net;
using System.Net.Sockets;

 

C#에서 소켓을 생성하는 과정은 간단하다.

1. 호스트(ip주소), 포트번호를 설정한 EndPoint 생성

2. 소켓 타입과 프로토콜 타입, AddressFamily를 지정하여 소켓 생성

3. 생성한 소켓에 EndPoint를 bind 하거나 connect

 

Note: UDP를 위한 DatagramSocket이 따로 존재한다.

 


Java

 

java.net를 import 하여 소켓 프로그래밍을 할 수 있다.

import java.net.*;

 

Java에서 소켓을 생성하는 과정 또한 간단하다.

1. 소켓 생성 (인자 없이 생성)

2. 호스트(ip주소), 포트번호를 설정한 INetSocketAddress 생성

3. 소켓과 INetSocketAddress 연결

 

Note: Java에는 TCP 연결을 위한 Socket 클래스, ServerSocket 클래스가 있고 UDP 연결을 위한 DatagramSocket클래스가 별도로 존재한다.

 

Note: Socket, ServerSocket, DatagramSocket에 여러가지 생성자가 오버로드 되있는데 몇몇 생성자는 각 클래스가 용도가 정해져 있는 만큼, 소켓 생성시에 자동으로 listen, bind를 바로 수행한다.
ex) 아래 코드에서 포트번호를 인자한 생성자를 호출하면 자동으로 listening 상태인 소켓이 생성된다.
(명시적으로 listen을 할 필요가 없다; 생성자 코드를 보면 listen 코드가 포함되어 있다.)

ServerSocket serverSocket = new ServerSocket(8888, 10);