...
프레임워크는 네트워크 등의 기능을 단순화하여
이용을 쉽게 하는 역할.
그래서 에러가 생겼을 때,
로우 레벨에서 어느 단계에서 문제가 생겼는지
판단하기 위해서는
로우 레벨이 어떻게 생겼는지 알아야 하니까!
클라이언트와, 서버가 통신하는 가운데에 있는걸
인터넷이라고 함.
클라이언트와 서버는
별다른 전문 용어가 아니라
고객과 서비스를 전달해주는 서버에 가까움.
...
인터넷은
대개 다수의 클라이언트와
하나의 서버가 서로 소통하는 구조인데,
클라이언트 - ------ -
클라이언트 - 인터넷 - 서버
클라이언트 - ------ -
그 클라이언트와 서버가 소통하는,
인터넷과 서버 사이 연결 영역에
Socket과 UDP/TCP 가 관여한다.
클라이언트 - ------ -
클라이언트 - 인터넷 -(TCP/UDP) - 서버
클라이언트 - ------ -
그런데,
서버가 받은 연결에 따라 서비스를 제공해주기 위해서
항상 모든 연결을 처리한다면
(심지어 연결에서 데이터가 오는 중이 아닌데도!)
당연히 서버가 과부하 오지않겠는가?
그러므로,
딱 지금 처리해야하는 데이터만 처리하기로 하는게
I/O multiplexing 이다.
클라이언트 - ------ -
클라이언트 - 인터넷 -(TCP/UDP) - 서버 - (I/O multiplexing)
클라이언트 - ------ -
얘는 현재 연결에서
지금 처리해야하는 것만 골라서 처리한다.
근데 데이터를 처리하려면?
들어온 데이터가 뭔지 판단해야 하지 않겠는가?
그래서 받은 데이터를
내가 이해할 수 있게 디코딩을 거친다.
이러한 디코딩 과정에 넣기전 전달된 데이터 형태가
messaging, packet 이다!
근데 이 데이터가 저 데이터인지 어떻게 판단하는가?
그거야!
| 이 데이터 - 저 데이터 |
| 요 데이터 - 그 데이터 |
라는 테이블이 있으면, 매핑으로 바로 알수 있지 않겠는가?
이렇게 매핑 역할을 하는 애를 message handler map이라고 한다.
좌측은 어떤 타입으로 왔는지! 에 따라
후자에 적합한 핸들러를! 호출해준다.
[MSG TYPE - HANDLER]
Login - onLogin...
등으로 매핑 해주는 것이다!
뭐 지금은 JSON, Protobuf 등의
정해진 form이 있지만 먼 옛날에는 직접 만들어야했다고......
아무튼.
...
근데, 이렇게 요청된 데이터만 처리한다고 해도 이슈는 있다.
앞 데이터를 처리하는 중에,
뒷 데이터는 무한히 기다려야하지 않겠는가?
(1000개의 클라이언트가
처음에 보낸 100개의 recv를 처리하느라
그 클라이언트들이 rec를 두번째 보낼 때는
100개를 처리할 때까지
아무것도 못 보낸다고..!?!?)
그래서!
일단 받는다. 그래서 작업 큐에 넣는다.
(작업 큐가 대단한게 아니고,
내가 처리해야하는 작업들을 넣어놓는 큐다.)
그래서 노는 애가(worker라고 하는데,
대개 Thread나 Process다.
처리하는 프로그램이 한개라서 Thread로 나뉘냐,
프로그램이 여러개라 Process 냐 정도로 나뉘겠지.)
큐에서 꺼내서 나눠서 처리한다.
휴!
그러니까,
인터넷 서비스는
다수의 클라이언트와 하나의 서버가 소통하는 구조고,
클라이언트가 인터넷에, 인터넷과 서버 사이 UDP/TCP, Socket이 있고
서버 스스로도 처리하기 위해 I/O multiplexing이 있단 말이지?
일단,
모든 개념은 전문 용어로 별개로 뿅 튀어나온 것이 아니다.
그래서 앞으로의 용어를 주의깊게 어원을 생각해보자.
상호 연결된 사람, 사물 등이 이어져있는 그룹이나 시스템.
사람, 사물을 점으로, 그들간의 관계를 선으로 표시한것.
그래서 실제로 네트워크라는 말은
보편적으로도 사용한다.
그렇다면 컴퓨터 세상에서 네트워크는?
점이 컴퓨터 고, 선이 랜선 이겠지.
아!
그럼 컴퓨터가 랜선으로만 이어져있으면
전부 네트워크겠구나?
그래서 Networking 이라는 말도
점 간의 관계를 맺게하는 것이다.
inter- 는 ~사이라는 뜻이다.
network는 아까 했다.
점들을 선으로 연결한 덩어리라는 거였지.
그럼 inter- net(work) 는...
....
점들을 선으로 연결한 덩어리, 들을 연결 한거니까,
덩어리 간 연결 이겠구나!
그래서 사실 인터넷이라는 말은 일반적 개념에 가까워서,
인터넷을 지칭하려면 The internet 이라고 써야한다.
인터넷은 네트워크를 연결한 거라,
네트워크는 인터넷이 되지 않아도
네트워크 자체로 존재하겠지.
그래서 내부망이라는 개념도 존재한다.
점과 선으로 이루어져있기만 하다면
전부 네트워크인 거니까.
IP를 가리키는 거나 다름 없다.
Internet protocol인데,
네트워크를 연결하는 프로토콜, 즉 약속으로,
우리가 앞으로 통신할 때는
이런 방식으로 소통하자! 라고 정해놓은 언어에 가깝다.
태초에 ARPANET이 있었다...
국방 목적으로 소통했지만,
좀 더 범용적으로 개발하기로 했다.
그래서 Internet의 목표에 따라 언어를 수립해야하니
무엇이 목표인지 아는게 중요하겠지.
대략 7가지의 규약이 있는데...
- 구성하는 네트워크 중 일부가 동작하지 않아도 계속 작동할 것.
(일부가 폭격당했는데 전부 통신 불가하면? .... 끔찍하다!)- 다양한 통신 서비스를 지원할 것.
(그야 서비스마다 인터넷을 만들어야하면 드는 자원이! 어우!)- 다양한 네트워크 수용 가능.
(그야 그렇겠지. 같은 네트워크끼리만 이어줄 것인가?)- 중앙 집중 식이 아닌 분산 처리 방식의 자원관리.
(사실 1이 성립하려면 4로 만들어야할테니까.)- 비용 효율적.
- 적은 비용으로도 호스트 추가 가능.
- 누가 어느 정도 리소스를 쓰는지 추적 가능.
...
그럼 인터넷은 이 모든걸 충족한단 말이야?
아니다!
뭐 다 충족하면 좋겠지만,
팔방미인은 고충이 큰 법이다.
일단 1번만 충족하면,
나머지는 충족되면 좋은 정도다.
실제로도 7번은, 예를 들어 IP 추적등이 가능하다고는 하지만,
어떤 특정 공유기를 쓴다면, 그 공유기를 사실 옆집 사람이 쓴건지 어떻게 안단 말인가?
...
아무튼, 지금도 인터넷은 꽤 훌륭하게 목표를 수행하고 있다.
WWW, 파일 전송, 터미널 서비스, DHT(비트 토렌트)...
ㅡㅡㅡㅡㅡㅡ IP ㅡㅡㅡㅡㅡㅡㅡㅡ
Ethernet, Wi-Fi, Token-ring ....
....
WWW를 쓰면 꼭 Ethernet만 써야하는가?
WiFi를 쓰면 터미널 서비스만 가능한가?
아니다. IP만 있으면 된다.
그러니까 사실상 2번, 3번이 성립하고 있는 것.
이것이 인터넷의 목표였다.
Hour glass(모래 시계) 모양의 모델을 취하는 것.
어떤 물리적 연결 기술이든,
어떤 서비스든,
IP로만 구현하면 서로 호환이 되는 것.
아키텍처의 뜻은?
구조다.
구조는 대개 구성 요소와 구성 요소 간의 관계 로 이루어져있다.
그럼 무슨 일을 할 것이느냐에 따라,
구성 요소와 관계를 다르게 설계해야할 것이다.
여기서 인터넷은 계층형을 선택했다.
예를 들어,
하나의 큰 덩어리를 만들고 거기서 전부 구현한다면,
그걸 전부 소화하고 있어야겠지만,
작은 덩어리로 나눠서 그걸 구현한다면
작은 덩어리 별로 볼수 있겠지 않겠는가.
(여기서 layering 개념이 나온다.)
그렇게 해서 얻는 장점은 이렇다.
물론 단점도 있다.
만약 당신이 계층 구조로 코딩을 한다면, 이걸 유의해라.
하위 계층에 범용적인 걸 넣을 생각 마라.
당장 쓰는 것만 넣어라....
그야, 자주 쓰지도 않는데 하위 계층에 넣어봤자
지나쳐야하는 모든 과정 속도만 느려지니까...!!!
OSI 7 계층 모형을 따른다.
정확히는 OSI Reference Model 이라고 하는데,
즉 실제로 구현하는 것이 아니라,
단순히 참조하는 모델이다.
아니, 실제 모델 만드려면
표준 참조 모델이 있긴 해야하니까 당연히 아니다.
TCP/IP 모델 자체도 여기서 비롯되었고.
그래서 TCP/IP 모델 기준 이렇다.
(주로 이 모델을 쓰고.)
Application (7, 6, 5층)
Transport (4층)
Network (3층)
Network Interface (2, 1층)
그럼 이 계층 구조를 어떻게 써먹는 걸까?
요청 - 응답으로 이루어져있으니,
데이터를 보내는 쪽을 먼저 보자.
이제 받는 쪽을 보자.
근데 기억 나는가?
계층은 자기가 할 것만 기억한다.
즉, 다음에 받는 애는 가장 겉포장만 본다.
...
그렇다!
이 친구들은 자기가 하는 일만 안다.
그럼 이제 궁금해진다.
정확히는,
Network Interface 자리에서는 MAC을,
Internet 자리에서는 IP를,
Transport 자리에서는 Port를 확인한다.
port의 뜻은 항구다.
그래서 공항도 airport다.
네트워크 세상의 port는 배편인 거겠지.
IP라는 국가에서 왔는데 어느 port로 진입하느냐?
처럼 이해하면 좀 편할 것이다.
그러니 전문 용어에 너무 매몰되지 말고 추상적으로 봐보자.
실제 아이템 사용 사실을 전달한다고 하는 경우를 볼까?
'아이템 쓴 사실'
'port 정보' + '아이템 쓴 사실' = TCP segment
'IP 정보' + 'TCP segment' = IP datagram(IP packet)
'MAC 정보' + 'IP datagram(IP packet)' = Ethernet frame
....
그래, 단계에 따라 넘어가는 건 알겠어.
근데, 단계에서 처리의 조건문은 뭘까?
그러니까, 그 단계를 어떻게 처리할까?
예를 들어 port 정보를 붙인다고 치자.
어떤 port를 붙여야하는지 어떻게 판단한단 말인가?
port 정보 붙이기
: 사실 당신이 쓰는 수단에 따라 이미 port가 지정되어있을 것이다.
당신이 새로운 창작 수단을 쓴다면, 그냥 port를 지정해주면 된다.
IP 정보 붙이기
: 가야하는 IP가 있겠지? 그 정해진 IP를 붙여주거나, 갈 서버 이름을 붙여준다.
MAC 정보 붙이기....
....
잠깐?
the Internet은 IP로 소통한다.
서버 주소가 숫자 형태로 존재하는 것이다.
그렇지만 우리가 가야하는 서버마다
n개의 무의미한 숫자를 외우는 건 너무 어렵다.
그래서 서버 이름 - IP 를 매핑 시켜서
서버 이름으로 조회하면 IP를 가져와서
그 IP로 접속할 수 있도록 해준다.
그 역할을 해주는 서버가 DNS 서버 다.
정확히는 이름과 IP를 저장하고 있다가,
요청하면 답해주는 역할을 한다.
그리고 그 서버 이름에서 IP를 알아내려고하는게
DNS resoultion 이고!
Domain? 지역, 그 범위를 가리킨다.
그러니까 Domain name이면 그 지역 이름이고,
DNS는 그 지역 이름 을 기억해주는 서버겠지...
실생활에서 DNS server로 조회하면
내가 어디서 가져오는 지 알수 있겠지...
또, 실제 파일 보내주는 서버는 살아있는데
중간 단계인 DNS 서버가 죽으면 서비스가 먹통이 되니
이런 것도 고려할만한 점이다!
그래서 무슨 과정이냐,
www.naver.com 이면
root로 가서 .com 서버가 뭐야? 라고 하고.
받아오면 .com 서버로 가서 naver.com가 뭐야? 라고 하고.
.naver.com로 가면 www.naver.com은 뭐야?
라고 해서
진짜 목적지를 알아내는 것이다...
.... 이럴수가!
그럼 네이버에 갈때마다 서버 세개를 돌아야한다는 건가?
DNS 서버는 무슨 잘못인가?
특히 .com 처럼 Top-level domain은 고달프다.
그래서 DNS caching을 쓴다.
DNS는 대개 자주 바뀌는 정보가 아니기때문에,
내가 한번 간 DNS등의 정보를 공유기 차원에서
caching 처럼 저장해둬서 빨리 로드해주는 것이다.
권한 없는 응답 같이 프롬프트에 뜨는 것이 이거다.
실제 DNS 서버까지 가서 가져온게 아니라
내가 캐싱으로 갖고 있던거 가져온건데 맞나< 싶은 말이다.
아니다.
실제 어떤 서버가 host1 등의 이름을 가져도,
진짜 DNS에 등록해두지 않으면
애초에 테이블에 참조할 수 없으니 찾아갈 수 없다.
ssh -A ubuntu@host1 을 쓴다고해서
이 세계 어딘가에 있는 host1에 도달하지 않는 것이다.
(걔가 DNS에 등록을 하지 않았다면 말이다.)
내부 서버는 전부 IP 주소를 써야하는 걸까?
아니다.
사실 DNS 서버만 있으면 돌아가지 않겠는가.
그러니까, 꼭 top-level이 아니더라도
내가 접근하는 경로 내에 DNS 서버가 있어서
내가 원하는 IP만 찾아올 수 있으면 된다.
내 기기 자체에서 설정할 수도 있고,
내가 접근할 다른 서버에 있으면 되겠지.
(결국 IP - 서버 이름 매핑만 되어있으면 되니까.)
질문 자체가 순간 의아할텐데,
Private IP라는 게 있다.
이 IP 주소는 공통적으로 쓰는 경우가 없도록 지정했기때문에
내 컴퓨터에서 그 IP는 항상 사적으로 쓸수 있고,
애초에 이 IP는 외부가 받아들이지도 않는다.
그래서 쟤도 사적 IP 주소가 172.16... 이고
나도 172.16.... 이지만
각자의 컴퓨터에서만 도는 회로라서 사실 따로 노는 애인 셈이다.
기재할수는 있긴한데
어차피 기재해봤자 원하는 통신이 되는 것도 아닌데
(내가 host1 - 172.16... 을 올려서
친구가 참조한다고 내 통신으로 들어오겠는가?)
아무 의미없다고 할 수 있다.
ssh ubuntu@localhost
-> ssh ubuntu@127.0.0.1
식으로는 실제로 접근될 것이다.
서버 이름을 쓰면,
IP 주소 자체를 변하는 게 편하고,(이름은 그대로일테니)
여러 IP 매핑이 가능하니 서버 이름으로 접속하는 애를 여러 IP에 가도록 할 수 있어서 로드 밸런싱이 되겠지.
대신 DNS 서버가 죽으면 나도 죽고
Resolve에도 소요시간이 클거고.
IP를 쓰면
단 하나의 IP만 쓴다는게 좀 어렵지만,
DNS 서버가 죽는다고 나도 죽을 일은 없을 것이다.
즉, 케바케.
IP는 변할 수 있다.
근데, 애초에 IP를 본다는 건 그쪽 동네에 이미 도달했다는 거겠지.
그럼 같은 IP를 쓰는 애를 그쪽 동네 전체에게 물어본다.
이 IP 누가 써요? 라고, broad cast, 전체 방송을 한다.
그럼 같은 IP 쓰는 애들의 상세 정보가 나오겠지.
그럼? 그 상세 정보가 일치하는 애를 찾아가면 된다!
Gateway에게 맡긴다.
gateway의 뜻은 관문이다.
생각해보자. 인천 공항 은 대한 민국의 gateway라고 볼 수 있다.
그러면 네트워크 세상에는?
네트워크의 입출입을 관리하는 관문 서버겠지.
Network A - Network A GateWay --[inter-network]-- Network B Gateway - Network B
....
그래서 실제로는
Gateway를 거치게 된다면,
이런 식으로 진행된다.
목적지 host 이름 담음.
목적지 포트 담음.
목적지 IP 담음.
GatWay A MAC 담음.
그럼 Gateway A로 가겠지?
Gateway A MAC 확인.
오! 잘 왔군.
그럼 다시 포장한다.
목적지 IP 담음.
GateWay B MAC 담음...
...
그래서, GateWay B가
목적지 MAC을 최종적으로 담아서
목적지인 Network B에 열때는
목적지 MAC을 확인할 수 있겠지!
그럼 의구심이 든다.
Routing과 Forwarding을 거친다.
Route + -ing,
즉 Route, 경로를 찾는 것이고,
Forward + -ing,는
얘가 앞에서 찾은 경로를 향해 Forward 한다는 것이다.
이렇게 목적지를 따라서 골라 보내기때문에 Switching이라고도 하는데,
그러니까...
실제로는 Routing table과 Forwarding table을 참조한다.
....
라는걸 참조할수 있으니까 말이다.
관리 주체가 이동 경로를 선택하는데,
단순히 빠르다고 선택하지 않고,
정치적, 비용적 이유에 따라
정책 기반에 따라 판단한다.
그래서 우리가 서비스를 개발할 때 이 점을 주의해야한다.
Latency/jitter에 영향을 미치거든.
즉 꼭 항상 느린 것도 아니고,
항상 일정한 것도 아닌데,
Latency는 지연이 되는 정도지만,
Jitter는 실행할 때마다 지연이 되는 정도가 차이가 있는데(정책 기반에 따라 경로를 자꾸 설정하니까!)
정확히는
Latency는 딜레이고,
Jitter는 Latency의 지연 정도라고 볼수 있을 것이다.
만약 서비스를 개발한다면,
이 부분을 고려해야할 것이다.
Latency는 반응이 늦다는 기분을,
Jitter는 자꾸 튄다는 느낌을 주는데,
속도가 생명인 게임에서 어떨땐 빠르고 어떨땐 느리면....
...... 큰일 나겠지!
....
비슷하지만 약간 다르다.
Switch 는 전환 이라는 뜻에서,
트래픽의 방향이 바뀌는 걸 의미한다.
당연히 방향을 바꾸려면 판단 근거가 있어야겠지?
그렇다면 판단 근거는?
당연히! 헤더다.
그래서...
출력 포트를 정하는 장비, 서버를 분산해주는 장비 등,
트래픽의 방향을 정해주는 것들은 모두 Switch라 부른다고 보면 된다.
이제 무슨 헤더를 보고 판단하느냐에 따라 다르겠지.
그래서, Switch는
기능을 의미하는 것에 가깝지, 장치를 의미하는 것은 아니다.
실제로 어떤 장비보다, 어떠한 소프트웨어가 기능을 제공할 때가 많다.
통상적으로,
HTTP,
TCP/UDP
IP
Ethernet 이라 할때,
실제로 헤더에는 주소가 주로 들어있지만,
메타데이터(바코드, 취급점 등 주소 외의 정보)가
담겨져있기도 하다.
그렇다!
헤더만 취급하니까.
헤더라고 하지만,
실제로는 데이터 뒤에 붙는다.
CRC라고, Frame check sequence 영역이 있어서 가능하다.
데이터는 최대 길이가 있으며,
그보다 크면 그냥 버려져서 상위계층에서 잘 쪼갰어야한다.
옵션에 따라 jumbo frame 같은 것도 선택 가능하다네.
Total length가 16비트라,
헤더를 포함해 64KB가 가능하다...
....
64KB보다 크면 쪼개서 여러 IP로 보내는 형식을 쓴다.
그래서 만약 6000byte를 보낸다면,
1500byte를 네번 보내고,
몇번째 sequence인지 표기하는 방식을 사용한다.
IP에서는 에러를 검출하진 않지만,
(Header 선에서 검출은 해도...)
(예를 들어,
Time to Live 라는 길이를 확인해서,
만약 뭐가 삐꾸나서 영원히 loop 도는 택배 같은 경우를,
한번 돌때마다 Time to Live의 횟수를 줄여
0이 되면 '만료되었다'라는 판정으로 중간에 버린다.)
(이 방법을 써서 루트 추적도 한다.
총 루트에서 1번 가면 만료 시켜서 받아옴...
2번 가면 만료 시켜서 받아옴...
같은 걸로.)
CRC가 1비트 변형 같은건 잡아주겠지!
라고 믿는다.
그런 기능!
없다.
대신 나눠서 보낼때
하나라도 누락하면 그냥 전체 누락시킨다.
그래서 힘내지만 전송을 보장하지 않는걸
best-effort 라고 한다.
User Datagram Protocol (UDP)
Transmission Control Protocol (TCP)
이다. 전송 제어라니,
당연히 헤더의 차이가 있겠지.
UDP는
포트만 구분하고, checksum만 있어서
IP와 속성의 결이 거의 유사하다.
계층 구조 통과용으로 만든거라 빈약하다.
TCP는
내가 보낸 sequence number도 체크하고,
(이것 덕분에 데이터가 연속적인 것처럼 보여서 Stream이라 한다)
내가 여태 받은 sequence ACK 도 확인한다.
(그래서 잘 받았는지 체크한다.)
또 Window size도 확인한다.
(수신자가 받을 여력이 있는지도 확인한다.)
근데 TCP는 넘버만 매기지
전부 받았는지 체크를 안할수도 있으므로
내가 보낸 바이트를 전부 받았는지,
못 받았다면 loop를 돌도록 만들어야한다...
(이 내용이 맞나?)
그리고,
UDP는
Socket 하나만 만들어서 쓰기때문에
매번 상대를 명시해야하는데,
(대신 상대가 받을 수 있든 말든 개의치않아서
상태를 체크하진 않아 stateless다.)
TCP는
너/나 라는 개념이 있어서
연결별로 socket을 만들되,
(그래서 최대 socket 수가 있기때문에 설계시 유의!)
상대를 명시할 필요가 없다.
대신 상대가 받을 수 있는 상태인지 확인한다.(statfeful)
TCP는
를 확인한다.
그래서 보낼때도 이 여부에 따라 속도가 달라진다.
과부하를 걸렸다고 해서
상대가 <나 과부하 걸렸어요!)라고 보내겠는가?
과부하 걸리느라 보내지도 못할 것이다.
그래서 ACK로 판단한다.
조금씩 보내면서,
제대로 받았다는 신호가 오는지 확인하고,
잘 안 오면 보내는 속도를 줄이는 등이다.
그래서 jitter 측면으로는
오락가락 한다.
(잘 가다가 막히면 속도를 줄일테니까!)
항상 많다? 아니다.
케바케다. 상대가 잘 받는다 싶으면 한번에 보낼 때도 있다.
수신자에게 이만큼 갈거라고 힌트를 줘서 상황을 보거나,
종료 신호 보내기 전까지 받게 하거나 해서 조절한다.
UDP에 적합한 서비스가 있다.
예를 들어 전화 통화.
전화가 잘 안 보내졌다고해서
나한테 다시 보내면
계속 하던말이랑 뒤섞여서
오히려 혼란스러울것이다!
다시 보내는 정보가 전혀 필요없고, 속도가 중요하다.
그래서 HTTP는 기본이 TCP인데
UDP가 필요한 서비스를 하면 피를 보게 되겠지....
UDP와 TCP를 동시에 서비스하면
UDP가 다 잡아먹는다.
UDP가 항상 최선을 다해서 보내기때문에
TCP는 막히는 정도에 따라 스스로 양보하면서
UDP가 양보한걸 다먹고
그래서 TCP는 또 양보하고....
...
그래서 TCP와 UDP 서비스를 동시에 한다면
한쪽 서비스가 손해보므로 (리소스도 많이 먹고!)
많은 논란이 되는 주제다.
JARGON, 전문 용어라 해도 다 전하고자 하는 뜻이 있다. 새로운 용어가 많이 나오는 학문이니, 그때마다 너무 독립되어 받아들이지 말고 기존 컨셉을 알아보자.
TCP는 안전성을 위해 jitter를 희생하지만,
UDP는 jitter가 살아도 안정성이 죽었다.
상황에 따라 TCP와 UDP 적합한게 다르니 신중히 고르자.
또, 꼭 TCP나 UDP 둘 중 하나만 써야하는 건 아니다.
받아야하는 데이터 케이스에 따라 다르게 처리하는 부분도
충분히 있으니 유념하자!
끝!