C언어의 메모리 구조


프로그램을 실행시키면 운영체제는 우리가 실행시킨 프로그램을 위해 메모리 공간을 할당해준다. 

할당되는 메모리 공간은 크게 스택(Stack), 힙(Heap), 데이터(Data)영역으로 나뉘어진다. 

이러한 메모리 공간이 어떠한 용도로 언제, 어디서 할당되는지 알아보도록 하자.


할당 시기 : 프로그램이 실행될 때마다

할당 장소 : 메인 메모리(RAM)

할당 용도 : 프로그램 실행 시 필요한 메모리 공간(지역변수, 전역변수 선언을 위해) 할당




데이터(Data) 영역


 - 전역 변수와 static 변수가 할당되는 영역

 - 프로그램의 시작과 동시에 할당되고, 프로그램이 종료되어야 메모리에서 소멸됨

 

#include <stdio.h>

int a = 10;	// 데이터 영역에 할당
int b = 20;	// 데이터 영역에 할당

int main() {

	...

	return 0;
}

위와 같은 코드에서 int형 변수 ab는 프로그램 실행시, main 함수가 호출되기 전에 데이터 영역에 할당된다.

그렇기 때문에 프로그램이 종료될 때까지 메모리상에 존재한다.

(전역변수가 프로그램이 종료될 때 까지 존재하는 이유)



스택(Stack) 영역


 - 함수 호출 시 생성되는 지역 변수와 매개 변수가 저장되는 영역

 - 함수 호출이 완료되면 사라짐

 

#include <stdio.h>

void fct1(int);
void fct2(int);

int a = 10;	// 데이터 영역에 할당
int b = 20;	// 데이터 영역에 할당

int main() {

	int i = 100;	// 지역변수 i가 스택 영역에 할당

	fct1(i);
	fct2(i);

	return 0;
}

void fct1(int c) {
	int d = 30;	// 매개변수 c와 지역변수 d가 스택영역에 할당
}

void fct2(int e) {
	int f = 40;	// 매개변수 e와 지역변수 f가 스택영역에 할당
}

main함수와 fct1fct2라는 함수를 추가하였다. 

ab를 데이터 영역에 할당한 뒤에 main함수를 호출하면서 int형 변수 i는 지역변수로서 스택영역에 할당된다.

그 뒤에 fct1()이라는 함수를 호출하면서 fct1함수의 매개변수인 c와 d가 스택영역에 할당된다.

fct1()이라는 함수호출이 끝나면 c와 d는 스택영역에서 삭제되며, 

그 뒤 fct2()라는 함수를 호출하면서 매개변수 e와 지역변수 f가 스택영역에 할당된다.

스택영역은 그 이름그대로 스택의 성질을 띄고있다.


 

힙(Heap) 영역


 - 필요에 의해 동적으로 메모리를 할당 할 때 사용


지금까지 데이터영역과 스택영역을 알아보았는데, 저 두가지 영역만 있으면 코드를 문제없이 짤 수 있을것 처럼 보인다.

그럼 힙영역은 왜 필요한 것일까?


힙 영역은 왜 필요할까?

제일 첫번째 그림을 보면 힙 영역은 프로그래머가 할당한다고 되어있다. 

그럼 언제 할당을 할까? 

배열을 예를들어서 설명을 하겠다.


우리는 배열을 선언할때 상수로 선언을 한다.

int main() {

	// 정상적인 배열선언
	int arr[10];

	// 비 정상적인 배열선언
	int i = 0;
	scanf("%d", &i);
	int arr[i];

	return 0;
}

배열의 길이를 사용자가 입력한 숫자로 잡아주는 것은 비 정상적인 배열선언이다. 왜 비 정상적일까?

메모리 구조에 대해서 잘 파악하고 있다면 당연한 이야기다.


제일 첫번째 그림을 다시보자, 스택 영역에 할당될 메모리의 크기는 컴파일 타임(컴파일 하는 동안)에 결정된다고 되어있다.

정상적인 배열 선언의 경우 arr이라는 배열의 크기가 40바이트 라는것을 알 수 있다.

하지만 비 정상적인 배열선언의 경우 i의 크기가 4바이트 라는 것을 알 수 는 있으나, arr이라는 배열의 크기는 알 수 없다.


그렇다면 다음과 같이 배열을 선언할 때는 문제가 없을까?

int main() {
	
	int i = 10;
	int arr[i];

	return 0;
}

i 라는 변수가 10이기 때문에 arr이라는 배열의 크기가 10이라는 것을 알 수 있지 않을까?

결과는 아니다.


컴파일을 하는 동안 i가 4바이트의 크기라는 것을 알 수는 있으나, 그 값이 10으로 초기화 되었다는 사실은 무시하고 넘어간다. 값이 10으로 초기화 되었다는 사실은 실행되는 동안, 즉 런타임에 결정된다.

그렇기 때문에 컴파일러는 arr의 크기가 40바이트가 된다는 사실을 알 수 없다. 


사용자의 요구에 맞게 메모리를 할당해 주기 위해서는(런타임에 메모리 크기를 결정하고 싶을 때) 메모리 동적 할당을 통해 힙 영역에 메모리를 할당해야 한다.


힙 영역 : 할당해야 할 메모리의 크기를 프로그램이 실행되는 동안 결정해야 하는 경우(런 타임때) 유용하게 사용되는 공간


힙 영역을 사용하기 위해서는 동적할당에 대해서 공부하여야 한다.

switch문이란, 조건문의 일종인데, 여러 개의 if~else 문을 대신하여 간결하게 작성할 때 사용하는 것입니다. if~else 문이 중첩되어 있으면 가독성이 떨어지기 때문에 스위치문이 필요합니다.

그러나 switch문 다음의 괄호()에는 "i <= 0" 이런 식의 판단문이 들어갈 수는 없고, 정수형이나 문자형(char)의 숫자만 들어갈 수 있는 제약이 있습니다. double 등의 실수는 안되고 error C2450: switch expression of type 'double' is illegal 이런 에러가 납니다.

switch는 "함수"가 아니고 "키워드"입니다.

  switch (정수) {
    case 상수 : 실행문; break;
    case 상수 : 실행문; break;
    case 상수 : 실행문; break;
    case 상수 : 실행문; break;

    default : 실행문; break;
  }



스위치문에서 주의해야 할 점은 각 case문 끝에 break; 를 꼭 붙여야 한다는 것입니다. break; 가 없으면, 그 아래쪽의 case문들까지 모두 실행되어 버립니다. break;를 만날 때까지 멈추지 않고 계속 실행됩니다.

의도적으로 break;를 생략한 경우가 아니라, 실수로 누락했을 때는 소스가 폭주하여 위험한 에러가 발생할 수 있습니다. 따라서 우선 무조건 break;를 붙여 놓고 소스의 흐름을 검토하는 것이 안전합니다.

default 라는 것은, 위의 case문들 중에서 어느 것도 해당되지 않을 때 실행할 코드입니다. 필요하지 않다면 default문이 없어도 됩니다.


switch문 사용 방법 예제 소스


소스 파일명: example.cpp
(※ 스크롤 박스 사용법: 박스 안을 마우스로 클릭한 후, 키보드의 좌우 화살표키를 누르면 양옆으로 움직일 수 있습니다. 박스에서 다시 나오려면, 박스 바깥의 아무곳이나 클릭하면 됩니다.)

#include <stdio.h>
#include <conio.h> // getch()
#include <ctype.h> // tolower()


int main(void) {

  int i = 1;

/*
i 의 값이 1일 경우에는 "자장면"이 출력
i 의 값이 2일 경우에는 break가 없기에
군만두"와 "탕수육"이 한꺼번에 같이 출력

i 의 값이 3일 경우에는 "탕수육"이 출력
i 의 값이 4일 경우에는 "짬뽕"이 출력
만약 i 의 값이 그밖의 숫자일 경우에는 "그런 음식은 없습니다."가 출력
*/

  switch (i) {
    case 1 : printf("자장면\n"); break;
    case 2 : printf("군만두\n"); // 아래의 탕수육도 실행됨
    case 3 : printf("탕수육\n"); break;
    case 4 : printf("짬뽕\n"); break;

    default : printf("그런 음식은 없습니다."); break;
  }



  // 또한 아래와 같이, 문자(char)형으로도 판단할 수 있음
  // 다만 double, float 같은 실수형은 불가능

  char ch = (char) getch(); // 키보드에서 문자 1개 입력 받기
  // 글자를 소문자로 변환
  // (대소문자 구분 없이 입력받기 위해)
  ch = (char) tolower(ch);


  switch (ch) {
    case 'a'  : printf("A를 누르셨군요\n");
                break;
    case 'b'  : printf("B를 누르셨군요\n");
                break;
    case 'c'  : printf("C를 누르셨군요\n");
                break;
    case '9'  : printf("9를 누르셨군요\n");
                break;
    case 0x0D : printf("Enter키를 누르셨군요\n");
                break;
    case 0x1B : printf("Esc키를 누르셨군요\n");
                break;

    default   : printf("그밖의 문자...\n");
                break;
  }



  return 0;
}


C언어 포인터 기본에 대해서 배워보자

 

C언어를 처음 접하신 분들은 포인터에 대해서 어려워 하시는 분들이 있는데 어려워 할 필요 없습니다.

 

C언어 포인터 에 대해서 조금만 이해하신다면 예제보고 테스트 소스를 코딩해보고 그러다 보면 언젠가 이게 뭐가 어렵지? 라는 생각을 하게 될 것입니다.

 

포인터에 대해서 조금 더 깊게 파고 들어가면 포인터연산, 함수포인터, 이중포인터 등등 여러가지가 나오는데 이 부분은 일단 포인터에 대해서 공부를 한다음 진도를 나가 봅시다.

 

C언어 를 테스트 할려면 컴파일러가 필요한데 아래 Dev-C++ 무료 컴파일러 입니다. 사용하시는 컴파일러가 있다면 굳이 다운로드 안하셔도 됩니다.

 

C언어 무료 컴파일러인 Dev-c++ 다운로드 방법 입니다.

http://seonissi.tistory.com/admin/entry/post/?id=25

 

 

Dev-c++ 간략한 사용법

http://seonissi.tistory.com/admin/entry/post/?id=26

 

 

C언어 포인터는 단순히 주소라고 생각하면 됩니다.

 

서울시 구로구 구로동 XXXX아파트 101동 1101호

우리가 사는 집엔 모두 주소가 붙듯이 변수를 선언하면 주소가 붙게 됩니다.


 

 

 

 

char 형태의 p라는 변수를 선언 했습니다.

 

 


선언된 변수를 printf문으로 출력해볼 경우 주소가 나타납니다..

 

 

 

 

 

 

 

이렇게 사용하면 변수의 주소를 공유하게 되 포인터로도 변수의 값을 사용 및 수정이 가능합니다. 예를 들어서 우리가 사는 주소에 A라는 사람이 들어가면 그 주소안에는 A라는 사람이 있는거고 B라는 사람이 들어가게 되면 그 주소안에는 B라는 사람이 있는것과 동일한 것입니다..

 

 

변수와 포인터의 주소값을 출력해볼 경우 동일하다라는걸 확인이 가능합니다.

 

 

  

 

포인터 p에 변수를 할당 하지 않을 경우 경우 각각 주소가 다릅니다.

 

위의 결과처럼 주소값이 1만 증가할수 있지만 경우에 따라서 주소값이 다른곳을 가르킬수 있습니다. 포인터가 가르키는 주소값은 메모리 어느 부분을 가르키고 있는데 주소를 할당하지 않은채 사용하다가는 언젠가는 프로

그램이 죽는 현상이 발생하니 주의해야 합니다.

 

 

C언어 포인터 예제 1

 

int main(int argc, char *argv[])

{
    char ch;
    char *p;

 

ch = 'a';
 
printf("ch = %c\n", ch);


    p = &ch;
 
    printf("*p = %c\n", *p);
    printf("ch = %c\n", ch);

}

 

위 예제를 보게 되면 char 형태의 ch를 선언하고 포인터 p를 선언했습니다.

char 형태의 변수값에 'a'라는 값을 넣고 포인터 p에 변수 ch 주소를 할당 했습니다.

그리고 포인터p 가 어떻게 변했느가를 살펴보는 예제 입니다.

 

 

 

 

 결과값을 보면 ch와 포인터p와 값이 동일하다는게 확인이 됩니다.

 

 

 


C언어 포인터 예제 2

int main(int argc, char *argv[])
{
 char ch1;
 char ch2;
 char *p;

 

 ch1 = 'a';
 ch2 = 'b';
 
 printf("ch1 = %c\n", ch1);
 printf("ch2 = %c\n", ch2);
 
 p = &ch1;
 printf("*p1 = %c\n", *p);
 
 p = &ch2;
 printf("*p2 = %c\n", *p);
}

 

 

 

결과값을 보면 할당된 포인터 값에 따라 포인터p의 값이 변환되는 것을 알수 있습니다.

이처럼 포인터는 주소값을 가지고 움직인다는것을 확인했습니다.

 

 

 

C언어 포인터 예제 3

void test1 (char *p)
{
 printf("test1 *p = %c\n", *p);
 *p = '1';
}

 

void test2 (char *p)

{

 printf("test2 *p = %c\n", *p);
 *p = 'a';
}

 

int main(int argc, char *argv[])
{
 char ch1 = 'z';

char *p;

 

 p = &ch1;

 

printf("*p = %c\n", *p);

 test1(p);
 printf("ch1 = %c\n", ch1);

 test2(p);
 printf("ch1 = %c\n", ch1);
}

 

위 예제를 보면 함수에 포인터를 대입해서 함수를 호출 했을때 인자값으로 전송 받았던 포인터 값에 대해 값이 변함이 없는지를 확인할 수 있는 예제 입니다.


거기에 인자값으로 받은 포인터에 다른 값을 대입했을 시 변수로 선언한 ch값이 변화가 있는지 없는지도 확인이 가능합니다.


함수안에서 값을 변경해도 main에서 선언된 ch1이라는 변수에도 영향을 미칩니다.


위의 예제와 같이 함수를 호출할때 함수에 포인터 변수나 주소를 전달하는 것을 call by reference라고 합니다..


ch값을 받고 할당 받은 포인터를 함수로 전달받고 그 값을 printf값으로 출력 하는 예제입니다.

 

 

 


결과값에서 봤듯이 인자값으로 받은 포인터가 ch값과 동일하다는것을 확인할 수 있습니다.


함수안에서 포인터 값을 변경해도 변수로 선언된 ch값 까지 변환되는 부분까지 확인이 가능합니다.


함수의 인자값으로 포인터를 사용해서 그 값을 공유할수 있다는 것입니다.
위와 같이 많이 사용하게 될텐데 포인터를 잘 사용해야 프로그램을 개발할때 모듈화를 하기가 쉽습니다.


이 부분은 더 공부를 해야 될 것입니다.

 


C언어 포인터 예제 4

int main(int argc, char *argv[])

{
 char ch1[10];
 char ch2[20];
 char *p;

 

 ch1[0] = '1';
 ch1[1] = '2';

 ch2[0] = 'a';
 ch2[1] = 'b';
 
 p = ch1;
 printf("ch1 p[0] = %c\n", p[0]);
 printf("ch1 p[1] = %c\n", p[1]);

 

 p = ch2;
 printf("ch2 p[0] = %c"\n, p[0]);
 printf("ch2 p[1] = %c\n", p[1]);
}

 

위 예제는 포인터와 배열에 대한 부분인데 ch1은 10개의 박스를 다 소유하고 있다고 생각하면 됩니다.

 

 

10개의 박스의 안에는 박스 사이즈에 맞게 물건을 넣을수 있는데 사이즈는 "char"형 이라고 보면 되고 물건은 "char"로 선언된 변수라고 보시면 됩니다.

 

포인터로 선언된 p로 ch1을 가르키게 되면 ch1의 데이타를 쓰기 및 읽어올수가 있습니다.


배열을 선언하고 그 배열을 포인터로 할당한 다음 간단하게 포인터로 제어를 하는 식으로 많이 사용합니다.


위의 예제를 보면 포인터 p에 ch1을 할당해서 ch1에 설정된 a, b값을 포인터 p로도 확인을 할수가 있습니다.


다시 포인터 p에 ch2를 할당하면 ch2와 동일하게 사용이 가능합니다.

 

 



결과값을 보시면 ch1과 ch2의 값을 포인터 p로 할당한 다음 printf문으로 출력했을 경우 동일하게 출력 된다는 것을 확인할 수 있습니다.

 

 

C언어 포인터 예제5

 

int main(int argc, char *argv[])

{
 char ch1 = '1';
 char *p1;
 char *p2;

 p1 = &ch1;
 p2 = &ch1;
 
 printf("*p1 = %c\n", *p1);
 printf("*p2 = %c\n", *p2);
 
*p1 = 'a';
 
 printf("*p2 = %c\n", *p2);
}

 

위의 예제를 보면 ch1의 값을 포인터p1과 포인터p2를 동시에 할당을 했습니다. 이럴경우 p1과 p2가 동일하다고 생각하면 되는데 같은 ch1의 변수를 할당받았고 p1을 수정했을 경우 p2의 값도 변한다는 것을 확인할 수 있습니다.


이렇게 포인터를 여러개 선언해서 같이 수정도 가능하다. ch1이 아니라 "p1 = p2"이렇게 선언해도 상관없습니다.
p1도 포인터고 p2도 포인터기 때문에 언제든 주소를 다시 할당할수 있습니다.

 

 

 

 

 

결과값을 보면 p1과 p2는 동일하게 변수 ch1의 값을 동일하게 printf문으로 출력을 하고 있음이 확인 가능합니다.

 

위의 예제처럼 포인터의 경우 다양한 사용이 가능합니다. 구조체를 선언해서 포인터로 할당해서 사용이 가능하고 여러가지 사용이 가능합니다. 위에는 간단하게 C언어 포인터 기본에 대해서만 예제를 설명했습니다.

 

C언어에서 포인터를 사용하지 않아도 프로그램 코딩은 가능하나 포인터를 사용하지 않고 프로그램 코딩을 하는 개발자는 없을 것입니다.

 

실제로 프로그램을 개발하게 되면 이렇게 간단하게 포인터를 사용하지 않고 포인터 연산도 들어가고 포인터 구조체도 쓰고 배열도 들어가고 복잡하게 진행이 됩니다.

 

포인터를 잘못사용할 시 메모리가 뒤죽박죽이 되버릴 수 있습니다. 그리고 포인터를 잘못 정의해도 컴파일러가 체크를 못하는 경우가 종종 발생하기 때문에 개발 완료 후 문제가 발생할 가능성이 있습니다. 그래서 좀더 세세한 코딩이 필요합니다.

도요타 급발진 문제처럼 버그가 발생할 수 있기 때문에 주의해서 개발을 해야 합니다.

MySQL에서 사용자의 로그인 보안 수준을 높이기 위해서,
MySQL 4.0.x 이하 버전과 MySQL 4.1.x 이상 버전의 PASSWORD() 함수의 구현 알고리즘이 달라졌다.
사실 아주 오래전 이야기이지만, 아직도 MySQL 4.0.x를 사용하는 사이트가 많고,
최근 들어서 MySQL 5.1이나 5.5 버전으로 업그레이드를 준비하면서 이런 내용이
업그레이드에 걸림돌이 되는 경우가 많은 것으로 보인다.



MySQL 4.0.x 이하 버전
  - PASSWORD()
  - OLD_PASSWORD() 함수는 없음


  mysql> SELECT PASSWORD('mypass');
  +--------------------+
  | PASSWORD('mypass') |
  +--------------------+
  | 6f8c114b58f2ce9e   |
  +--------------------+


MySQL 4.1.x 이상 버전
  - PASSWORD()         ==> 버전업된 암호화 함수
  - OLD_PASSWORD()     ==> 기존 암호화 (MySQL 4.0.x의 PASSWORD()와 동일)


  mysql>select PASSWORD('mypass');
  +-------------------------------------------+
  | password('mypass')                        |
  +-------------------------------------------+
  | *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4 |
  +-------------------------------------------+
  
  mysql>select OLD_PASSWORD('mypass');
  +------------------------+
  | old_password('mypass') |
  +------------------------+
  | 6f8c114b58f2ce9e       |
  +------------------------+


위 결과를 보면, 새로운 암호화 알고리즘에 의해서 암호화된 내용은 암호 제일 앞에 "*" 마크가 붙게 되므로, 새로운 암호인지 예전 암호인지 쉽게 구분할 수 있다.


그런데, old_passwords=1로 설정하게 되면, MySQL 4.1.x 이상 버전에서도 아래와 같이 MySQL 4.0.x와 같은 결과를 보여주게 된다.
MySQL 4.1.x 이상 버전에서도, 이전 버전과 동일하게 짧은 암호화 문장으로 변환됨
  root@localhost:(none)>select PASSWORD('mypass');
  +--------------------+
  | PASSWORD('mypass') |
  +--------------------+
  | 6f8c114b58f2ce9e   |
  +--------------------+
  
  root@localhost:(none)>select OLD_PASSWORD('mypass');
  +------------------------+
  | OLD_PASSWORD('mypass') |
  +------------------------+
  | 6f8c114b58f2ce9e       |
  +------------------------+


MySQL 4.1.x 이상 버전에서 old_passwords=0 (기본 설정값)인 경우에는, mysql.user 테이블의 비밀번호가 
예전 버전에서 생성된 짧은 비밀번호라면 로그인할 수 없게 된다.


하지만, MySQL 4.1.x 이상 버전에서도 mysql.user 테이블에 사용자의 비밀번호가 예전 버전인 경우 로그인할 수 있도록 
해주기 위해서 old_passwords 라는 옵션을 1로 설정할 수 있도록 해둔 것이다.


근본적인 원인은 MySQL이 업그레이드되면서 기존 비밀번호의 암호화 수준을 보완하여 더 보안 수준을 높이면서 
이런 문제가 야기되었다는 것이며, 가능하다면 업그레이드된 긴 암호를 사용하는 것이 좋아 보인다.


더 중요한 것은
MySQL의 PASSWORD() 함수는 MySQL의 사용자 자체의 계정 및 비밀번호를 관리하기 위한 함수이지
일반 서비스용 계정및 암호를 관리하는 용도로는 적합하지 않다는 것이다.


예를 들어서 MySQL 4.0.x 버전의 회원정보가 예전 방식의 PASSWORD() 함수로 암호화되어서 저장되어져 있다면,
MySQL 4.1.x 이상의 PASSWORD() 함수로는 로그인이 되지 않게 될 것이다. (이 경우에는 OLD_PASSWORD()를 사용해야만 로그인을 할수 있게 된다.)
하지만, 이 경우 예전 버전의 PASSWORD()함수의 암호화 내용을 새로운 버전의 PASSWORD() 함수로 대체할 수 없다.
(한번 암호화된 문장은 다시 풀어낼 수 없는 형태 - 비대칭형 암호화 - 이기 때문)
서비스용 계정이 MySQL의 사용자 계정 암호화 방식에 의존하게 되면 이런 문제가 야기될 수 있으므로 
필요시에는 MD5와 같은 알고리즘을 사용할 것을 추천한다.


또한, 이렇게 두개 버전의 암호화 방식이 존재하는 상태에서
서비스용 MySQL의 버전 업그레이드와 연관되어서 명확히 해결하지 않고 업그레이드를 진행하게 되면,
일부 사용자의 암호는 예전 버전이고, 또 일부 사용자는 새로운 암호화 버전을 사용하도록 되어버리면
걷잡을 수 없는 혼란에 빠져들고, 이를 처리하기 위해서 또 한번 쿼리와 IF ~ ELSE가 필요해질 수도 있다는 것이다.

'프로그램 > MySql' 카테고리의 다른 글

[MySQL]사용자 계정 생성 및 삭제  (0) 2016.11.29
MYSQL 사용자 생성  (0) 2016.11.29
MySQL 계열의 FLUSH PRIVILEGES 명령어  (0) 2016.11.28
MySQL 내장 함수 (MySQL전용 함수)  (0) 2016.11.28
MySQL 기본 명령어 정리  (0) 2016.11.28
MySQL이나 MariaDB를 사용하다보면 FLUSH PRIVILEGES라는 명령어를 자주 사용하게 된다. 대체 무슨 의미일까. 보통은 INSERT, DELETE, UPDATE를 통해 사용자를 추가, 삭제, 권한 변경 등을 수행하였을 때 이 변경 사항을 반영하기 위하여 사용한다. 이 떄 FLUSH PRIVILEGES는 grant 테이블을 reload함으로서 변경 사항을 즉시 반영하도록 한다. UPDATE USER SET PASSWORD=password('새로운패스워드') WHERE USER='사용자명'; FLUSH PRIVILEGES; DELETE FROM USER WHERE USER='사용자명'; FLUSH PRIVILEGES; 그런데 만약 INSERT, DELETE, UPDATE와 같은 SQL문을 사용하지 않고 바로 grant 명령어를 사용하여 작업하였다면 FLUSH PRIVILEGES를 실행할 필요가 없어진다. 또한 MySQL/MariaDB 상이 아닌 OS 커맨드 상에서도 flush를 할 수 있다. $ mysqladmin reload $ mysqladmin flush-privileges 패스워드가 설정된 경우는 인증을 해야 한다. $ mysqladmin -u root -p reload Enter password: 그런데 이 FLUSH PRIVILEGES는 굉장히 성능에 영향을 준다. 특히 습관적으로 FLUSH PRIVILEGES를 사용하는 경우가 있는데(모든 명령 이후에 사용하는 경우도 있다) 이는 엄청난 부하가 된다.

'프로그램 > MySql' 카테고리의 다른 글

MYSQL 사용자 생성  (0) 2016.11.29
PASSWORD()와 OLD_PASSWORD() 함수 그리고 old_passwords 설정  (0) 2016.11.28
MySQL 내장 함수 (MySQL전용 함수)  (0) 2016.11.28
MySQL 기본 명령어 정리  (0) 2016.11.28
join문  (0) 2015.10.14

7.3.3 MySQL 내장 함수 (MySQL전용 함수)


- IFNULL(A, B) : A가 null 이면 B를 A가 null이 아니면 A를 그대로 반환한다.

- ISNULL(A) : A가 null 이면 true(1) , null 이 아니면 false(0) 을 반환한다.


- NOW() : 현재시간 반환

- SYSDATE() : 현재시간 반환

** 일반적인 웹서비스에서 NOW()가 아닌 SYSDATE()를 꼭 사용해야 이유는 없다. 기능은 동일하지만 SYSDATE()는 '호출시점'에 따라 값이 결정되기 떄문에 인덱싱 등에 문제를 가진다.

    where from_data > SYSDATE() 는 실행때마다 SYSDATE값이 달라진다, 이건 상수가 아닌상태이다!!



- DATE_FOMRAT : Date Type -> String

  SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H시 %i분 %s초') AS cur_str;

- STR_TODATE : 문자열을 날자 타입으로 변경

  SELECT STR_TO_DATE( '2011-04-30', '%Y-%m-%d') as cur_dt;


- DATE_ADD, DATE_SUB : 날자 타입의 가감

  SELECT DATE_ADD( NOW(), INTERVAL 1 DAY ) as tomorrow;

  SELECT DATE_ADD( NOW(), INTERVAL -1 DAY ) as yesterday;

** YEAR, MONTH, DAY, HOUR, MINUTE, SECOND 의 값이 있고 [ INTERVAL n 단위 ] 형식으로 입력하면 된다.


- RPAD(),  LPAD() : 문자의 좌우측에 문자를 덧붙여 지정된 길이로 만든다.

  SELECT RPAD("Cloee', 10, '_'); -> Cloee_____

- RTRIM(), LTRIM(), TRIM() : 문자의 우측, 좌측, 양측의 공백(Space, NewLine, Tab)을 제거

- CONCAT : 문자열을 연결, 인자의 갯수는 제한이 없다.

- CONCAT : 문자열을 구분자를 넣어서 연결해준다.

  SELECT CONCAT_WS(',', 'A', 'B', 'C') --> A,B,C


- GROUP_CONCAT :  값들을 정렬한후, 연결하거나 구분자설정, 중복제거등 유용하다.


  ex1-SELECT GROUP_CONCAT(dept_no) 

  ==> d001, d002, d003, d004 

  FROM dept (dept모든 레코드에서 dept_no 칼럼을 기본 구분자, 로 연결한 값을 반환)

  


  ex2- SELECT GROUP_CONCAT(dept_no, SEPARATOR '|') FROM dept

  ==> d001|d002|d003}d004 

  

  ex3- SELECT GROUP_CONCAT(dept_no, ORDER BY dept_name DESC) from dept

  ==> d007,d008,d004,d001

  dept_name 역순 정렬 -> dept_no 들의 연결값을 가져옴


  ex4- SELECT GROUP_CONCAT(DISTINCT dept_no ORDER BY dept_name DESC) from dept

  ==> d007,d008,d006,d004

  ex3과 동일하지만 중복된 dept_no가 있다면 제거하고 가져온다.

  

** 제한적인 메모리 버퍼를 사용하는데 TOAD나 SQLYog에서는 단순한 Warnning지만, JDBC로 연결할 때는 SQLException이 발생하므로, GROUP_CONCAT의 결과가 버퍼를 초과하지 않도록 주의해야한다.


  

- CASE WHEN (Function가 아닌 Syntax)

SELECT emp_no, frst_name 

CASE gender WHEN 'M TEHN 'Man' 

 WHEN 'F' THEN 'Woman' 

ELSE 'Unknown' 

END AS gender

FROM emp LIMIT 10

 ** CASE WHEN 절이 일치해야만 THEN 이하도 실행이 된다.   서브쿼리->CASE WHEN으로 성능 향상을 꾀할 수 있다.(P407)



- MD5, SHA : 비대칭형 암호화 알고리즘 (SHA - SHA-1알고리즘, 160bit 해시 값, MD5 - Message Digest알고리즘 128bit 해시 값)

 중복의 가능성이 매우 낮기 때문에, 길이가 긴 데이터를 줄여서 인덱싱하는 용도로도 사용한다.(url값 인덱싱)



- COUNT() : 칼럼이나 표현식을 인자로 받고, *을 사용하지만 '모든 칼럼이 아니라, RECORD 자체를 의미'한다.
  - MyISAM : 메타테이블의 전체 레코드수가 있어서 where가 없는 count(*)는 결과를 바로 반환가능
  - 그외 스토리지 : 직접 읽어야만 하므로, 큰 테이블에서 count(*)는 주의해야한다.

- 표준 주석
  -   --공백하나 : 한줄의 주석
  -   /* 내용 */ : 여러준 주석
  -   # 라인 이후 주석 : 비표준 

  - 변형 주석
   CREATE /*! 50154 TEMPORARY */ TABLE tb_test (fd INT, PRIMARY KEY(fd));
   -> 5.1.54이상 CREATE TEMPORARY TABLE tb_test (fd INT, PRIMARY KEY(fd));
   -> 5.1.54미만 CREATE TABLE tb_test (fd INT, PRIMARY KEY(fd));
    MySQL의 버전에 따라 주석이 될수도, 쿼리문장이 될 수도 있다. !뒤에가 기준 버전이 된다.

    MySQL 5.0에서 쿼리나 프로시저에 포함된 주석은 모두 삭제되는데 이를 트릭으로 막을 수 있다.

    BEGIN
        /*! 99999 주석 내용 */
        RETURN '테스트'
    END 


'프로그램 > MySql' 카테고리의 다른 글

MYSQL 사용자 생성  (0) 2016.11.29
PASSWORD()와 OLD_PASSWORD() 함수 그리고 old_passwords 설정  (0) 2016.11.28
MySQL 계열의 FLUSH PRIVILEGES 명령어  (0) 2016.11.28
MySQL 기본 명령어 정리  (0) 2016.11.28
join문  (0) 2015.10.14

SQL

SQL (Structured Query Language) 은 구조적인 질의 언어라는 것이다.

이 SQL 이라는 질의 언어를 통해서 데이터베이스를 제어, 관리한다.

 

SQL 은 다음 언어로 나눌 수 있다.

 

⒜ DDL : 데이터 정의 언어 

⒝ DML : 데이터 조작 언어

⒞ DCL : 데이터 제어 언어

 

DDL

DDL (Data Definition Language) 는 데이터 베이스 스키마를 정의 하거나 조작하기 위해 사용한다.

SCHEMA, DOMAIN, TABLE, VIEW, INDEX 를 다음 명령어로 정의, 변경, 삭제한다.


 

⒜ CREATE : 정의 

⒝ ALTER: 수정

⒞ DROP : 삭제

⒟ TRUNCATE : DROP 후 CREATE

 

* Oracle 11g 이전 버전과 MySQL은 DDL에 대해서 트랜잭션을 지원하지 않는다.

(Rollback 할 수 없고 Commit할 필요도 없다.)

 

DML

DML (Data Manipulation Language) 는 데이터를 조작 (조회, 추가, 변경, 삭제) 하기 위해 사용한다.

사용자가 응용 프로그램과 데이터 베이스 사이에 실질적인 데이터 처리를 위해서 주로 사용한다.

 

 SELECT : 조회

⒝ INSERT : 추가

⒞ DELETE : 삭제

⒟ UPDATE : 변경

 

기본적인 위의 명령어 외에 LOCK, EXPLAIN, CALL 등도 DML에 포함 된다.

 

DQL

일부에서는 DML에서 SELECT 만을 따로 분리해서 DQL (Data Query Language) 나 

간단히 QUERY 로 표현하기도 한다.

 

DCL

DCL (Data Control Language) 는 데이터를 제어하는 언어이다.

데이터의 보안, 무결성, 회복, 병행 수행제어 등을 정의하는데 사용한다.

 

⒜ COMMIT : 트랜잭션의 작업 결과를 반영 

⒝ ROLLBACK : 트랜잭션의 작업을 취소 및 원래대로 복구

⒞ GRANT : 사용자에게 권한 부여

⒟ REVOKE : 사용자 권한 취소

 

TCL

일부에서는 DCL 에서 트랜잭션을 제어하는 명령인 COMMIT 과 ROLLBACK 만을 따로 분리해서 TCL (Transaction Control Language) 라고 표현하기도 한다.

 

'프로그램 > 데이터베이스' 카테고리의 다른 글

ER 다이어그램 (Entity-Relationship Diagram)  (0) 2017.09.19
[oracle] 토드팁 - sql자동생성  (0) 2016.12.30
데이터 무결성 (Data Integrity)  (0) 2016.12.02
클라이언트/서버  (0) 2016.11.28
Osi 7 layer  (0) 2016.11.28

MySQL 기본 명령어 정리

MySQL의 기본 명령어와 SQL문 정리. 내가 RDBMS에 완전 문외한이기 때문에 기본 SQL쿼리까지…

Redhat Linux 7.3, MySQL 3.23.58 에서 테스트함.

설치는 Redhat 기본 제공 RPM으로 했다.

데이터베이스 접속

mysql -u 사용자명 -p dbname

설치 직후에는 root 사용자에 비밀번호가 없으므로 다음과 같이 접속하여 MySQL을 관리할 수 있다.

mysql -u root mysql

외부 서버에서 접속이 불가하면 MySQL 설정에서 bind-address 항목을 살펴본다.

비밀번호 변경

MySQL을 설치한 직후에는 root 계정에 암호가 지정되어 있지 않다. 다음 세가지 방법으로 비밀번호를 변경 할 수 있다.

# mysqladmin 이용
mysqladmin -u root password 새비밀번호
# update문 이용
mysql -u root mysql
----
mysql> UPDATE user SET password=password('새비밀번호') WHERE user='root';
mysql> FLUSH PRIVILEGES;
# Set Password 이용
mysql> SET PASSWORD FOR root=password('새비밀번호');

일단 root 비밀번호가 설정된 상태에서는 mysql이나 mysqladmin 명령을 실행할 때 -p 옵션을 붙여주고 기존 비밀번호를 입력해야만 한다.

사용자 추가/삭제

GRANT ALL PRIVILEGES ON dbname.* TO username@localhost IDENTIFIED BY 'password';

username 이라는 사용자를 password라는 비밀번호를 갖도록 하여 추가한다. username은 dbname이라는 데이타베이스에 대해 모든 권한을 가지고 있다. username 사용자는 로칼 호스트에서만 접속할 수 있다. 다른 호스트에서 접속하려면

GRANT ALL PRIVILEGES ON dbname.* TO username@'%' IDENTIFIED BY 'password';

위를 또한 번 실행한다. '%'에서 홑따옴표를 주의한다.

특정 권한만 주려면, 아래와 같은 형태로 권한을 나열한다.

GRANT INSERT,UPDATE,SELECT ON dbname.* TO username@'localhost' IDENTIFIED BY 'pwd';

MySQL error 1045(28000): Access denied for user ...에 따르면 '%'란 localhost 를 제외한 모든 호스트를 뜻한다고 한다. 즉, localhost에 대해서는 명시적으로 따로 권한을 지정해야 한다.

CREATE USER를 통한 사용자 생성이 안될 경우에는 mysql - ERROR 1396 (HY000): Operation CREATE USER failed for 'jack'@'localhost' 참조하여, 먼저 생성하려던 사용자를 drop 하고 재시도 해본다. 이 현상이 나타나는 이유는, CREATE USER/GRANT 명령으로 사용자와 권한을 추가/관리해야 하는데 mysql.db, mysql.user 테이블을 직접 조작하다가 일관성이 깨졌기 때문이다. 가급적 mysql의 계정/권한 테이블에 대한 직접 조작은 하지 말아야 한다.

drop user admin@localhost;
flush privileges;
create user admin@localhost identified by 'admins_password'

불필요한 사용자 삭제는

mysql> DLETE FROM USER WHERE USER='username';
mysql> FLUSH PRIVILEGES;

데이터베이스 생성/보기

# 데이터베이스를 생성하고,
mysql> CREATE DATABASE dbname;
 
# 현재 존재하는 데이터베이스 목록을 보여준다.
mysql> SHOW DATABASES;
 
# 특정 데이타베이스를 사용하겠다고 선언한다.
mysql> USE dbname;
 
# 쓸모 없으면 과감히 삭제한다.
mysql> DROP DATABASE [IF EXISTS] dbname;

IF EXISTS 옵션은 비록 데이타베이스가 없더라도 오류를 발생시키지 말라는 의미이다.

테이블 생성/보기

테이블을 생성하고,

mysql> CREATE TABLE tablename (
  column_name1 INT PRIMARY KEY AUTO_INCREMENT,
  column_name2 VARCHAR(15) NOT NULL,
  column_name3 INT
) ENGINE=INNODB;

현재 데이타베이스의 테이블 목록을 보고

mysql> SHOW TABLES;

테이블 구조를 살펴본다.

mysql> EXPLAIN tablesname;
혹은
mysql> DESCRIBE tablename;

이름을 잘못 지정했으면 이름을 변경할 수도 있다.

mysql> RENAME TABLE tablename1 TO tablename2[, tablename3 TO tablename4];

필요 없으면 삭제한다.

mysql> DROP TABLE [IF EXISTS] tablename;

현재 상태 보기

mysql> STATUS
 
--------------
mysql Ver 11.18 Distrib 3.23.58, FOR pc-linux (i686)
 
Connection id: 26
CURRENT DATABASE: study
CURRENT USER: study@localhost
CURRENT pager: stdout
USING OUTFILE: ''
Server version: 3.23.58
Protocol version: 10
Connection: Localhost via UNIX socket
Client characterset: latin1
Server characterset: euc_kr
UNIX socket: /var/lib/mysql/mysql.sock
Uptime: 2 hours 9 MIN 59 sec
 
Threads: 1 Questions: 160 Slow queries: 0 Opens: 28 FLUSH TABLES: 1
OPEN TABLES: 1 Queries per SECOND avg: 0.021
--------------

INSERT

mysql> INSERT INTO tablename VALUES(1,2, ...);
혹은
mysql> INSERT INTO tablename (col1, col2, ...) VALUES(1,2, ...);

SELECT

mysql> SELECT col1, col2, ... FROM tablename;

컬럼명을 *로 하면 모든 컬럼 의미.

mysql> SELECT col1 AS '성명', col2 AS '국어점수' FROM grade;

컬럼의 이름을 바꿔서 출력.

mysql> SELECT * FROM tablename ORDER BY col1 DESC;
mysql> SELECT col1, korean + math english AS '총점' FROM tablename ORDER BY '총점' ASC;

DESC는 내림차순 ASC는 오름차순.

mysql> SELECT * FROM grade WHERE korean < 90;

결과중 처음부터 10개만 가져오기

mysql> SELECT * FROM grade LIMIT 10;

결과중 100번째부터 10개만 가져오기. 첫번째 레코드는 0번 부터 시작한다.

mysql> SELECT * FROM grade LIMIT 100, 10;

UPDATE

mysql> UPDATE tablename SET col1=새값 WEHER 조건

DELETE

mysql> DELETE FROM tablename WEHRE 조건

DELETE with JOIN

-- DELETE 바로 뒤에 삭제할 테이블을 적는다.
-- INNER JOIN
DELETE T1, T2
FROM T1
INNER JOIN T2 ON T1.key = T2.key
WHERE condition;
 
-- LEFT JOIN
DELETE T1
FROM T1 
LEFT JOIN T2 ON T1.key = T2.key 
WHERE T2.key IS NULL;

mysql에서 쿼리 결과 세로로 보기

-E 옵션을 줘서 실행한다.

mysql -E -u root -p mysql

mysql에서 발생한 오류나 경고 다시 보기

mysql> SHOW errors;
mysql> SHOW warnings;

show processlist

SHOW FULL processlist;
SHOW FULL processlist\G;

MySQL 버전 알아보기

SHOW VARIABLES LIKE "%version%";

CREATE TABLE 구문 보기

SHOW CREATE TABLE [테이블이름]\G

테이블/컬럼 정보보기

-- 전체 테이블 정보를 주석까지 포함해 보여준다.
SHOW TABLE STATUS;

SHOW TABLE STATUS like 'member%'; -- 테이블 이름 매칭 조건

-- 테이블의 컬럼 정보를 주석까지 포함해 보여준다.
SHOW FULL COLUMNS FROM [테이블이름];

테이블/컬럼의 주석(Comment) 지정

-- 테이블의 주석 변경
ALTER TABLE [테이블이름] COMMENT = '테이블설명';

-- 컬럼의 주석 변경
ALTER TABLE [테이블이름] CHANGE COLUMN [컬럼이름] [새컬럼이름] ...여러 속성... COMMENT '새 주석';

테이블과 컬럼의 전체 정보

information_schemaTABLES, COLUMNS를 쿼리하여 테이블, 컬럼 정보를 살펴볼 수 있다.

select t.TABLE_SCHEMA, t.TABLE_NAME, c.COLUMN_NAME, c.COLUMN_TYPE, c.COLUMN_COMMENT from `TABLES` t
	inner join `COLUMNS` c on t.TABLE_NAME = c.TABLE_NAME
order by t.TABLE_SCHEMA, t.TABLE_NAME


1. 클라이언트/서버 이란?

  ㅇ 클라이언트 (Client)
     - 영어 뜻 자체로는 고객을 의미
        . 클라이언트는 기본적으로 한 개 이상의 서버가 제공하는 서비스를 사용할 수
          있는 소비자의 개념
     - 클라이언트/서버 모델에서, 
        . 네트워크를 이용하여 서버(Server)측에 서비스 요청을 의뢰하는 주체

  ㅇ 서버 (Server)
     - 클라이언트들이 요구하는 각종 서비스를 제공하는 측
     - 클라이언트/서버 모델에서,
        . 네트워크상에서 하드웨어 또는 소프트웨어로써 서비스의 요청을 받는 측


2. 클라이언트/서버 출현배경

  ㅇ 과거에는 동일 컴퓨터 내에서 호출 및 피호출 프로그램이 상호작용함으로써 이들을
     분리할 필요가 없었음
 
  ㅇ 그러나,  컴퓨터 및 네트워크 기술발전에 따라 많은 프로그램을 대신하여 서비스를
     제공하거나 자원을 관리하는 전문화된 프로그램의 개념이 널리 확산되어,
     - 이를 서버라 하고 서비스 또는 자원을 의뢰(요청)하는 측을 클라이언트라고 하게됨


3. 클라이언트/서버 모델의 특징

  ㅇ 이 모델에서의 통신은 항상 요청-응답의 형태를 취함
     - 클라이언트에 의해서만 시작되고 서버에 의해서는 결코 시작되지 않음

  ㅇ 서버 종류 
     - 통상 프린트서버, 고속의 그래픽서버, 데이타베이스서버, 화일서버, 네임서버 등과
       같은 것이 있으며 한 가지 작업을 전담함
     - 일반적으로 서버란 많은 다른 클라이언트들의 동시적인 요구를 처리할 수 있도록
       설계프로세스라고 말할 수 있음

  ㅇ 클라이언트/서버 환경
     - 최종 사용자에게는 많은 장점을 제공하는 반면에 망 운영자에게는 복잡하고 어려
       운 문제를 끊임없이 제기하게됨

  ㅇ 구성요소 : Client,  Server,  Network소프트웨어 위치
     - 변화가 적은 소프트웨어는 클라이언트측에 변화가 잦은 소트웨어는 서버측에 놓음

  ㅇ 분산처리
     - 클라이언트/서버 모델은 분산협동처리(distributed cooperative processing)
       의 특별한 예라고 할 수 있음
     - 지능형 동배간 처리에서 한 서버는  여유있는 서버에게 계산 부담을 분배함으로써
       서버와 네트워크 특성을 기반으로 하는 분산을 최적화할 수 있음


4. 클라이언트/서버 TCP/IP 프로토콜

  ㅇ 例) HTTP, FTP, 전자우편(SMTP,POP), TELNET, DNS 등

  ㅇ 서버 포트(Port) 관리
     - 서버는 클라이언트가 접근하는 초기 포트로써 잘알려진 포트를 사용하고,
     - 일단 이 포트를 통해 클라이언트와의 연결이 이루어지면,
     - 일반적으로, 서버는 임시 포트(Ephemeral Port)를 생성하여 연결하고, 
     - 이후에는 데이터 교환이 이렇게 유지되는 연결을 통해 이루어지짐

◎ OSI 7 Layer

– 처음에는 네트워크 관련 제조사마다 각자 다른 독자적인 계층 구조를 사용했으나 타사와의 호환이 문제가 되어 참조모델로써 OSI 7 Layer가 도입되었습니다

– 호환 뿐 아니라 표준화를 통해 효율성 또한 높일 수 있으며 네트워크 상에서 문제가 발견되었을 때 데이터의 흐름을 파악해 문제점을 해결하기가 좀 더 수월합니다

– OSI 7 Layer는 위 그림처럼 나타낼 수 있습니다

– 데이터를 보낼 때는 7계층에서 1계층까지 거치면서 각 계층의 헤더와 여러 정보 (발신자의 주소 등)가 원래 데이터에 붙게 되는데 이것을 Encapsulation이라고 합니다

– 데이터를 수신한 입장에서는 1계층에서 7계층까지 거치면서 패킷의 헤더들이나 정보들을 벗겨내면서 원래 데이터를 만드는데 이것을 De-capsulation이라고 합니다

 

◈ Application ( 7계층 – 응용계층 )

– 사용자의 인터페이스를 담당하며 사용자들이 사용하는 네트워크 응용프로그램이라고 할 수 있습니다

– 서비스를 위한 프로토콜이 포함되어 사용자가 네트워크를 이용할 수 있도록 해주는 역할을 합니다 (서비스 제공)

– Ex > FTP , Telnet , SMTP , DNS , DHCP ….

 

◈ Presentation ( 6계층 – 표현계층 )

– 보내질 데이터의 포맷 즉 형식을 지정하는 계층입니다

– 송신 측과 수신 측의 부호체계가 다를 수 있기 때문에 그러한 것에 대한 변화를 규정하고 데이터 형식을 정합니다

– 데이터 형식이라 하는 것은 확장자나 파일 포맷 뿐 아니라 Charater Set이나 Encoding 등도 포함됩니다

 

◈ Session ( 5계층 – 연결계층 ) //논리적인 연결

– 연결을 담당하여 데이터의 송수신을 가능하게 하는 계층입니다

– 연결 즉 세션을 맺고 끊고 유지하는 역할을 하는데 통신에 있어서 양쪽 즉 수신과 송신 컴퓨터간의 최초연결과 연결유지를 담당합니다

 

◈ Transport ( 4계층 – 전송계층 ) // port

– 서비스를 PORT주소로 구분해서 데이터를 전송하는 역할을 담당합니다

– 만약 보내는 데이터가 클 때는 데이터를 쪼개서 패킷으로 만드는 역할 또한 연결계층이 담당합니다

– 데이터 전송 중 네트워크 오류나 기타 장애로 인해 데이터가 중간에 끊긴 경우 역시 연결계층에서 실패한 패킷만 재전송하는 역할도 합니다

– 4계층의 데이터 전송방식에는 TCPUDP가 있는데 이것에 대해서는 다음에 다시 알아보도록 하겠습니다. 간단하게 TCP는 신뢰성 / UDP는 빠른 속도를 가집니다

– 4계층의 PDU(Protocol Data Unit)은 Segment입니다

 

◈ Network ( 3계층 – 네트워크계층) //ip

– 논리적 주소인 IP를 가지고 통신노드에 대한 다양한 경로를 설정하고 라우팅 및 망,노드간의 트래픽을 제어하는 계층입니다

– 데이터의 안전한 전송을 위해 논리적 경로, 링크를 설정하고 흐름이나 순서를 제어합니다

– 3계층의 PDU는 Packet과 Datagram입니다

 

◈ Data Link ( 2계층 – 데이터링크계층)

– 물리적 주소인 MAC을 사용해서 노드대 노드로 데이터를 전달하는 계층입니다

– PDU는 Frame으로 Encapsulation시에 헤더와 테일을 붙이는데 테일을 붙이는 이유는 데이터의 무결성검사 즉 오류체크를 하기 위해서입니다

– LAN Protocol = Ethernet / WAN Protocol = HDLC , PPP

 

◈ Physical ( 1계층 – 물리계층 )

– 다 만들어진 패킷, 데이터를 실제 전기적신호로 바꾸어 물리적인 선을 타고 수신자에게 보내는 계층입니다

 

 

+ Recent posts