오늘은 대부분 CS 지식에 대한 내용이 주를 이루었다.
네트워크, 컴퓨터 시간 원리, 암호화, 함수형 프로그래밍, 객체지향/프로토타입, 이벤트 루프, 모듈, 유니코드, 정규표현식, 쿠키와 세션/웹스토리지
등에 대한 내용을 배웠다.
평소 프로젝트를 리액트를 사용하여 했던지라 함수형 프로그래밍
은 어느정도 친숙했고, 알고리즘 문제를 풀 때도 큼지막한 기능들은 함수로 구현하려고 노력했었다. 이어 프로젝트에서 사용했던 웹스토리지
와 알고리즘 문제를 풀며 사용했던 정규표현식
도 조금씩 사용해봤던 경험이 있어 생소하지는 않았다.
오늘도 배웠던 모든 문제에 대해 다루는 것 보다 내가 어려웠던 내용에 대해 다뤄보겠다!
https://channy.creation.net/blog
을 예시로 보자.
https://
는 통신 프로토콜이다. 이 스키마는 브라우저에 전송 계층 보안(TLS)를 사용하여 서버에 연결하도록 지시하며, TLS는 인터넷을 통한 통신을 보호하는 암호화 프로토콜이다. HTTPS를 사용하면 암호나 신용카드 정보와 같이 브라우저와 서버 간에 교환되는 데이터가 암호화 됨.channy.creation.net
은 웹 사이트의 도메인 이름이다. 기억하기 쉬운 주소이며 특정 서버의 IP 주소를 가리킨다.https://channy.creation.net/blog/hello-world
의 경우 blog
는 서버에서 요청된 리소스인 hello-world
로 이어지는 경로이다. 이는 컴퓨터에 있는 디렉터리 구조처럼 생각할 수 있다.hello-world
는 보려는 우베 사이트의 리소스 이름이다. .html
과 같은 파일 확장자로 볼 수 있는데, 이는 HTML 콘텐츠가 있는 서버의 정적 파일임을 나타낸다.브라우저는 인터넷에서 연결할 서버를 파악해야 한다. 입력한 도메인을 사용하여 웹 사이트를 호스팅하는 서버의 IP 주소를 조회해야 한다. DNS 조회를 사용해 이 작업을 수행한다.
DNS 기록을 찾기 위해 브라우저는 다음과 같은 네 개의 캐시를 확인한다.
첫 번째, DNS 쿼리는 우선 브라우저 캐시를 확인한다. 브라우저는 내가 이전에 방문한 웹 사이트의 DNS 기록을 일정 기간 동안 저장하고 있다.
두 번째, 브라우저는 OS 캐시를 확인한다. 브라우저 캐시에 원하는 DNS 레코드가 없다면, 브라우저가 내 컴퓨터 OS에 시스템 호출(ex. 윈도우에서 gethostname 호출)을 통해 DNS 기록을 가져온다. (OS도 DNS 레코드 캐시를 저장하고 있다.)
세 번째, 브라우저는 라우터 캐시를 확인한다. 만약 컴퓨터에도 원하는 DNS 레코드가 없다면, 브라우저는 라우터에서 DNS 기록을 저장한 캐시를 확인한다.
마지막으로, ISP 캐시를 확인한다. 만약 위 모든 단계에서 DNS 기록을 찾지 못한다면, 브라우저는 ISP에서 DNS 기록을 찾는다. ISP(Internet Service Provider)는 DNS 서버를 가지고 있는데, 해당 서버에서 DNS 기록 캐시를 검색할 수 있다.
네트워크 장비 라우터를 이용해 이동한다.
논리 주소인 IP 주소를 물리 주소인 MAC 주소로 변환하는 프로토콜로 실제 통신을 위해 변하지 않는 고유한 MAC 주소가 필요하다.
네트워크 내에 ARP를 브로드캐스팅하면 해당 IP 주소를 가지고 있는 기기가 MAC 주소를 반환한다.
브라우저가 올바른 IP 주소를 수신하면 IP 주소와 일치하는 서버와 연결해 정보를 전송한다. 브라우저는 인터넷 프로토콜을 이용하여 이러한 연결을 구축한다. 사용할 수 있는 여러가지 인터넷 프로토콜이 있지만, 일반적으로 HTTP 요청에서는 TCP라는 전송 제어 프로토콜을 사용함.
클라이언트와 서버 간 데이터 패킷을 전송하려면 TCP 연결을 해야하는데 3 way handshake
라는 연결 과정을 통해 이뤄진다. 클라이언트와 서버가 SYN(연결 요청) 및 ACK(승인) 메시지를 교환하여 연결을 설정하는 3단계 프로세스를 아래에서 살펴보자.
클라이언트는 인터넷을 통해 서버에 SYN 패킷
을 보내 새 연결이 가능한지 여부를 묻는다.
서버에 새 연결을 수락할 수 있는 열린 포트가 있는 경우, SYN/ACK 패킷
을 사용하여 SYN 패킷의 ACK(승인)으로 응답한다.
클라이언트는 서버로부터 SYN/ACK 패킷
을 수신하고 ACK 패킷
을 전송하여 승인한다.
TCP 연결이 설정되면 데이터 전송이 시작되어 브라우저는 웹 페이지를 요청하는 GET 요청
을 보낼 것이다.
만약 자격 증명(credentials)
을 입력하거나 form
을 제출하는 경우 POST 요청
을 사용할 수 있다. 이 요청에는 브라우저 식별(User-Agent 헤더)
, 수락할 요청 유형(Accept 헤더)
및 추가 요청을 위해 TCP 연결을 유지하라는 연결 헤더와 같은 추가 정보
도 포함된다. 또한 브라우저가 이 도메인에 대해 저장한 쿠키에서 가져온 정보도 전달한다.
서버에는 웹 서버가 포함되어 있는데, 이는 브라우저로부터 요청을 수신하고, 해당 내용을 requset handler
에 전달하여 응답을 읽고 생성하는 역할을 한다. request handler
는 요청, 요청의 헤더 및 쿠키를 읽고 필요한 경우 서버의 정보를 업데이트하는 프로그램이다(NET, PHP, Ruby, ASP 등으로 작성됨). 그런 다음 response를 특정 포맷으로(JSON, XML, HTML)으로 작성한다.
서버 응답에는 요청한 웹 페이지와 함께 상태 코드, 압축 유형, 페이지 캐싱 방법, 설정할 쿠키, 개인 정보 등이 포함된다.
상태 코드는 숫자로 표시가 되는데 숫자 코드를 사용하여 HTTP 응답 결과를 다섯 가지 상태로 나타낸다.
브라우저는 응답받은 HTML을 화면에 단계별로 표시한다. HTML을 읽어 DOM Tree를 구축하고, 만들어진 DOM Tree를 이용하여 화면에 그리고 스크립트를 실행한다.
JS에는 기본 데이터 타입을 제외한 모든 것이 객체이다. 객체가 만들어지기 위해서는 자신을 만드는 데 사용된 원형인 프로토타입 객체를 이용하여 객체를 만든다. 이때 만들어진 객체안에 __proto__
속성이 자신을 만들어낸 원형을 의미하는 프로토아입 객체를 참조하는 숨겨진 링크가 있다. 이 숨겨진 링크를 프로토타입이라고 정의함.
function Person() {}
var joon = new Person();
위 그림 joon 객체의 멤버인 __proto__
속성이 프로토타입 객체를 가리키는 숨은 링크가 프로토타입이라고 한다. 프로토타입은 크게 두 가지로 해석이 되는데, 함수의 멤버인 prototype 속성은 프로토타입 객체를 참조하는 속성이다. 그리고 함수와 new 연산자가 만나 생성한 객체의 프로토타입 객체를 지정해주는 역할을 한다. 객체 안의 __proto__
속성은 자신을 만들어낸 원형인 프로토타입 객체를 참조하는 숨겨진 링크로써 프로토타입을 의미한다.
JS에서는 숨겨진 링크가 있어 프로토타입 객체 멤버에 접근할 수 있다. 그래서 이 프로토타입 링크를 사용자가 정의한 객체에 링크가 참조되도록 설정하면 코드의 재사용/객체 지향적 프로그래밍을 할 수 있다.
재사용 하면 떠오르는 것은 상속. JS는 프로토타입 기반 언어로 프로토타입을 이용해 코드 재사용을 할 수 있다.
크게 두 가지 방법이 있는데 classical/prototypal 방식이 있다. classical 방식은 new 연산자를 통해 생성한 객체를 이용해 코드를 재사용하는 방법이며, prototypal 방식은 리터럴 또는 Object.create()를 이용하여 객체를 생성하고 확장해 가는 방식이다. classical 보다 간결하게 구현할 수 있어 JS에서 선호하는 prototypal에 대해서만 다루겠다.
prototypal한 방식의 재사용Object.create()를 사용해 객체를 생성과 동시에 프로토타입 객체를 지정한다. 이 함수의 첫 번째 매개변수는 부모객체로 사용할 객체를 넘겨주고, 두 번째 매개변수는 선택적 매개변수로써 반환되는 자식 객체의 속성에 추가되는 부분이다. 이 함수를 사용함으로써 객체 생성과 동시에 부모 객체를 지정하여 코드의 재활용을 간단하게 구현할 수 있다.
var person = {
type: "인간",
getType: function() {
return this.type;
},
getName: function() {
return this.name;
}
};
var joon = Object.create(person);
joon.name = "혁준";
console.log(joon.getType()); // 인간
console.log(joon.getName()); // 혁준
위 소스에서 부모 객체에 해당하는 person을 객체 리터럴 방식으로 생성했으며 자식 객체 joon은 Object.create() 함수를 시용해 첫 번째 매개변수로 person을 넘겨받아 joon 객체를 생성하였다. 한 줄로 객체를 생성함과 동시에 부모 객체의 속성도 모두 물려받아 classical 방식보다 간단하다. JS에 서는 new 연산자와 함수를 통해 생성한 객체를 사용하는 classical 방식보다 prototypal 방식을 더 선호한다.
프로토타입에 관한 그림 및 내용 참조 : https://www.nextree.co.kr/p7323/
위 사이트에 들어가면 classical 한 방식에 대해 알 수 있습니다. 보시면 왜 prototypal 방식을 선호하는지 이해가 잘 됩니다!
3일 차인 내일 강의는 어느정도 숙지가 된 내용이기에 아직 깊게 학습하지 못한 이벤트 루프, 쿠키, 세션, 웹 스토리지, 모듈, 정규표현식(이건 외우지 말고 그냥 어떠한 기능이 있는지 이해하고 넘어간 뒤에 필요할 때마다 보고 사용하련다..)
부분에 대해서는 내일 다시 학습하여 포스팅 할 예정이다 😁
CS에 대한 부분이 너무 약하다는 걸 느꼈고, 내가 사용하려는 언어나 기술의 동작원리에 대해 정확히 이해한다면, 알고리즘 문제 또는 프로젝트를 경험하며 실제 맞닥뜨릴 문제에 대한 해결 능력에 있어서 더욱 +가 될 것 같은 느낌이 많이 든다. 너무 이해가 안되는 내용이라면 질문하고, 그게 아니라면 오래 걸리더라도 하나씩 하나씩 이해하고 넘어가자!