네트워크 프로그래밍에서 바이트 주소를 읽는 방식에 따라서 빅엔디안과 리틀엔디안으로 나뉜다.

CPU의 종류에 따라서 바이트 주소를 읽는 방식이 다르다는 의미이다.

 

기본적으로 TCP/IP 통신은 데이터를 읽는 방식을 빅엔디안 방식으로 통일해서 사용한다.

그래서 기본적으로 소켓을 설정할 때 htons, htonl을 사용하는 형식을 봤을 것이다.

** Write Read 함수에 내부적으로 엔디안 처리가 되어 있기 때문에, 소켓통신 포트와 Ip 변환해주면 된다.

빅엔디안 (IBM, SPARC, Motorola)

빅엔디안은 네트워크바이트오더 형식으로 데이터를 읽는다.

0x1234

htons (Host to Network Short)

- port 변환 시 사용함수

htonl (Host to Network Long)

- ip 변환 시 사용함수

리틀엔디안 (Intel x86, AMD , Arm, DEC)

리틀엔디안은 호스트바이트오더 형식으로 데이터를 읽는다.

0x3412

ntohs (Network to Host Short)

- port 변환 시 사용함수

ntohl (Network to Host Long)

- ip 변환 시 사용함수

UDP에서 유명한 멀티캐스팅(Multi Casting)과 브로드캐스팅(Broad Casting)에 대해서 알아보자.

 

*참고 유니캐스트(Unicast)는 1대1 통신, 멀티캐스팅과 브로드캐스팅은 1대 다통신이다. 

멀티캐스팅 (MultiCasting)

UDP 소켓 기반

멀티캐스팅은 TTL 개념이 있다. (Time-To-Live)

TTL 설정 값에 따라서 해외까지 송출이 가능하다. 

한 번만 전송하기 때문에 전송방식은 같지만 트래픽 양이 적다.

멀티캐스트 그룹을 대상으로 데이터를 딱 한 번 전송한다.

TTL이 라우터 거친 수에 따라서 1씩 감소하고, 0이되면 패킷이 소멸된다.

 

브로드캐스팅(BroadCasting)

UDP 소켓 기반

1. Directed 브로드캐스트 <Broadcast IP of each Subnet>

- Send Packet to every host on local IP network. 

- Send Packet to every host on foreign IP network. 

ex) ping 10.1.1.255

- 1 1 -> 255.255 해당 네트워크에 있는 모든 호스트에게 전달 된다.

 

2. Local 브로드캐스트

- Send Packet to every host on local IP network. 

ex) ping 255.255.255.255

- 255.255.255.255 전송한 호스트가 속한 네트워크로 데이터가 전송된다.

하나의 네트워크로 연결되어 있는 집단내에서의 데이터 전달 목적 (ex 국내 방송)

데이터 전송 대상이 호스트가 아닌 네트워크다.

 

서브넷이란? (Subnet)

서브넷은 IP 주소에서 네트워크 영역을 부분적으로 나눈 부분 네트워크를 뜻한다.

이러한 서브넷을 만들 때 사용하는 것이 서브넷 마스크이다. 

서브넷마스크는 IP주소를 네트워크 ID와 호스트 ID를 분리학는 역할을 한다. 

 

예를들어 C클래스크는 앞의 24비트는 NETWORK ID, 뒤의 8비트는 HOST ID이다. 

이 때, 서브넷마스크를 이용하면 원본 네트워크를 여러개의 네트워크로 분리할 수 있다.

이러한 과정을 서브넷팅(Subnetting)이라고 한다.

 

기본 서브넷 마스크

IP 어드레스에서 서브넷마스크를 AND 연산을 하면 Network ID를 구할 수 있다.

서브넷팅 예시

예제에서 할당 가능한 호스트 수는 2^8-2 = 254개이다. 

192.168.32.0은 Network Address로 쓰이고 마지막 주소인 192.168.32.255는 Broadcast로 쓰이기 때문에 호스트에 할 당 할 수 없기 때문이다.

이제 서브넷 마스크의 비트 수를 1 증가하여 192.168.32.0/25로 변경하게 된다면 아래 그림처럼 된다.

서브넷의 구성

위 그림을 보면 네트워크 수가 어떻게 2개로 늘어났는지 이해하기 쉬울 것이다.

 

 

Network ID = First IP Address in each Sub-Network

Broadcast IP = Last IP Address in each Sub-Network

First HOST IP = IP Address after the Network ID

LAST HOST IP = IP Address before the Broadcast IP

Next Network = IP Address after Broadcast IP

IP Address = Number of IP addresses in sub-network

CIDR/Subnet = Converting between CIDR/Subnet Mask

 

 

 

서브넷팅 관련 잘 정리 된 글 : https://code-lab1.tistory.com/34

서브넷팅 관련 잘 정리 된 동영상: https://www.youtube.com/watch?v=BWZ-MHIhqjM

 

[네트워크] 서브넷, 서브넷마스크, 서브넷팅이란? | 서브넷팅 예제

서브넷의 등장 배경 흔히 사용되는 IPv4 주소 체계는 클래스를 나누어 IP를 할당한다. 하지만 이 방식은 매우 비효율적이다. 예를 들어 어떤 기관에 A 클래스를 할당한다고 하면 16,777,214개의 호스

code-lab1.tistory.com

 

 

삽입정렬

시간복잡도 : O(n^2) , 최선의 경우 O(N)의 시간복잡도를 가진다.

선택정렬에 비해 난이도가 조금 높은 편이지만, 일반적으로 더 효율적으로 동작한다.

선택정렬과 버블정렬보다 조금 더 빠르고, 효율적이다.

처리하지 않은 데이터를 하나씩 골라 적절한 위치에 삽입한다. 

#include <bits/stdc++.h>

using namespace std;

int n = 10;
int target[10] = {7, 5, 9, 0, 3, 1, 6, 2, 4, 8};

int main(void)
{
    for (int i=1; i<n; i++)
    {
        for (int j=i; j>0; j--)
        {
            if (target[j] > target[j-1])
            {
            	swap(target[j], target[j-1]);
            }
            else
            {
            	break;
            }
        }
    }
    for (int i=0; i<n; i++)
    {
    	cout << target[i] << ' ';
    }
    return 0;
}

 

선택정렬

N번만큼 가장 작은 수를 찾아서 맨 앞으로 보낸다.

시간복잡도 : O(n^2) = (N^2 + N - 2 / 2)

N + (N -1) + (N -2) + ... + 2 

#include <bits/stdc++.h>

using namespace std;

int n = 10;
int target[10] = {7, 5, 9, 0, 3, 1, 6, 2, 4, 8};

int main(void)
{
    for (int i=0; i<n; i++)
    {
    	int min_index = i;
        for (int j=i; j<n; j++)
        {
            if (target[min_index] > target[j])
            {
            	min_index = j;
            }
        }
        swap(target[i],target[min_index]);
    }
    for (int i=0; i<n; i++)
    {
    	cout << target[i] << ' ';
    }
    return 0;
}

 

버블정렬

시간복잡도 : O(N^2) 

선택정렬과 시간복잡도는 같지만 가장 느린 정렬알고리즘이다. 

이유는 계속 왼쪽 숫자와 비교하며 교체하는 작업이 있기 때문이다.

선택정렬은 가장 작은 숫자를 골라서 마지막에 한번만 교체해준다.

#include <stdio.h>

int main(void)
{
    int i, j, temp;
    int target[10] = {7, 5, 9, 0, 3, 1, 6, 2, 4, 8};
    for(i=0; i<10;i++)
    {
    	for(j=0; j<9-i; j++)
        {
            if(target[j] > target[j+1])
            {
                temp = target[j];
                target[j] = target[j+1];
                target[j+1] = temp;
            }
        }
    }
    for(i=0; i<10; i++)
    {
    	printf("%d ", target[i]);
    }
    return 0;
}

퀵정렬

시간복잡도 : 평균 -  O(NlogN) , 최악의 경우 O(N^2) --> 이미 정렬이 수행이 되어 있는 경우. (1 2 3 4 5 6 7 8 9 10)

결과적으로 이미 정렬이 되어 있는 경우에는 삽입정렬 알고리즘이 매우 빠르게 풀어 낼 수 있다.

기준 데이터를 설정하고 기준보다 큰 데이터와 작은 데이터의 위치를 바꾸는 방법

가장 많이 사용되는 정렬 알고리즘이고, 프로그래밍 언어의 정렬 라이브러리의 근간이 되는 정렬 방법

이진탐색과 비슷한 방법이다.

#include <bits/stdc++.h>

using namespace std;

int n = 10;
int target[10] = {7, 5, 9, 0, 3, 1, 6, 2, 4, 8};

void quickSort(int *target, int start, int end)
{
    if (start >= end) return;
    int pivot = start;
    int left = start + 1;
    int right = end;
    while (left <= right)	// 엇갈릴 때 까지 반복
    {
    	// 키 값 보다 큰 값을 만날때까지
        while (left <= end && target[left] <= target[pivot]) left++;
        // 키 값보다 작은 값을 만날때까지
    	while (right > start && target[right] >= target[pivot]) right--;
        // 엇갈린 상태라면 pivot 값과 교체
        if (left < right) swap(target[pivot], target[right]);
        // 엇갈리지 않았다면 큰 값과 작은 값을 교체
    	else swap(target[left], target[right]);
    }
    // 데이터가 엇갈려서 while문을 빠져나온다면 pivot 값을 기준으로 왼쪽과 오른쪽에 대해서 퀵정렬을 수행한다.
    quickSort(target, start, right - 1);
    quickSort(target, right + 1, end);
}

int main(void)
{
    quickSort(target,0,n-1);
    for (int i=0; i<n; i++)
    {
    	cout << target[i] << ' ';
    }
    return 0;
}

pivot은 기준 값이다. pivot은 첫 번째 원소이다.

퀵정렬은 재귀적으로 수행이 된다.

퀵정렬의 경우 위의코드는 오름차순 코드인데, 내림차순으로 바꾸려면 

첫 while문 뒤의 2개의 while문에 있는 조건식의 부등호 방향만 바꿔주면 내림차순 코드가 된다.

 

 

결론 - 일반적으로는

버블정렬 < 선택정렬 < 삽입정렬 < 퀵정렬 순으로 선호된다.

하지만 결과적으로는 데이터의 특성에 따라서 적절한 정렬 알고리즘을 사용하는 것이 중요하다.

예를들어서 이미 정렬 된 데이터의 경우 퀵정렬보다 삽입정렬이 더 빠르게 풀어낼 수 있기 때문이다.

 

 

+ Recent posts