경고!!
제가 아는 부분에 대해서 공유드리는 목적의 발표입니다. 이 부분에 대해 빠삭하지 않기 때문에 질문에 대한 답을 당장은 드릴 수 없을 수 있지만, 추후에 공부를 통해서 답을 드리겠습니다.
네트워크 프로그래밍
저희가 목표로 하는 통신 기능이 있는 C# 코드를 구현하기 전에 네트워크 프로그래밍이 무엇인지 감을 잡도록 하겠습니다.
인터넷의 유래
최초의 컴퓨터는 프로그램을 입력받고 실행한 뒤 결과를 출력하는 정도가 전부였습니다. 이 시기의 컴퓨터는 다음 그림처럼 중앙 컴퓨터에 더미 터미널 여러개를 연결했다고 합니다.
더미 터미널은 연산 능력은 없고, 입력(키보드)와 출력(모니터)만 할 수 있었습니다. 이 터미널은 지능은 없었지만 중앙 컴퓨터와 데이터를 주고 받는 기능을 가지고 있었습니다.
냉전이 한창이던 1957년 소련은 위성을 하늘에 쏘았고, 이는 미국을 자극했습니다. 자국보다 앞선 우주 기술을 가지고 있다는 것에 충격을 받았고, 각 분야는 빠르게 발전했습니다.
그 중 하나인 DARPA라는 기관은 군대를 위한 신기술을 개발하기 시작했습니다. 냉전 시대에 설립된 이 기관은 막대한 예산을 지원받으며 미군을 위한 연구를 진행했죠. DARPA의 본부는 알링톤에 있었고, 프로젝트는 상당수가 대학이나 외부 연구소에서 진행되었습니다. 각 연구기관의 축적된 연구 자료를 본부에 전달할 수 있는 유일한 방법은 택배였습니다. 믿을만한 요원에게 연구자료를 맡겨야했죠.
DARPA는 이를 해결하기 위해 네트워크와 네트워크를 연결하는 방법을 마련하기 위해 연구를 진행했습니다. 네트워크와 네트워크가 연결되면 한쪽 네트워크에 접속한 사용자는 다른 네트워크에 있는 컴퓨터에 접근할 수 있게 됩니다. 또 네트워크를 통해 다른 네트워크로 접속할 수 있게 됩니다. 이 방식을 이용해 DARPA는 연구기관을 잇는 회선을 일일히 구축하지 않고 연구소들의 컴퓨터를 연결했습니다. 이른바 DARPANET이라 불리던 이 네트워크는 점점 더 많은 연구기관으로 연결되고 세계로 연결되더니 1980년대 말에 이르러서는 인터넷이라는 국제 통신망을 형성하게 되었습니다.
TCP/IP 스택
컴퓨터끼리 네트워크에서 데이터를 주고 받기 위해 그 네트워크에서 사용하는 규칙인 프로토콜을 따라야합니다. 컴퓨터들이 네트워크를 통해 데이터를 주고 받기 위한 통신 규약을 의미합니다. 인터넷은 전 세계 네트워크 표준으로 자리 잡았고, 인터넷의 통신 프로토콜로 사용되는 TCP/IP는 실질적으로 인터넷 표준 프로토콜로 자리잡았습니다.
위의 그림은 TCP/IP의 규칙의 종류를 보여주고 있습니다. 이처럼 TCP/IP 프로토콜은 굉장히 많은 규칙의 집합입니다. 이 네트워크는 물리적인 통신선으로 어떤 재질로 만들어야 하는가에 대한 규칙. 1:1, 1:N 그리고 N:N 네트워크에서 대화 상대를 어떻게 판단하는가에 대한 규칙. 데이터 송수신할 때의 바이트 오더에 대한 규칙 등등이 그 예입니다. TCP/IP는 표준 프로토콜로, 인터넷에서 데이터를 주고 받는데 필요한 일련의 프로토콜 모음입니다. TCP/IP는 다음과 같이 4개의 계층으로 구성되어있으며, 계층이 포개져있는 형태때문에 TCP/IP 스택이라고 부릅니다.
계층을 분리할 때 여러가지 방식이 있는데 대표적으로 OSI 7계층(open system interconnection)이나, RFC 1122 4계층으로 나누는 방식이 있습니다. TCP/IP 프로토콜은 4계층으로 나누고 있습니다. 웹 브라우저, 메신저, 팟캐스트 등 어플리케이션의 데이터들은 모두 이 4계층을 오르내리고 있습니다.
왜 이렇게 계층으로 나누었을까요?
DARPANET에 기반한 인터넷은 점점 커졌고, 각 기능에 대한 요구사항을 해결하기 위해 전체 프로그램을 수정하였습니다. 이러한 비용을 줄이기 위해 프로그램을 계층으로 나누었습니다. 각각의 요구사항 해결할 때 다른 계층에 영향 미치지 않도록 각 계층은 인터페이스를 정의하게 됩니다. 계층의 내부는 인터페이스에 맞춰 요구사항을 해결하고, 각 계층의 통신은 인터페이스를 통해 이뤄지도록 구현하였습니다.
애플리케이션 계층
어떤 매체로 피자를 주문할지(프로토콜 지정 - 여기선 핸드폰 주문)와 어떤 언어로 주문(암호화, 복호화)할지 통화를 연결(세션 생성)하는 것까지를 포함해서 어플리케이션 계층에서 진행.
이 계층은 응용 프로그램 즉 개발자가 작성한 어플리케이션에 프로토콜들을 제공하는 계층입니다. 크롬이나, 파이어폭스, 이메일들의 응용 프로그램이 이 계층에 속하는 것이 아닌 어플리케이션이 사용하는 프로토콜들이 모여있는 계층입니다. 원격 로그인을 위한 TELNET, 파일 전송을 위한 FTP, 메일 전송을 위한 SMTP 그리고 웹 데이터를 주고 받기 위한 HTTP 등이 존재합니다. 각각의 프로토콜들은 하부 계층의 TCP나 UDP에 기반하여 동작합니다.
트랜스포트 계층
프로토콜에 따라 의심쩍은 피자를 검사하여 괜찮은 피자만 배달거나 피클이 빠졌을 때 다시 배달을 하는 것과 같은 신뢰성 작업을 합니다.
이름 그대로 패킷의 운송을 담당합니다. 그 중에서도 TCP(Transmission Control Protocol)은 보내는 쪽과 받는 쪽 간의 연결성을 제공하여, 신뢰할 수 있는 패킷 전송 서비스를 제공합니다(이를 Stream 방식으로 부르기도 합니다). 여러 개의 패킷을 보낼 때 순서를 보장하며, 패킷이 손실되거나 유실되면 그 부분을 재전송해주기도 합니다. TCP/IP에서 TCP가 바로 이 프로토콜을 가리키는 것이며, TCP는 IP가 제공하지 않는 연결성, 신뢰성을 제공합니다. HTTP를 비롯한 여러 프로토콜이 이 TCP와 IP 프로토콜 위에서 동작합니다.
이러한 TCP 프로토콜에 정의되어 있는 규칙을 조금 더 파보자면 다음의 4가지로 나눌 수 있습니다.
세션 관리(연결성)
TCP는 세션 관리를 통해 각 연결의 흐름을 제어하도록 정의되어 있습니다. 여기서 말하는
세션이란 서버가 해당 클라이언트와 데이터 통신을 하기 위해 제공하는 전용 통로
라고 생각 하시면 됩니다.일반적으로 클라이언트가 서버에 접속하기 위해서는 TCP 연결을 요청하게 되며, 서버쪽에서는 연결을 요청한 클라이언트를 위한 세션이 생성됩니다. 이 세션은 해당 클라이언트만 사용할 수 있는 유일한 통로가 됩니다. 이미 연결 되어 있는 클라이언트 외에 다른 클라이언트가 연결을 요청하면 해당 클라이언트를 위한 새로운 세션을 생성하게 됩니다. 생성되어 있는 세션은 해당 클라이언트와 통신하기 위해서 사용하며 다른 클라이언트가 사용하는 세션은 사용 할 수 없습니다. 이렇게 각각의 클라이언트에 따라 구분되어 있는 연결 관리는 서로 다른 클라이언트에서 전송한 패킷이 충돌되는 것을 방지함으로써 인터넷에서 데이터의 전송을 안전하게 보장 해 줍니다.
핸드 셰이크(신뢰성)
TCP는 핸드셰이크(HandShake)라 불리는 기법을 이용하여 인터넷에서 데이터가 유실되는 것을 방지하도록 정의되어 있습니다. 이는 TCP에서 데이터 전송 후 해당 데이터를 잘 받았다는 메시지를 받고, 알았다는 메시지를 보내 정의 되어 있는 것이 마치 악수하면서 인사하는 것과 비슷하다고 해서 유래된 이름입니다.
핸드셰이크는 일정한 시간이 흐른 후에도 데이터를 잘 받았다는 메시지가 도착하지 않으면 데이터가 유실되었다고 판단하여 데이터를 재전송 하게 됩니다. 이렇게 꼼꼼하게 데이터의 확인 과정을 거치면서 네트워크 상황이 좋지 않아서 중간에 데이터가 유실되는 상황이 벌어지더라도 데이터의 신뢰성을 확보 할 수 있습니다.
네트워크 상에서 패킷을 전송할 때 패킷의 유실 위험을 막기 위해 데이터를 전송하고 응답 패킷(ACK)이 올 때까지 기다렸다가 또 다음 패킷을 보내고 응답 패킷(ACK)을 받는 방법입니다. TCP는 이런 방법을 통해서 데이터의 유실을 막고 신뢰성 있는 데이터 전송을 보장해 줍니다.
패킷 순서 조합
핸드셰이크 같이 데이터를 하나씩 전송하고 확인하는 과정을 거치면 데이터의 신뢰성을 보장할 수 있는 장점이 생기지만 데이터 전송 속도가 떨어지는 문제점이 발생할 수 있습니다. 아무리 데이터의 신뢰성이 보장되더라도 데이터 전송 속도가 너무 떨어지면 사용하기에 불편한 프로토콜이 될 것입니다.
이렇게 전송 속도가 떨어지는 문제점을 보완하기 위해 나온 것이 패킷의 순서 조합입니다. 이는 데이터에 번호를 부여한 다음에 메시지의 전송 속도가 떨어지는 것을 막기 위해 여러 개의 데이터를 한 번에 보내는 방법입니다. 데이터를 받은 곳에서는 데이터의 순서에 맞추어 데이터를 정렬하고 데이터를 잘 받았다는 메시지를 전송해줍니다.
포트를 이용한 서비스 다중화
네트워크를 통한 장치에서 인터넷을 사용하기 위해 설정하는 것은 IP 주소 밖에 없습니다. 그렇다면 단 하나의 IP 주소를 통하여 여러 가지 프로그램은 어떻게 동작할 수 있을까요? 그 정답은 TCP 프로토콜에 있는 포트라는 개념입니다.
TCP에서 IP는 주소 외에도 포트라는 개념이 있어 우리가 사용하는 애플리케이션 포트를 하나씩 할당해 줍니다. 각각의 애플리케이션은 자신에게 할당 된 포트를 이용하여 통신할 데이터를 주고 받게 됩니다.
포트가 필요한 이유?
유스페이스 A동(IP주소)에 호수(포트번호)라고 이해하면 편합니다. 유스페이스 A동에 만약 피자집만 존재한다면 유스페이스 A동을 통해서 주문을 해도 될 겁니다. 하지만 치킨 집, 곱창 집이 들어오게 되면 각 호수에 대한 주소가 따로 필요하겠죠. 이를 위해 존재하는 것이 포트번호입니다.
하지만 TCP 프로토콜에는 장점만 있는 것이 아닙니다. 데이터가 작을 경우 하나의 데이터만 보내도 되며 이 경우 순서 보장에 대한 이슈는 사라지게 됩니다. 또한 꼭 받아야하는 데이터가 아닌 경우 재전송이 필요없겠죠. 작고, 신뢰성을 요구하지 않는 데이터는 필요 없는 기능이 붙어 전송이 더뎌지게 됩니다.
트랜스포트 계층은 이런 문제를 해결하기 위해 또 다른 프로토콜인 UDP(User Datagram Protocol)을 제공합니다. 이는 연결성, 순서, 신뢰성 모두 제공하지 않지만 성능이 더 우수합니다(이를 데이터그램 방식이라고 부르기도 합니다).
네트워크(인터넷) 계층
네비게이션을 키고 가장 빠른 길을 찾아서 찾아가는 것과 같습니다.
네트워크 계층은 패킷을 수신해야할 상대의 주소를 지정하고, 나가는 패킷에 대해서 적절한 크기로 분할하며 들어오는 패킷에 대해서는 재조립을 수행합니다. 이 계층에서 사용되는 규약이 바로 IP(Internet Protocol)입니다. TCP/IP에서 한 부분을 차지하는 중요한 부분이죠.
IP는 내보낸 패킷을 상대방이 잘 수령했는지에 대해 보장하지 않습니다. 택배로 비유하여 소포가 배달 중 문제가 생겨 파손되거나 분실되도 전혀 책임을 지지 않는 악덕 택배회사죠. 택배를 잘 수령했는지 여부를 파악하는 기능 자체가 없습니다. 그저 트랜스포트 계층에서 내려온 패킷에 주소를 붙여 링크 계층으로 보낼 뿐입니다. 이 때문에 여러 개의 소포를 보낼 때 순서대로 도착하지 않아도 이상할 것이 없습니다.
링크(네트워크 인터페이스) 계층
TCP/IP는 네트워크 물리적 구성으로부터 독립적인 프로토콜입니다. 컴퓨터가 네트워크에 물리적으로 전화선 모뎀으로 연결되던, LAN에 이더넷 케이블로 연결되던, Wi-Fi로 연결되어 있던 신경쓰지 않습니다. 이 것은 링크계층에서 네트워크의 물리적인 연결 매체를 통해 패킷을 주고받는 작업을 담당해주기 때문입니다.
가령 어떤 패킷이 네트워크를 통해 들어오면 먼저 이 링크 계층에 들어오게 됩니다. 링크 계층은 이 패킷에서 물리적 데이터 전송에 사용되던 부분(패킷의 헤더나 푸터)를 제거하고 인터넷 계층에 넘깁니다. 이렇게 함으로서 네트워크 계층에서는. 어떤 물리적인 장치로 패킷이 넘어왔던 신경쓰지 않고 처리를 시작할 수 있게 됩니다.
패킷이란?
패킷은 "소포"라는 뜻의 영단어입니다. 네트워크를 통해 오고가는 데이터를 패킷이라고 부릅니다. 그 이유는 "내용물"인 데이터를 애플리케이션 계층, 트랜스포트 계층, 네트워크 계층, 링크 계층에서 각각 필요한 정보들을 포장해서 보내기 때문입니다. 그리고 받을 때도 각 계층에서는 포장지를 한겹 한겹 벗겨서 데이터를 얻어내죠.
더 많은 정보는 다음의 유튜브 동영상을 확인하세요.
Socket 프로그래밍
소켓이란?
네트워크는 간단하게 말해서 네트워크에 연결되어 있는 서로 다른 두 컴퓨터가 데이터를 주고 받는 것 입니다. 이것이 전부입니다! 이를 위해선 물리적 연결이 우선 필요합니다. 하지만 대부분의 컴퓨터는 이미 물리적 연결이 이루어져 있으므로 신경쓰지 않도록 합니다. 그 다음으로는 물리적 연결을 기반으로 하는 소프트웨어적인 데이터 송수신 방법을 고민하면 됩니다. 하지만 운영체제에서 이미 소켓이라는 것을 제공하기 때문에 데이터 송수신의 원리를 잘 몰라도 소켓을 통해서 데이터를 주고 받을 수 있습니다. 그래서 네트워크 프로그래밍을 소켓 프로그래밍이라고도 하죠.
그렇다면 왜 소켓이라는 말을 쓸까요? 우리는 전력망으로부터 전기를 공급 받기 위해 소켓을 꽂죠. 마찬가지로 멀리 떨어져있는 컴퓨터와 데이터를 송수신 하기위해 인터넷이라는 네트워크망에 연결을 해야합니다. 프로그래밍에서의 소켓은 네트워크 망에 연결하는 도구가 되는 것입니다.
소켓의 유형
소켓의 유형에는 TCP/IP 프로토콜 기반의 Stream 방식과 UDP/IP 프로토콜 기반의 Datagram 방식이 있습니다.
Stream 방식
- 가장 큰 특징은 양방향 연결이 필요하다는 것입니다. 또한 보낸 곳에서 받는 곳까지 데이터가 소실되거나 변하지 않게 보장해 주며 보낸 순서대로 받을 수 있게 해줍니다. 하지만 보낸 한 개의 패킷을 여러 개로 나누어 받거나 반대로 여러 개의 패킷을 한 개로 뭉쳐서 받을 수 있으니 그에 대한 적절한 처리를 따로 해주어야 합니다.
Datagram 방식
- 스트림 방식과는 달리 양방향 연결이 필요 없고 보낸 데이터가 중간에 소실 될 수 있다는 특징을 가지고 있습니다. 언제 어떻게 소실될지는 여러 가지 이유로 달라 질 수 있으므로 에측하기 어렵습니다. 또한 먼저 보낸 데이터를 나중에 보낸 데이터보다 늦게 받을 수 있으며, 한 개의 데이터는 여러개로 쪼개짐 없이 받을 수 있습니다.
이번 스터디에서는 Stream을 다뤄보도록 하겠습니다.
소켓 통신 과정
자 그럼 소켓을 이용해 어떤 절차를 가지고 데이터를 주고 받는지 알아보도록 하겠습니다. (Stream Socket을 기반으로 한 설명입니다.)
전화기의 통신 과정
소켓은 전통적으로 전화기를 빗대어 많이 설명을 합니다. 네트워크의 통신도 전화기 통신과 마찬가지이기 때문에 유사하게 동작하는 것이죠. 일반적으로 전화기를 통해 통화를 할 때 다음과 같은 절차를 거칩니다.
소켓의 통신 과정
소켓의 통신은 위에서 다룬 전화기의 통신 방식과 거의 동일합니다.
실제 코드
실제 코드에서는 다음과 같이 사용합니다.
소켓 통신 들여다보기
1. server 소켓 생성과 listen
서버에서 전화를 받기 위해 전화기를 생성하고 전화번호를 192.168.1.102:80으로 부여한 후 네트워크에 연결하여 listen 상태로 만듭니다.
그림
코드
// Server 1. 전화기 생성
Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.TCP);
// Server 2. 상대방에게 연결되기 위해 전화 번호를 부여
var endpoint = new IPEndPoint (IPAddress.Parse ("192.168.1.102"), 80);
socket.Bind (endpoint);
// Server 3. 전화를 통신망에 케이블로 연결
socket.Listen (backlog);
2. connect을 위한 client 소켓 생성
이제 전화를 거는 클라이언트에서 전화기를 생성합니다.
그림
코드
// Client 1. 전화기 생성
Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.TCP);
var endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.102"), 80);
3. client 소켓에서 server 소켓으로 메시지 전송
이제 클라이언트 전화기에서 서버 전화기로 연결 요청을 합니다.
그림
코드
// Client 2. 상대방에게 연결하기
socket.Connect(endpoint);
4. server에서 새로운 소켓 생성 후 처리
서버가 클라이언트의 요청을 받으면 통신을 위한 새로운 소켓을 생성합니다. 그리고 이 소켓은 클라이언트 소켓의 IP 주소와 포트번호를 사용합니다. 이제 TCP 연결 세션이 생성되었습니다.
그림
코드
// Server 4. 수화기를 들어 전화 받기
var newClient = socket.Accept();
5. server Socket에서 client 소켓으로 메시지 전송
이제 서버와 클라이언트가 서로 소켓을 이용해 통신(읽기, 쓰기)를 합니다.
6. 소켓 Close
모든 통신이 끝나면 소켓을 종료합니다.
그림
코드
// 종료
socket.Close();
다음 주제
- 오늘 배워본 TCP 프로토콜을 사용하는 소켓 통신을 각자 구현해봅시다. 링크
'Basic > C#' 카테고리의 다른 글
[c#] async / await 사용 예시 (0) | 2019.03.27 |
---|---|
[C#] CS0120: non-static field 에러 (0) | 2019.03.19 |
C# 클래스 인스턴스 하나만 만드는 방법 (0) | 2016.12.14 |