소켓에서 버퍼링을 하는 이유는 성능 최적화와 데이터 무결성 보장이다.

 

시스템 호출 최소화

소켓을 통해 데이터를 주고받을 때, 시스템 호출( send(), recv() )은 매우 비용이 크다

  • 네트워크 입출력은 커널 공간과 유저 공간을 오가야 하는데, 시스템 호출이 발생할 때마다 문맥교환이 일어난다.
  • 문맥교환은 오버헤드가 크기 때문에, 자주 호출하는 것보다 한 번에 큰 덩어리로 처리하는 것이 훨씬 효율적이다.
  • 버퍼를 사용하면 소량의 데이터를 보낼 때마다 시스템 호출을 하는 것이 아닌, 일정 크기만큼 모아서 (=버퍼링) 한 번에 보냄으로써 성능 향상을 기대할 수 있다.

 

네트워크 트래픽 감소

  • 네트워크는 패킷 단위로 데이터를 전송하는데, 너무 작은 패킷을 자주 전송하면 오버헤드와 지연이 발생한다.
  • 버퍼링을 사용하면 작은 데이터 여러 개를 하나의 패킷으로 묶어서 전송하여 네트워크 부하를 줄일 수 있다.

 

데이터 손실 방지

  • 송신 측과 수신 측의 속도가 다를 수 있다. ( 예: 빠른 서버 <-> 느린 클라 )
  • 만약 버퍼가 없다면, 수신 속도가 느릴 때 송신된 데이터가 사라질 수 있다.
  • 이를 방지하기 위해 수신 버퍼를 사용하여 데이터가 안정적으로 도착할 때까지 저장해야한다.

 

패킷 순서 보장 및 데이터 무결성 유지

  • TCP와 같은 프로토콜에서는 패킷이 순서대로 도착하도록 버퍼를 활용하여 정렬 및 재조합을 한다.
  • 예를 들어, 네트워크 상태가 불안정할 경우 패킷이 순서대로 도착하지 않을 수도 있는데, 버퍼를 사용하여 이를 재조립한다.

 

위와 같은 이유로 버퍼링이 꼭 필요하다.

네이글 알고리즘은 네트워크에서 작은 데이터 패킷이 과도하게 전송되는 것을 방지하여 대역폭 사용을 최적화하고
혼잡을 줄이기 위한 알고리즘이다.

 

앞서 언급했듯이 소켓은 본질적으로 파일이라고 생각할 수 있다.

그러므로 소켓도 버퍼를 사용하게 되는데, 소켓에는 입력 버퍼와 출력 버퍼 2가지가 있다.

 

소켓에 send를 호출하면 우리가 보내고자 하는 내용이 소켓의 출력 버퍼에 복사된다.

복사된 데이터가 TCP 레이어에서 Segment가 되고, IP 레이어에서 Packet이 된다. 

 

Packet은 인터엣에서의 유통의 단위다. 네트워크에서 속도를 2가지로 정의 하는데, 하나는 bps고 다른 하나는 pps다.

bps는 초당 비트가 얼마만큼 전송이 되즌지를 나타내고, pps는 초당 패킷이 얼마만큼 전송 되는지를 나타낸다.

pps보다는 bps가 높아야 좋은 상황이라고 생각하면 된다.

 

packet은 Header와 payload로 구성되는데, 여기서 Header가 대략 40바이트의 크기를 갖는다.

만약 hello라는 문자열을 전송한다고 생각하면, 겨우 5바이트를 전송하려고 40바이트를 붙이는 아이러니한 상황이 생기게된다.

 

버퍼에 데이터를 많이 담아서 전송하면 bps가 증가하게 되는 것이므로 해당 알고리즘을 만들게 되었는데 이를 Nagle 이라 한다.

 

📌 네이글 알고리즘 동작 원리

네이글 알고리즘의 핵심 아이디어는 이전 패킷에 대한 ACK를 받기 전까지는 작은 패킷을 계속해서 모으는 것이다.

동작 과정

  1. 전송할 데이터가 MSS보다 크면 즉시 전송한다.
  2. 전송할 데이터가 MSS보다 작은데 이전 패킷에 대한 ACK를 받지 않았으면, 현재 데이터를 버퍼에 저장하고 추가 데이터를 기다린다. ACK를 받았으면, 즉시 새로운 패킷을 보낸다.

위처럼 동작하면 작은 데이터가 여러 개 있을 때, 첫 번째 데이터가 전송된 후 ACK을 받을 때까지 기다렸다가 한꺼번에 보낼 수 있어 네트워크 부하를 줄일 수 있다.

 

📌 네이글 알고리즘 단점

네이글 알고리즘이 항상 유리한 것은 아니다. 일부 환경에서 문제가 될 수 있다.

 

대기 시간이 중요한 프로그램에서의 문제

  • 실시간 프로그램( 게임, 금융 거래 등 )
    • 네이글 알고리즘이 적용되면 작은 데이터가 즉시 전송되지 않기 때문에 지연이 증가할 수 있다.
Echo Server는 클라이언트가 보낸 데이터를 그대로 다시 반환하는 서버를 말한다.
즉, 클라가 서버에 메세지를 전송하면, 서버는 그 메세지를 그대로 클라이언트에게 다시 보낸다.

 

🔹 Echo Server, Echo Client 의 주요 특징

  • 구현이 간단하기 때문에 네트워크 프로그래밍을 학습하는 초보자에게 적합하다.
  • 클라이언트와 서버 간 통신이 정상적으로 이루어지는지 확인할 때 유용하다.

 

TCP 기반 Echo Server

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

int main()
{
    // 윈속 초기화
    WSADATA wsa = { 0 };
    if(::WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
    {
        puts("ERROR: 윈속을 초기화 할 수 없습니다.");
        return 0;
    }
    
    // 1. 접속대기 소켓을 생성한다.
    SOCKET hSocket = ::socket(AF_INET, SOCK_STREAM, 0);
    if(hSocket == INVALID_SOCKET)
    {
        puts("ERROR: 접속 대기 소켓을 생성할 수 없습니다.");
        return 0;
    }
    
    // 2. 포트 바인딩
    SOCKADDR_IN svraddr = { 0 };
    svraddr.sin_family = AF_INET;
    svraddr.sin_port = htons(25000);
    svraddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
    if(::bind(hSocket, (SOCKADDR*)&svraddr, sizeof(svraddr)) == SOCKET_ERROR)
    {
        puts("ERROR: 소켓에 IP주소와 포트를 바인드 할 수 없습니다.");
        return 0;
    }
    
    // 3. 접속대기 상태로 전환
    if(::listen(hSocket, SOMAXCONN) == SOCKET_ERROR)
    {
        puts("ERROR: 리슨 상태로 전환할 수 없습니다.");
        return 0;
    }
    
    // 4. 클라이언트 접속 처리 및 대응
    SOCKADDR_IN clientaddr = { 0 };
    int nAddrLen = sizeof(clientaddr);
    SOCKET hClient = 0;
    char szBuffer[128] = { 0 };
    int nReceive = 0;
    
    // 4.1 클라이언트 연결을 받아들이고 새로운 소켓을 생성한다. (개방)
    while((hClient = ::accept(hSocket,
        (SOCKADDR*)&clientaddr,
        &nAddrLen)) != INVALID_SOCKET)
    {
        puts("새 클라이언트가 연결되었습니다."); fflush(stdout);
        // 4.2 클라이언트로부터 문자열을 수신한다.
        while((nReceive = ::recv(hClient, szBuffer, sizeof(szBuffer, 0)) > 0)
        {
            // 4.3 수신한 문자열을 그대로 전송한다.
            ::send(hClient, szBuffer, sizeof(szBuffer), 0);
            puts(szBuffer); fflush(stdout);
            memset(szBuffer, 0, sizeof(szBuffer));
        }
        
        // 4.4 클라이언트가 연결을 종료한다.
        ::shutdown(hClient, SD_BOTH);
        ::closesocket(hClient);
        puts("클라이언트 연결에 끊겼습니다."); fflush(stdout);
    }
    
    // 5. 리슨 소켓 닫기
    closesocket(hSocket);
    
    // 윈속을 해제 한다.
    ::WSACleanup();
    return 0;
}

 

 

TCP 기반 Echo Client

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


int main()
{
	// 윈속 초기화
	WSADATA wsa = { 0 };
	if (::WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
	{
		puts("ERROR: 윈속을 초기화 할 수 없습니다.");
		return 0;
	}

	//1. 접속대기 소켓 생성
	SOCKET hSocket = ::socket(AF_INET, SOCK_STREAM, 0);
	if (hSocket == INVALID_SOCKET)
	{
		puts("ERROR: 소켓을 생성할 수 없습니다.");
		return 0;
	}

	//2. 포트 바인딩 및 연결
	SOCKADDR_IN	svraddr = { 0 };
	svraddr.sin_family = AF_INET;
	svraddr.sin_port = htons(25000);
	svraddr.sin_addr.S_un.S_addr = inet_addr("192.168.77.2");
	if (::connect(hSocket,
		(SOCKADDR*)&svraddr, sizeof(svraddr)) == SOCKET_ERROR)
	{
		puts("ERROR: 서버에 연결할 수 없습니다.");
		return 0;
	}

	//3. 채팅 메시지 송/수신
	char szBuffer[128] = { 0 };
	while (1)
	{
		//사용자로부터 문자열을 입력 받는다.
		gets_s(szBuffer);
		if (strcmp(szBuffer, "EXIT") == 0)
        {
            break;
        }

		//사용자가 입력한 문자열을 서버에 전송한다.
		::send(hSocket, szBuffer, strlen(szBuffer) + 1, 0);
		//서버로부터 방금 보낸 문자열에 대한 에코 메시지를 수신한다.
		memset(szBuffer, 0, sizeof(szBuffer));
		::recv(hSocket, szBuffer, sizeof(szBuffer), 0);
		printf("From server: %s\n", szBuffer);
	}

	//4. 소켓을 닫고 종료.
	//::shutdown(hSocket, SD_BOTH);
	::closesocket(hSocket);
	//※윈속 해제
	::WSACleanup();
	return 0;
}

 

🔹 Wire shark로 연결 상태 확인

앞서 배운 내용 처럼 서버를 실행하고 클라를 실행한후 port를 25000으로 지정하면 

3 Way Handshake를 수행한 결과를 위 그림처럼 와이어 샤크로 확인할 수 있다. [SYN], [SYN, ACK], [ACK]

 

 

일반적인 데이터 주고 받을때

 

 

일반적인 종료 상황에서의 4 Way Handshake

웹서버

 

웹서버는 HTTP를 이용해 인터넷 상에서 클라이언트의 요청을 처리하고 응답해주는 프로그램이다.

HTTP는 기본적으로 TCP를 사용하지만, 필요에 따라 TCP, UDP 프로토콜 또한 사용한다.

웹서버는 클라이언트의 HTTP 요청을 받아 정적인 콘텐츠 ( HTML, CSS, 이미지 파일 등 )를 제공한다.

 

웹 어플리케이션 서버

웹 어플리케이션 서버

 

웹 어플리케이션 서버 ( WAS, Web Application Server )는 웹 서버와 협력해 동적인 컨텐츠를 제공한다.

클라이언트의 요청을 웹 서버로부터 전달받아 처리하고, 결과를 다시 웹 서버에 반환하여, 최종적으로 클라이언트가

응답을 받을 수 있도록 구성한다.

복잡한 데이터를 가공하거나 다양한 비즈니스 로직을 수행하기 때문에 정적인 데이터만 전달하는 웹 서버에 비해

처리 시간이 길어질 수 있다.

웹 어플리케이션 서버는 콘텐츠 생성이나 데이터베이스와의 상호 작용이 필요할 때 주로 사용한다.

웹 브라우저

웹 브라우저는 인터넷 브라우저라고도 불리며, 웹 서버로부터 정보를 요청하고 받아 사용자에게 보여주는 소프트웨어다.

 

웹 브라우저는 인터넷 상의 다양한 정보를 조회하고 접근한다. 우리가 일반적으로 사이트에 접속했을때,

HTML, CSS, Javascript 파일을 전달받아 이를 해석하고 화면에 보여준다.

이 과정에서 웹 브라우저는 정적(Static)파일과 동적(Dynamic)정보를 처리하게 된다. 정적 웹페이지는 서버에서 브라우저로 전송되는 그대로 표시되나, 동적 웹 페이지는 서버로부터 데이터를 받아 브라우저가 실시간으로 내용을 생성 또는 변경한다.

 

대표적인 웹 브라우저에는 Internet Explorer, Chrome, Firefox, Safari 등이 있다.

 

웹 브라우저의 통신방식

브라우저의 통신 방식은 아래와 같다.

 1. 사용자가 웹 브라우저의 주소창에 URL을 입력한다.

 2. 웹 브라우저는 입력받은 URL을 DNS 서버로 전달해 해당 IP 주소를 찾게 된다.

 3. DNS 서버는 도메인 이름을 IP 주소로 변환한다.

 4. 웹 브라우저는 해당 IP 주소로 HTTP 요청을 전달한다.

 5. IP 주소에 연결된 웹 서버는 요청을 받아 처리한다.

 6. 웹 서버는 처리 결과를 HTTP Response로 브라우저에게 전달한다.

 7. 웹 브라우저는 받은 HTTP Response을 바탕으로 사용자에게 표시한다.


URL

URL

 

URL ( Uniform Resource Locator )은 인터넷 상의 리소스 위치를 나타내기 위해 사용한다. ( = 인터넷 상의 주소 )

 

웹 브라우저는 주소창에서 원하는 인터넷 리소스를 조회하기 위해 URL을 입력한다.

여기서 URL은 <프로토콜>://<도메인 명>:<포트>/<경로>의 구조를 가지며,

이는 웹서버의 특정한 리소스의 위치를 가리키게 된다.

 

예를 들어, 'http://cafe.naver.com/joonggonara' 라는 URL을 분석해 보면,

'http'는 프로토콜을 나타내고, 'cafe.naver.com'은 'naver.com'이라는 메인 도메인 명과 'cafe'라는 서브 도메인 명으로

이루어져 있으며, 'joonggonara'는 서버에서 리소스 경로를 가리키게 된다. 

즉, 중고나라 라는 카페를 가르키게 된다.

 

이렇게 URL을 통해 웹 브라우저는 웹 서버의 특정 리소스에 대한 위치를 파악하고 요청을 전달하게 된다.

웹 브라우저에 'cafe.naver.com' 이라고 입력하면, 브라우저는 'cafe.naver.com' 서버의 메인 페이지를 요청하고,

해당 서버가 보내는 데이터를 받아 웹 브라우저에 보여줌으로써 웹 페이지를 조회할 수 있게 된다.


DNS

DNS

 

DNS ( Domain Name Service )는 도메인 이름을 중개해서, IP로 변경해주는 서비스를 제공한다. ( = 인터넷 상의 연락처 )

 

만약 'blog.naver.com' 주소를 웹 브라우저 주소창에 입력하면 대응 되는 정보를 조회하게 된다.

'blog.naver.com'과 같이 영어, 숫자, 특수문자롸 이루어진 URL을 IP로 변환해주는 역할을 하는 서비스를

DNS ( Domain Name Service ) 라고 하는것 이다.

 

인터넷 상의 각각의 리소스들은 고유의 IP 주소를 가지고 있다.

이 IP 주소는 숫자와 점 ( . )으로 이루어져 있어, 사람이 외우기 어렵고, 무슨 정보를 나타내는지 이해하기 어렵다.

이 때 DNS를 이용하면, 사용자가 IP를 사용하지 않고도 더욱 편리하게 해당하는 인터넷의 리소스에 접근할 수 있다.

 

DNS는 인터넷의 주소록 또는 연락처와 같은 역할을 하게 된다. 


HTTP, HTTPS 차이

 

HTTP

 

HTTP ( HyperText Transfer Protocol ) 는 문서( 하이퍼텍스트 )를 전송하기 위한 프로토콜로,

서버와 클라이언트 사이에서 어떻게 메세지를 교환할지를 정해 놓은 규칙이다.

요청 ( Request )과 응답 ( Response )으로 구성되어 있고, 일반적으로 80번 포트를 사용한다.

서버와 브라우저의 관계로 간단히 설명하자면,

1. 브라우저는 서버에게 자신이 원하는 페이지를 요구( Request )한다.

2. 서버는 브라우저가 원하는 페이지가 있는지 확인하고, 있을 경우 해당 페이지에 대한 데이터를

    반환( Response )해준다. 

3. 브라우저는 서버에게 전달 받은 데이터를 기반으로 브라우저에 그려준다.

위 경우에 한해 데이터는 어떠한 데이터든 주고 받는게 가능하다.

 

HTTPS

HTTPS는 HTTP를 기반으로 데이터 통신의 안전성을 높이기 위해 암호화 기능이 포함된 통신 프로토콜이다.

 

일반적으로 443번 포트를 사용한다. 

엄밀히 말해 HTTPS는 HTTP와 별개의 프로토콜은 아니다.

HTTPS는 단순히 HTTP 프로토콜을 통해 TLS/SSL 암호화를 사용한다.

개방형 시스템 상호 연결( OSI ) 모델은 표준 프로토콜을 사용해 다양한 통신 시스템이 통신할 수 있도록 국제표준화기구에서 만든 개념 모델이다. 쉽게 말하면 OSI는 상이한 컴퓨터 시스템이 서로 통신할 수 있는 표준을 제공한다.

 

OSI 모델은 컴퓨터 네트워킹의 범용 언어로 볼 수 있다.

이 모델은 통신 시스템을 7개의 추상적 계층으로 나누고, 각 계층은 다음 계층 위에 스택된다.

OSI 7계층

 

OS 모델의 각 계층은 특정 작업을 처리하고 그 위와 아래의 계층과 통신한다.

 

7. 응용 프로그램 계층 ( 애플리케이션 계층 )

응용 프로그램 계층 ( 애플리케이션 계층 )

 

이 계층은 사용자의 데이터와 직접 상호 작용하는 유일한 계층이다.

웹 브라우저 및 이메일 클라와 같은 소프트웨어 앱은 통신을 개시하기 위해 애플리케이션 계층에 의지한다.

다만, 앞서 언급한 앱들은 애플리케이션 계층의 일부가 아니라는 점을 알아야한다.

애플리케이션 계층은 소프트웨어가 사용자에게 의미 있는 데이터를 제공하기 위해 프로토콜과

데이터를 조작하는 역할을 한다는 점을 알고 있어야한다.

 

애플리케이션 계층에는 HTTP, FTP, SMTP, Telnet 등과 같은 프로토콜이 포함된다.


6. 프레젠테이션 계층 ( 표현 계층 )

프레젠테이션 계층 ( 표현 계층 )

 

이 계층은 주로 데이터를 준비하는 역할을 하고, 애플리케이션 계층이 이를 사용할 수 있게 한다.

다시말해, 계층 6은 애플리케이션이 소비할 수 있도록 데이터를 프레젠테이션한다.

프레젠테이션 계층을 데이터의 변환, 암호화, 압축을 담당한다.

 

서로 통신하는 두 개의 통신 장치는 서로 다른 인코딩 방법을 사용할 수 있어서, 계층 6은 수신 장치의 애플리케이션 계층이 이해할 수 잇는 구문으로 수신 데이터를 변환하는 일을 담당한다. 예를 들면, EBCDIC로 인코딩된 문서 파일을 ASCII로 인코딩 된 파일로 바꿔주는 작업 등을 말한다.

 

장치가 암호화된 연결을 통해 통신하는 경우, 계층 6은 최종 송신자에게 암호화를 추가할 뿐만 아니라 최종 수신자에게 암호화를 디코딩하여 암호화되지 않은 읽기 쉬운 데이터로 애플리케이션 계층을 제시할 수 있도록 하는 역할을 한다.

 

마지막으로, 프레젠테이션 계층은 애플리케이션 계층에서 수신한 데이터를 계층 5로 전송하기 전에 압축하는 일도 담당합니다. 전송할 데이터의 양을 최소화함으로써 통신의 속도와 효율을 높이는 데 도움이 된다.


5. 세션 계층 

세션 계층

 

두 기기 사이의 통신을 시작하고 종료하는 일을 담당하는 계층이다. 통신이 시작될 때부터 종료될 때까지의 시간을 세션이라 한다. 세션 계층은 교환되고 있는 모든 데이터를 전송할 수 있도록 충분히 오랫동안 세션을 개방한 다음 리소스를 낭비하지 않기 위해 세션을 즉시 닫을 수 있도록 보장한다.

 

또한 세션 계층은 데이터 전송을 체크포인트와 동기화한다. 예를 들어, 100MB의 파일이 전송되는 경우 세션 계층이 5MB마다 체크포인트를 설정할 수 있다. 52MB가 전송 된 후 연결이 끊어 지거나 충돌이 발생하면 마지막 체크 포인트에서 세션을 재개하는 것이 가능하다. 즉, 50MB의 데이터만 더 전송하면 된다. 체크 포인트가 없으면 전체 전송을 처음부터 다시 시작해야 한다.


4. 전송 계층

전송 계층

 

계층 4는 두 기기 간의 종단 간 통신을 담당한다. 여기에는 세션 계층에서 데이터를 가져와서 계층 3으로 보내기 전에 세그먼트라고하는 조각으로 분할하는 일이 포함된다. 수신 기기의 전송 계층은 세그먼트를 세션 계층이 이용할 수 있는 데이터로 재조립해야 한다.

전송 계층은 또한 흐름 제어 및 오류 제어 기능의 역할을 한다. 흐름 제어는 연결 속도가 빠른 송신자가 연결 속도가 느린 수신자를 압도하지 않도록 최적의 전송 속도를 결정한다. 전송 계층은 수신된 데이터가 완료되었는지 확인하고 수신되지 않은 경우 재전송을 요청하여 최종 수신자에 대해 오류 제어를 수행한다.

 

전송 계층 프로토콜에는 TCP 및 UDP 가 있다.


3. 네트워크 계층

네트워크 계층

 

네트워크 계층은  서로 다른 두 네트워크 간 데이터 전송을 용이하게 하는 역할을 한다. 서로 통신하는 두 장치가 동일한 네트워크에 있는 경우에는 네트워크 계층이 필요하지 않다. 네트워크 계층은 전송 계층의 세그먼트를 송신자의 장치에 패킷이라고 불리는 더 작은 단위로 세분화하여 수신 장치에서 이러한 패킷을 다시 조립한다. 또한, 네트워크 계층은 데이터가 표적에 도달하기 위한 최상의 물리적 경로를 찾는데 이를 라우팅이라 한다.

 

네트워크 계층 프로토콜에는 IP, ICMP 등이 있다.


2. 데이터 연결 계층

데이터 연결 계층

 

데이터 연결 계층은 네트워크 계층과 매우 비슷하지만, 데이터 연결 계층은 동일한 네트워크에 있는 두 개의 장치 간 데이터 전송을 용이하게 한다. 데이터 연결 계층은 네트워크 계층에서 패킷을 가져와서 프레임이라고 불리는 더 작은 조각으로 세분화한다. 네트워크 계층과 마찬가지로 데이터 연결 계층도 인트라 네트워크 통신에서 흐름 제어 및 오류 제어를 담당한다.(전송 계층은 네트워크 간 통신에 대해서만 흐름 제어 및 오류 제어만을 담당함).

 

대표적인 장비로 스위치가 있다.


1. 물리 계층

물리 계층

 

이 계층에는 케이블, 스위치 등 데이터 전송과 관련된 물리적 장비가 포함된다.

주로 전기적, 기계적, 기능적인 특성을 이용해 통신 케이블로 데이터를 전송하게 된다.

이 계층에서는 단지 데이터를 전달만 할뿐 전송하려거나 받으려는 데이터가 무엇인지, 어떤 에러가 있는지

등에는 전혀 신경쓰지 않는다.

이 계층은 또한 1과 0의 문자열인 비트 스트림으로 변환되는 계층이다.

뿐만 아니라 두 장치의 물리적 계층은 신호 규칙에 동의해서 두 장치의 1이 0과 구별될 수 있어야 한다.

 

대표적인 장비로는 통신 케이블, 리피, 허브 등이 있다.

 

참고 : https://www.cloudflare.com/ko-kr/learning/ddos/glossary/open-systems-interconnection-model-osi/

 

 

 

+ Recent posts