<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>sour_aguacate</title>
        <link>https://velog.io/</link>
        <description>신입 풀스택 웹개발자로 일하고 있습니다</description>
        <lastBuildDate>Thu, 31 Aug 2023 07:51:17 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>sour_aguacate</title>
            <url>https://velog.velcdn.com/images/sour_aguacate/profile/a68a7e4f-9607-4b57-a596-9e2d8933faee/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. sour_aguacate. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/sour_aguacate" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[CDN(Content Delivery Network)]]></title>
            <link>https://velog.io/@sour_aguacate/CDNContent-Delivery-Network</link>
            <guid>https://velog.io/@sour_aguacate/CDNContent-Delivery-Network</guid>
            <pubDate>Thu, 31 Aug 2023 07:51:17 GMT</pubDate>
            <description><![CDATA[<h3 id="정의">정의</h3>
<p>CDN은 웹 콘텐츠 로드/배포 시 지연을 최소화하기 위해 사용하는 분산된 서버의 그룹이다. 프록시 서버에 웹 페이지, 이미지 등과 같은 콘텐츠를 복사해 캐싱해 놓고 사용자의 요청 시 해당 사용자에게 물리적으로 가까운 서버에서 콘텐츠를 제공하는 형태로 운영된다. 웹 상 다양한 미디어 콘텐츠가 공유되면서 CDN의 중요성이 대두되기 시작했다.</p>
<h3 id="작동-메커니즘">작동 메커니즘</h3>
<p>CDN은 ATM과도 같은 개념으로 생각할 수 있다. 출금을 원할 때마다 사용자들이 은행을 방문하는 수고를 덜어주기 위해 은행은 도시 곳곳에 ATM을 설치한다. 이제 사용자들은 자신의 집에서 먼 은행 대신 바로 길 건너 모퉁이의 ATM기만 찾아가면 언제든지 
이번에는 실제 사례로 CDN의 작동 방식을 이해해보자. 부산의 사용자가 영국에 서버를 둔 웹사이트를 방문했다고 가정하자. 해당 웹사이트에서 비디오와 같은 콘텐츠를 로드하기 위해서는 먼저 요청을 전송하고 응답을 받아야 하는데, 이러한 소통은 말 그대로 바다를 건너서 이루어지는 것이라 속도가 느릴 수밖에 없다. 만약 웹사이트 측에서 영국 서버의 콘텐츠들을 전세계 곳곳의 서버에 캐싱해놓았다면 사용자는 영국보다 훨씬 가까운 곳에서 콘텐츠를 받을 수 있고, 따라서 콘텐츠에 훨씬 빠르게 접근할 수 있다. 이렇게 서버들을 분산해서 위치시킨 곳들을 PoP(Points of Presence)라고 부른다.</p>
<p><img src="https://velog.velcdn.com/images/sour_aguacate/post/b06e490e-1952-4bca-96cc-0b0b542d900c/image.png" alt="">CDN을 사용하지 않을 때는 서버와의 물리적 거리가 늘어날 수록 시간 지연이 증가하는 모습을 보인다.
<br></p>
<p><img src="https://velog.velcdn.com/images/sour_aguacate/post/eb07093b-b284-4466-8e39-3cff2c210877/image.png" alt="">CDN을 사용할 경우 사용자의 요청은 글로벌 서버 로드 밸런서라는 글로벌 레벨의 DNS 서비스가 CDN의 DNS 서버 중 하나로 전달된다. 글로벌 서버 로드 밸런서는 최고 성능을 낼 수 있는 CDN 프록시 서버, 즉, 엣지(Edge) 주소를 선택하여 요청을 전달한다. </p>
<p><img src="https://velog.velcdn.com/images/sour_aguacate/post/b0793621-ea59-4f84-ad25-bd9c798970ca/image.png" alt="">이후 사용자는 해당 엣지에 HTTP 요청을 하고, 엣지 서버는 사용자가 원하는 콘텐츠가 자신이 이미 가지고 있는지 확인한다. 만약 캐싱된 콘텐츠가 있다면 사용자에게 바로 넘겨주고, 그렇지 않다면 먼저 같은 region 그룹의 엣지 서버에 해당 콘텐츠가 있는지 묻는 메세지를 전송한다. 이때도 콘텐츠를 전달 받지 못한다면 원본 서버(Origin Server)에 요청을 전송하여 사용자에게 콘텐츠를 전달해준다. 주의할 점은 CDN은 주로 정적 콘텐츠 전달에 특화되어 있다는 것이다. 정적 콘텐츠는 누가 언제 요청을 하든 내용이 변하지 않는 콘텐츠를 일컫는다. 이미지, CSS 파일, 자바스크립트 라이브러리, 비디오, 정적 HTML 페이지 등이 대표적인 예이다. 동적 콘텐츠의 경우 엣지 서버는 </p>
<p>그런데 엣지 서버에 캐싱된 웹 콘텐츠가 콘텐츠의 가장 최신 버전과 일치함을 어떻게 보증할까? 이 문제를 해결하기 위하여 CDN은 TTL(Time-to-Live) 개념을 도입하였다. TTL값은 캐싱된 콘텐츠가 얼마나 오랫동안 서버에 머물 수 있는지를 결정한다. 다만 TTL값은 캐싱된 콘텐츠가 최신 버전과 같다고 항상 보장하지는 않는다. TTL값은 캐싱된 콘텐츠를 최신 버전이라고 상정할 기간을 임의로 지정한 값이기 때문이다. 또한, TTL값이 지나지 않아도 콘텐츠에 대한 요청 불충분 등의 이유로 콘텐츠가 캐시에서 탈락하는 경우도 있다.
<br>
<img src="https://velog.velcdn.com/images/sour_aguacate/post/89f702ea-29f3-4fb9-8271-872937b40b7a/image.png" alt="">해당 화면은 레딧 웹 어플리케이션 화면으로, 화면의 에러 메세지는 레딧의 CDN 서버가 모종의 이유로 원본 서버에 접근하지 못하여 콘텐츠를 로드하지 못한 상황을 보여준다.
<br></p>
<h3 id="탄생-배경">탄생 배경</h3>
<p>웹 페이지, 이미지 등 콘텐츠에 대한 웹 사용자들의 수요가 폭발적으로 증가하여 CDN의 필요성이 대두하였다. 이후 Netflix 등 주문형 비디오 서비스의 성장으로 CDN에 대한 관심이 더욱 증가하게 되었다. 현재 비디오 스트리밍 사이트, 전자 상거래 플랫폼 등 다양한 호스트들이 CDN을 이용하여 사용자들에게 자사의 콘텐츠를 전달하고 있다.</p>
<p>현재 AWS, GCP 등 클라우드 서비스들은 자신들이 이미 보유한 글로벌 네트워크 인프라를 활용하여 클라우드 CDN를 제공하고 있다. 유명한 서비스로는 AWS의 CloudFront, 구글의 Google Cloud CDN 등이 있다.</p>
<h3 id="장단점">장단점</h3>
<p><strong>장점</strong></p>
<ul>
<li>웹사이트 페이지 로드 시간 개선</li>
<li>원본 서버에 대한 요청을 줄여 웹사이트 소유자의 호스팅 비용 절감</li>
<li>분산 서버 구조 덕분에 원본 서버보다 더 많은 웹 트래픽을 처리 및 하드웨어 오류 견디기 가능</li>
<li>글로벌 서버 로드 밸런서와 엣지 서버의 사용으로 네트워크 전체 용량에 걸쳐 균등하게 로드를 분산함으로써 DDos 공격 가능성 완화</li>
<li>엣지 서버 단위로 더욱 세밀한 액세스 관리 가능</li>
</ul>
<p><strong>단점</strong></p>
<ul>
<li>트래픽 볼륨 등 요소에 따라 과도한 비용 발생 가능</li>
<li>관리해야 될 서버가 많으므로 서비스 관리 복잡도 증가</li>
<li>캐싱 에러, </li>
<li>CDN 관리를 서드 파티 서비스 주체에 위임하면 내 서비스에 대한 제어권 감소</li>
<li>원본 서버가 잘 작동해도 엣지 서버들이 다운되면 서비스 제공 장애 발생 가능</li>
<li>TTL값이 잘 설정되지 않으면 최신 버전 이전의 콘텐츠 제공이 가능한 문제<br>
### 함께 알면 좋은 키워드

</li>
</ul>
<p>proxy server, global server load balancer, edge server, caching
<br>
<em>참고 사이트</em></p>
<p><a href="https://www.cdnetworks.com/ko/what-is">https://www.cdnetworks.com/ko/what-is</a>
<a href="https://www.cloudflare.com/ko-kr/learning/cdn/how-cdns-reduce-bandwidth-cost/https://www.akamai.com/glossary/what-is">https://www.cloudflare.com/ko-kr/learning/cdn/how-cdns-reduce-bandwidth-cost/https://www.akamai.com/glossary/what-is</a>
<a href="https://www.reddit.com/r/explainlikeimfive/comments/2jdzdw">https://www.reddit.com/r/explainlikeimfive/comments/2jdzdw</a>
<a href="https://www.reddit.com/r/webdev/comments/qk39tv/">https://www.reddit.com/r/webdev/comments/qk39tv/</a>
<a href="https://stackoverflow.com/questions/42865428/do-akamai-edge-servers-share-cached-content-or-go-to-">https://stackoverflow.com/questions/42865428/do-akamai-edge-servers-share-cached-content-or-go-to-</a>
<a href="https://www.cloudflare.com/ko-kr/learning/cdn/glossary/time-to-live-ttl/">https://www.cloudflare.com/ko-kr/learning/cdn/glossary/time-to-live-ttl/</a>
<a href="https://www.linkedin.com/advice/1/what-benefits-drawbacks-using-cdn-web-performance-skills-web-design#:~:text=Drawbacks%20of%20a%20CDN&amp;text=A%20CDN%20can%20be%20expensive,overage%20fees%2C%20and%20minimum%20commitments">https://www.linkedin.com/advice/1/what-benefits-drawbacks-using-cdn-web-performance-skills-web-design#:~:text=Drawbacks of a CDN&amp;text=A CDN can be expensive,overage fees%2C and minimum commitments</a>.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CORS(Cross-Origin Resource Sharing)]]></title>
            <link>https://velog.io/@sour_aguacate/CORSCross-Origin-Resource-Sharing</link>
            <guid>https://velog.io/@sour_aguacate/CORSCross-Origin-Resource-Sharing</guid>
            <pubDate>Thu, 31 Aug 2023 04:54:23 GMT</pubDate>
            <description><![CDATA[<h3 id="정의">정의</h3>
<p>CORS는 브라우저가 현재 도메인 밖의 다른 도메인에 속한 자원과 상호작용하기 위해 사용하는 HTTP 헤더 기반의 메커니즘이다. 출처가 다른 어플리케이션 간 상호작용은 CSRF 등의 보안 문제에 취약하기 때문에, 웹은 같은 출처에서만 자원을 공유케 하는 Same-Origin Policy를 수립하였다. 그러나 웹 어플리케이션에서 다른 출처의 자원(서드 파티 api, 라이브러리 등)을 가져와 로드하는 일이 매우 빈번하기 때문에 SOP에 예외 조항을 두었고, 이에 따라 CORS 정책에 부합한다면 현재 도메인 밖의 출처로 자원을 요청할 수 있게 되었다. CORS 정책 부합 여부는 서버가 아닌 브라우저가 판단한다.
<br></p>
<h3 id="같은-출처-구분-기준">같은 출처 구분 기준</h3>
<p><img src="blob:https://velog.io/34bfda82-8768-405f-a8ec-980199ac66a5" alt="업로드중.."></p>
<p>출처(Origin)는 위 그림의 Protocol, Host 그리고 생략된 포트 번호를 합친 것으로, 서버의 위치를 찾아갈 때 필수적인 정보의 합을 일컫는다. 따라서 같은 출처라 함은 Protocol/Scheme, Host, Port Number 값이 동일한 출처를 말한다. </p>
<table>
<thead>
<tr>
<th>URL</th>
<th>구분</th>
<th>이유</th>
</tr>
</thead>
<tbody><tr>
<td><a href="http://store.aws.com/dir/page.html">http://store.aws.com/dir/page.html</a></td>
<td>클라이언트 URL</td>
<td></td>
</tr>
<tr>
<td><a href="http://store.aws.com/dir2/new.html">http://store.aws.com/dir2/new.html</a></td>
<td>동일한 오리진</td>
<td>경로만 다름</td>
</tr>
<tr>
<td><a href="http://store.aws.com/dir/inner/other.html">http://store.aws.com/dir/inner/other.html</a></td>
<td>동일한 오리진</td>
<td>경로만 다름</td>
</tr>
<tr>
<td><a href="https://store.aws.com/page.html">https://store.aws.com/page.html</a></td>
<td>다른 오리진</td>
<td>다른 프로토콜</td>
</tr>
<tr>
<td><a href="http://store.aws.com:81/dir/page.html">http://store.aws.com:81/dir/page.html</a></td>
<td>다른 오리진</td>
<td>다른 포트(http:// 는 기본적으로 포트 80임)</td>
</tr>
<tr>
<td><a href="http://news.aws.com/dir/page.html">http://news.aws.com/dir/page.html</a></td>
<td>다른 오리진</td>
<td>다른 호스트</td>
</tr>
<tr>
<td><br></td>
<td></td>
<td></td>
</tr>
</tbody></table>
<h3 id="cors-작동-메커니즘">CORS 작동 메커니즘</h3>
<p><strong>Simple Request</strong></p>
<p><img src="https://velog.velcdn.com/images/sour_aguacate/post/054201d3-1ae5-4f68-a7ae-9dc097176b1e/image.png" alt=""></p>
<p><code>GET</code>, <code>POST</code> 메서드 사용 시에만 사용 가능한 방식이다. 또한, 해당 방식과 사용 가능한 헤더의 종류에도 제한이 있고, <code>Content-Type</code>을 사용하는 경우 <code>multipart/form-data</code>, <code>text/plain</code> 등만 한정적으로 허용한다. 따라서 사용 빈도가 높은 <code>text/xml</code> 또는 <code>application/json</code> 컨텐츠 타입에 대해서는 사용이 불가하다. </p>
<p>해당 방식 사용 시 예비 요청(Preflight request) 없이 바로 서버에게 본 요청을 보내고, 서버가 응답 헤더에 <code>Access-Control-Allow-Origin</code> 값을 보내주면 이를 바탕으로 브라우저가 CORS 정책 위반 여부를 검사한다. 위의 이미지에서 보면 <code>Access-Control-Allow-Origin</code>의 값이 *인데, 이는 어떠한 출처에서든 해당 자원을 액세스할 수 있음을 의미한다.</p>
<p><strong>Preflight Request</strong></p>
<p><img src="https://velog.velcdn.com/images/sour_aguacate/post/596ca2d5-ce74-42a8-be18-6e65c0bdc3f7/image.png" alt=""></p>
<p>일반적인 웹 어플리케이션에서 대부분 사용하는 방식이다. 자원 요청 시 브라우저가 서버에 예비 요청을 먼저 전송하고, 서버의 응답에 따라 같은 서버로 본 요청을 보낸다.</p>
<pre><code class="language-jsx">**OPTIONS /doc HTTP/1.1**
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
**Origin: https://foo.example**
**Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type**</code></pre>
<p>예비 요청은 <code>OPTIONS</code>라는 HTTP/1.1 메서드를 사용하여 이루어진다. <code>Origin</code> 헤더에는 자신의 도메인을, <code>Access-Control-Request-Headers</code>에는 본 요청에서 사용할 헤더 정보들을 넣어 예비 요청을 전송한다. 
<br></p>
<pre><code class="language-jsx">HTTP/1.1 204 No Content
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2
**Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type**
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive</code></pre>
<p>예비 요청을 받은 서버는 자원 액세스 가능 여부를 판단하여 브라우저에 응답을 전송한다. 응답 헤더들을 살펴보면 어떠한 출처에서 자원을 액세스 할 수 있는지 뿐만 아니라 어떠한 HTTP 메서드로 자원에 접근 가능한지, 예비 요청에서 브라우저가 보낸 <code>Access-Control-Request-Headers</code>의 헤더들을 본 요청에서 사용 가능한지 여부 등을 명시하고 있다. 한편, 예비 요청은 서버의 응답에 명시된 시간만큼 캐싱될 수 있다.
<br></p>
<pre><code class="language-jsx">POST /doc HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF-8
Referer: https://foo.example/examples/preflightInvocation.html
Content-Length: 55
Origin: https://foo.example
Pragma: no-cache
Cache-Control: no-cache</code></pre>
<p>예비 요청에서 자원 액세스가 가능하다는 응답을 받았기 때문에 브라우저는 서버로 본 요청을 전송한다. 본 요청의 내용은 Simple Request와 동일하다.
<br></p>
<h3 id="cors-정책-위반-방지법">CORS 정책 위반 방지법</h3>
<p>CORS 정책 위반 시에도 보안 상의 이유로 에러의 상세 내용은 확인할 수 없으므로 처음부터 에러가 발생하지 않도록 방지하는 것이 중요하다. CORS 정책 위반 여부는 브라우저에서 검사하지만 방지 조치는 주로 서버단에서 수행한다.</p>
<p>커스텀 필터를 생성하거나 WebMvcConfigurer를 이용해서 처리할 수도 있지만 내가 사용한 방법은 컨트롤러에서 <code>@CrossOrigin</code> 어노테이션을 추가해주는 것이었다. 서드 파티 api를 사용한 부분에서 계속 CORS 에러가 났는데 해당 api를 호출하는 컨트롤러 메서드에 해당 어노테이션을 추가해주니 에러가 해결되었다. <code>@CrossOrigin</code>은 컨트롤러 레벨이나 메서드 레벨 중 선택해서 추가하거나 둘 다 해주어도 된다.</p>
<pre><code class="language-java">@Controller
@CrossOrigin(origins = &quot;https://foo.example&quot;) // 컨트롤러에서 설정
public class AdminController{

    @GetMapping
    @CrossOrigin(origins = &quot;https://foo.example&quot;) // 메서드에서 설정
    public String memberList(){
        }
}</code></pre>
<p><i>* 해당 글은 다음의 글들을 참고하여 작성하였습니다: </i>
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS</a>
<a href="https://evan-moon.github.io/2020/05/21/about-cors/">https://evan-moon.github.io/2020/05/21/about-cors/</a>
<a href="https://aws.amazon.com/ko/what-is/cross-origin-resource-sharing/">https://aws.amazon.com/ko/what-is/cross-origin-resource-sharing/</a>
<a href="https://wonit.tistory.com/572">https://wonit.tistory.com/572</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ES6 모듈과 번들링]]></title>
            <link>https://velog.io/@sour_aguacate/ES6-%EB%AA%A8%EB%93%88%EA%B3%BC-%EB%B2%88%EB%93%A4%EB%A7%81</link>
            <guid>https://velog.io/@sour_aguacate/ES6-%EB%AA%A8%EB%93%88%EA%B3%BC-%EB%B2%88%EB%93%A4%EB%A7%81</guid>
            <pubDate>Wed, 30 Aug 2023 16:12:14 GMT</pubDate>
            <description><![CDATA[<h3 id="npmnode-package-manager">NPM(Node Package Manager)</h3>
<p>원래 자바스크립트 라이브러리나 파일을 다른 파일에서 사용 시 직접 다운받아서 스크립트 태그 형식으로 직접 포함시켜야 했다. 하지만 이 방식은 라이브러리 버전 관리도 힘들고, 다른 사용자와의 파일 공유시 다른 사용자들도 각자 사용된 라이브러리 및 스크립트를 다운로드해야한다는 단점이 있었다. 이를 개선하고자 등장한 것이 패키지 매니저 프로그램들이다.</p>
<p>npm은 <code>package.json</code> 파일을 생성해 해당 프로젝트 관련 정보를 관리한다. npm install을 통해 원하는 패키지를 설치하면 해당 패키지가 <code>package.json</code> 파일의 프로젝트 dependency 목록에 추가된다. 따라서 프로젝트를 공유할 때 패키지가 설치된 폴더 대신 <code>package.json</code> 파일만 공유하면 다른 사용자들이 자동으로 필요한 패키지를 설치할 수 있다는 장점이 있다.
<br></p>
<h3 id="번들링bundling">번들링(Bundling)</h3>
<p>하지만 npm으로 다운받은 파일은 스크립트 태그 형식으로 직접 추가해 주어야하는 불편사항을 여전히 있었다. 자바스크립트는 브라우저에서만 실행하기위해 만들어진 언어였으므로 애초에 클라이언트의 파일 시스템에 액세스할 수 없기 때문이다. 이러한 불편사항을 극복하기 위하여 번들러 프로그램들이 출시되었다. Webpack을 비롯한 번들러 프로그램들은 dependency들이 import되는 지점을 찾아 이를 import되는 파일에서 실제 필요한 내용으로 변환하고, 최종적으로 프로젝트를 하나의 자바스크립트 파일로 묶어준다. 번들러는 사용자가 지정한 entry point를 시작으로 프로젝트의 모든 파일을 살펴서 entry point 당 하나의 결과 파일, 즉, 하나의 컴파일된 output을 생성한다.
<br></p>
<h3 id="es6-모듈modules">ES6 모듈(Modules)</h3>
<p>번들러 프로그램은 ES6 모듈을 사용하는 프로젝트의 경우 특히 중요하다. 프로젝트가 여러 모듈 파일로 구성되어 있을 경우 브라우저가 각 파일에 대해 별도의 HTTP request를 날려야 할 수도 있기 때문에 프로젝트 크기나 복잡도에 따라 속도나 비용 면에서 큰 손실이 발생할 수도 있기 때문이다.</p>
<p>한편, 모듈은 코드 재사용성의 증가라는 큰 장점을 가지고 있다. import 선언을 통해 자바스크립트 파일을 현재 페이지에서 바로 사용할 수 있고, 반대로 export 선언을 통해 다른 페이지에서 사용하고 싶은 값, 함수, 클래스, 생성자 등을 내보낼 수 있는 덕분이다. </p>
<p><strong>export</strong></p>
<p>export는 named export와 default export 두 종류가 있다. 모듈 당 named export는 여러 개, default export는 단 한 개만 허용된다. export 선언의 이름은 겹쳐서는 안되며, 중복시 <code>syntaxError</code>가 발생한다.</p>
<ol>
<li><p>named export</p>
<pre><code class="language-jsx"> export { myFunction2, myVariable2 };
 export let myVariable = Math.sqrt(2);
 export function myFunction() {}</code></pre>
<ul>
<li>여러 개의 값을 export 할 때 유용</li>
<li>import한 파일은 넘어온 값들을 export된 명으로 칭해야 함</li>
</ul>
</li>
<li><p>default export</p>
<pre><code class="language-jsx"> export default 1 + 1;
 export default function foo() {
   console.log(&quot;Hi&quot;);
 }
 export default function () {
   console.log(&quot;Hi&quot;);
 }</code></pre>
<ul>
<li><code>export</code> 키워드 뒤에 어떠한 표현(expression)도 허용</li>
<li>함수와 클래스를 익명으로 export 가능</li>
<li>import시 어떠한 이름으로도 칭할 수 있음</li>
</ul>
</li>
</ol>
<p><strong>import</strong></p>
<pre><code class="language-jsx">import { foo, bar } from &quot;/modules/my-module.js&quot;;
import * as myModule from &quot;/modules/my-module.js&quot;;</code></pre>
<ul>
<li>export한 모듈의 변화에 따라 import한 값이 업데이트되지만, 반대로 현재 파일에서의 변화가 export한 모듈에 적용되지 않는 live binding 방식</li>
<li>import 선언은 모듈의 최상위 레벨에서 이루어져야함</li>
<li>expression대신 스트링 리터럴 식별자만 사용 가능</li>
<li>위와 같이 엄격한 구문 문법 적용덕분에 모듈의 dependency들을 runtime 이전에 정적으로 분석 가능<br>
### Single Page Application 개발에서의 활용
Vue.js는 컴포넌트 사용에 있어 ES6 모듈 방식을 적극 활용한다. Vue.js의 공식 문서에도 언급되어 있듯이 Vue.js는 컴포넌트 기반 구조와 클라이언트 단의 라우터 등의 다양한 툴을 제공하여 Single Page Application 개발에 적합한 프레임워크이다. 번들러 프로그램은 Vue.js의 컴포넌트 등의 자원들을 묶어서 브라우저에서 보다 효율적으로 동작하도록 도울 수 있다.
<br>
<br></li>
<li><i>해당 글은 다음의 글들을 참고하여 작성하였다</i>:</li>
<li><a href="https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html">https://peterxjang.com/blog/modern-javascript-explained-for-dinosaurs.html</a></li>
<li><a href="https://www.theodinproject.com/lessons/node-path-javascript-es6-modules">https://www.theodinproject.com/lessons/node-path-javascript-es6-modules</a></li>
<li><a href="https://ljs0705.medium.com/spa-single-page-app-%EC%97%90%EC%84%9C-webpack%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-ce7d3f82fe9">https://ljs0705.medium.com/spa-single-page-app-에서-webpack을-사용하는-이유-ce7d3f82fe9</a></li>
<li><a href="https://vuejs.org/guide/extras/ways-of-using-vue.html#single-page-application-spa">https://vuejs.org/guide/extras/ways-of-using-vue.html#single-page-application-spa</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[갑자기 EC2 배포 주소로 연결이 안되는 오류 해결]]></title>
            <link>https://velog.io/@sour_aguacate/%EA%B0%91%EC%9E%90%EA%B8%B0-EC2-%EB%B0%B0%ED%8F%AC-%EC%A3%BC%EC%86%8C%EB%A1%9C-%EC%97%B0%EA%B2%B0%EC%9D%B4-%EC%95%88%EB%90%98%EB%8A%94-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0</link>
            <guid>https://velog.io/@sour_aguacate/%EA%B0%91%EC%9E%90%EA%B8%B0-EC2-%EB%B0%B0%ED%8F%AC-%EC%A3%BC%EC%86%8C%EB%A1%9C-%EC%97%B0%EA%B2%B0%EC%9D%B4-%EC%95%88%EB%90%98%EB%8A%94-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0</guid>
            <pubDate>Mon, 31 Jul 2023 09:29:05 GMT</pubDate>
            <description><![CDATA[<h3 id="오류의-내용">오류의 내용</h3>
<p>EC2 서버로 배포한 서비스가 갑자기 연결이 안된다. 배포 주소로 들어가면 연결을 거부했다는 메세지만 계속 출력되는 것이다. 며칠 전만 해도 잘 작동하는 걸 직접 확인했는데 너무 당황스러웠다. 일단 인스턴스에 문제가 생겼는지 확인하기 위해서 다음의 사항들을 확인해보았다:</p>
<ol>
<li>인스턴스 상태가 running인지 확인</li>
<li>보안 그룹 인바운드/아웃바운드 규칙 확인</li>
<li>IP 주소 변경 여부 확인</li>
<li>인스턴스 시스템 로그 확인</li>
</ol>
<br>

<h3 id="오류의-이유">오류의 이유</h3>
<p>확인 결과 인스턴스는 문제 없이 구동 중이었다. 오류의 이유도 모른 채 ‘EC2 연결 오류’로 구글링만 하염 없이 해도 대부분은 인스턴스 문제에 관한 팁이어서 별 도움이 되지 않았다. 그러다 번뜩 떠오른 것이 AWS 웹사이트에서 확인 가능한 인스턴스 콘솔 스크린샷이었다. 인스턴스 콘솔 스크린샷을 보니 그제야 오류의 원인을 파악할 수 있었다:</p>
<p><img src="https://velog.velcdn.com/images/sour_aguacate/post/8c54e558-75ed-47a9-a1a9-4f8c0a3951b0/image.png" alt=""></p>
<p>메모리가 부족해서 서비스를 강제로 종료한 것이었다. AWS 공식 홈페이지에 따르면 out of memory 발생 시 Linux Out Of Memory(OOM) 매니저가 호출되고, 이 매니저가 프로세스들을 강제 종료시킨다고 한다.$\tt{^{1}}$ 나는 다행히 해당 인스턴스에서 swiftER 서비스만 구동 중이었기에 서비스가 강제 종료되는 선에서 끝났지만 여러 서비스를 배포/구동 중이었다면 연쇄적으로 피해가 발생할 수도 있는 상황이었다. EC2 인스턴스는 기본적으로 스왑 공간을 할당받지 않아서 직접 스왑 파일을 생성해야 한다. 공식 홈페이지에서 설명하는 스왑 파일 생성 방법은 다음과 같다:
<br></p>
<h3 id="스왑-파일-생성-방법">스왑 파일 생성 방법</h3>
<p>1.   <strong>dd</strong> 명령을 사용하여 루트 파일 시스템에 스왑 파일을 생성합니다. </p>
<pre><code>$ sudo dd if=/dev/zero of=/swapfile bs=128M count=32</code></pre><p>2.    스왑 파일의 읽기 및 쓰기 권한을 업데이트합니다.</p>
<pre><code>$ sudo chmod 600 /swapfile</code></pre><p>3.    Linux 스왑 영역을 설정합니다.</p>
<pre><code>$ sudo mkswap /swapfile</code></pre><p>4.    스왑 공간에 스왑 파일을 추가하여 스왑 파일을 즉시 사용할 수 있도록 합니다.</p>
<pre><code>$ sudo swapon /swapfile</code></pre><p>5.    프로시저가 성공적인지 확인합니다.</p>
<pre><code>$ sudo swapon -s</code></pre><p>6.    <strong>/etc/fstab</strong> 파일을 편집하여 부팅 시 스왑 파일을 시작합니다. 먼저, 편집기에서 파일을 엽니다.</p>
<pre><code>$ sudo vi /etc/fstab</code></pre><p>파일 끝에 다음 줄을 새로 추가하고 파일을 저장한 다음 종료합니다.
<br></p>
<h3 id="해결">해결</h3>
<p>위의 방식대로 하니 서비스가 다시 정상적으로 구동하기 시작했다.</p>
<p><img src="https://velog.velcdn.com/images/sour_aguacate/post/c2e0309f-db14-4844-a4b8-9b77156f8c30/image.png" alt=""></p>
<hr>
<p>1) <a href="https://repost.aws/knowledge-center/ec2-linux-prevent-over-utilization">https://repost.aws/knowledge-center/ec2-linux-prevent-over-utilization</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Threads and Processes]]></title>
            <link>https://velog.io/@sour_aguacate/Threads-and-Processes-4np9qp9n</link>
            <guid>https://velog.io/@sour_aguacate/Threads-and-Processes-4np9qp9n</guid>
            <pubDate>Sun, 09 Jul 2023 10:55:36 GMT</pubDate>
            <description><![CDATA[<p>해당 노트는 UC Berkeley CS162 lecture 2를 듣고 작성한 강의 노트이다.</p>
<h3 id="threads">Threads</h3>
<p>Each thread can represent one chunk of code and is a unit of concurrency provided by the OS. In other words, the OS can handle multiple things at once with threads. </p>
<p><img src="https://velog.velcdn.com/images/sour_aguacate/post/ff7225c7-6732-4c69-9478-425f48eb7cbc/image.png" alt=""></p>
<p>A thread is in one of the three states: running, ready and blocked. If a thread is waiting for an I/O to finish, the OS marks it as blocked. Once the I/O operation finishes, the OS marks it as ready. Once a process starts, it issues system calls to create new threads. The calls are usually made by OS library or language runtime so system calls are hidden below programming interface. For example, $\tt{pthread_create()}$ in C library issues a system call with some special assembly code and then the kernel creates a new thread and return the values and the program runs in user mode again. </p>
<p>Main thread creates, or, forks subthreads and after its subthreads are done, it joins with them, collecting their results. While content of memory and I/O state are shared by all threads in one process, information in TCB, CPU registers(including program counter) and execution stack are kept private to each thread. Execution stack stores parameters and temporary variables. A thread’s stack can touch that of another thread but since the focus of protection is on process itself, not individual threads, procedures to prevent this aren’t essential. </p>
<p>Scheduler can run threads in any order and can switch threads at any time. This can be problematic in race conditions where threads might depend on the result of other threads. To prevent race conditions, synchronization is needed. A lock is an object only one thread can hold at a time, ensuring only one thread does a particular thing at a time. Before a thread executes, it will claim to acquire a lock and after execution it will release the lock so one of the other threads can acquire it.</p>
<p><img src="https://velog.velcdn.com/images/sour_aguacate/post/a99fa92e-7c63-4424-9e63-eedaa3ec4478/image.png" alt=""></p>
<h3 id="processes">Processes</h3>
<p>Processes are always created by other processes and the first process is initiated by the kernel. The OS library calls main thread (i.e. public static void main(String[] args) in java) and when main returns, the library calls exit on the process.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Thread, Address Space, Process and Dual Mode Operation]]></title>
            <link>https://velog.io/@sour_aguacate/Thread-Address-Space-Process-and-Dual-Mode-Operation</link>
            <guid>https://velog.io/@sour_aguacate/Thread-Address-Space-Process-and-Dual-Mode-Operation</guid>
            <pubDate>Sun, 09 Jul 2023 10:53:42 GMT</pubDate>
            <description><![CDATA[<p>해당 노트는 UC Berkeley CS162 lecture 2를 듣고 작성한 강의 노트이다.</p>
<h3 id="thread">Thread</h3>
<p>A thread is a single unique execution context that has a program counter, registers, execution flags, stack and memory state. Out of many threads, only one at a time gets executed on a processor when it is resident in the processor registers. Being resident means that the registers hold the root state of that thread including PC register pointing at the next instruction of the instructions in memory, intermediate values/pointers for ongoing computations and stack pointer holding the address of the top of stack. On the contrary, a thread is suspended, or, not executing when its state is not loaded into the processor registers. The last values from the execution are stored in memory during this period.</p>
<p>With a single processor, you can <strong>multiplex the hardware</strong> in time to achieve the illusion of multiple processors, running a part of each thread for a certain amount of time, alternating between threads. These threads are virtual cores. Switching from one thread to another is called <strong>context switching</strong>. During context switching, OS saves the current thread’s PC, SP, etc. information in its thread control block in memory and load that of the other thread.</p>
<p><img src="https://velog.velcdn.com/images/sour_aguacate/post/1f9d0109-260a-4c50-8c98-3679ec5e09d5/image.png" alt=""></p>
<p>While the illusion of multiple processors is achievable, the aforementioned way is not safe in that the threads share the same memory and thus can overwrite each other, even OS. A simple protection approach is base and bound where the start and end of the execution boundary of a thread are written in base register and bound register respectively. Whenever a program executes, hardware will check if the address program counter inputs is within that range. When a thread is loaded into memory, it is relocated according to the base register and the program counter will store addresses within the range. Instead, if you add an adder by which the program counter will store addresses as is and the adder will add the value of the base register when they are loaded to memory.</p>
<p>One significant problem this method has is when the currently running program needs more memory space, the current memory space’s contents have to be copied into somewhere bigger. After use, it can cause fragmentation errors. An alternative is translation where instructions operate on virtual addresses and the hardware translates them into physical addresses with a page table.</p>
<h3 id="address-space">Address Space</h3>
<p>An address space is a set of memory addresses accessible to program for read/write. It includes program counter, static data, stack, heap and so on.</p>
<h3 id="process">Process</h3>
<p>A process is an execution environment with restricted rights. In other words, it is a protected (by base and bound or translation mentioned in the thread section) address space with one or more threads. Application programs usually execute as a process. While it is easy for threads within the same process to communicate as they share memory, it is harder for processes to communicate with one another for protection. Bugs can only overwrite memory of process they are in and malicious process cannot read/write other process’ data.</p>
<p><img src="https://velog.velcdn.com/images/sour_aguacate/post/97dea45c-3d61-479b-9229-c864f81479d4/image.png" alt=""></p>
<h3 id="dual-mode-operation">Dual Mode Operation</h3>
<p>Hardware provides at least two modes: kernel mode and user mode. Some operations are prohibited in user mode. Processes execute in user mode while kernel executes in kernel mode. A program can issue a system call to transition into kernel mode.</p>
<p><img src="https://velog.velcdn.com/images/sour_aguacate/post/c28942b4-486c-4bd3-8a1d-c8bbe99d6ed7/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[AVL Tree]]></title>
            <link>https://velog.io/@sour_aguacate/AVL-Tree</link>
            <guid>https://velog.io/@sour_aguacate/AVL-Tree</guid>
            <pubDate>Thu, 06 Jul 2023 02:11:19 GMT</pubDate>
            <description><![CDATA[<p>여기에 정리할 요약 노트의 원 강의는 MIT 6.006 Introduction to Algorithms, Spring 2020이다.</p>
<h3 id="binary-search-tree-set-binary-tree">Binary Search Tree (Set Binary Tree)</h3>
<p>Finding a certain item can be done with binary search if the nodes are ordered so that the keys the nodes represent are in an increasing order</p>
<ul>
<li><p>subtree_find(node, k):</p>
<p>  if node is not to be found, return. If k &lt; node.item.key, recurse on node.left. If equal, return the node as this is the node we intended to look for. If k &gt; node.item.key, recurse on node.right. As you can see, it is the same as binary search </p>
</li>
</ul>
<h3 id="sequence-binary-tree">Sequence Binary Tree</h3>
<p>Its traversal order is the sequence order. The challenge is to find the <em>ith</em> node in the subtree. Knowing the size of the subtree is crucial and the size of a node means the number of nodes in the subtree, including the node itself
<img src="https://velog.velcdn.com/images/sour_aguacate/post/19cc633d-7c34-42d5-971c-2f85f4aeb226/image.png" alt=""></p>
<ul>
<li><p>subtree_at(node, i):</p>
<p>  Set an arbitrary variable NL to the size of node.left(the subtree on the left in the picture above). Suppose we know the value of the size somehow. So the index* of the root node is NL. If i &lt; NL then recurse on node.left. If i = NL, return the current node. Lastly, if i &gt; NL then do subtree_at(node.right, i-NL-1) recursively. We readjust the NL’s value to i-NL-1 because we don’t need node.left(NL) and the root node(1) so we subtract them. This operations takes O(height)</p>
<p>  <em>* when dealing with set binary trees, keys were used; here, indices are used with sequence objects</em></p>
</li>
</ul>
<h3 id="subtree-augmentation">Subtree Augmentation</h3>
<p>Each node can store O(1) extra fields/properties. Subtree property can be computed from properties of its left or right children in O(1) time. Size of a sequence binary tree is a property as node.size = node.left.size + node.right.size + 1(itself). If every node has its size as its property, we can get a size of a particular node in constant time. Common properties include sum, min, max of some feature of every node in subtree. </p>
<p>However, you cannot store the index or depth of each node as once a new node is added, every node’s index changes and a node’s index doesn’t necessarily depend on the subtree it belongs to. For example, the index of the first node in node.right right below the root is solely reliant on the number of nodes in node.left and root.</p>
<p>When a new leaf is added or removed, the newly created subtree(which is the new leaf itself) and the subtrees that contain its ancestors should be updated. The number of subtrees to be updated is the same as the height of the tree. To update the subtrees, you need to update each ancestor’s size value bottom up. To update one subtree takes a constant time because its children have correct information either because they were unaffected by the change or they already have been updated before we’ve moved on to the subtree at focus. Thus, the whole operation as a whole takes O(height).
<img src="https://velog.velcdn.com/images/sour_aguacate/post/0208682d-06a8-4133-8161-3bc4d1465c53/image.png" alt=""></p>
<h3 id="avl-tree">AVL Tree</h3>
<p>When the height equals log n, the tree is considered <code>balanced</code>. To rebalance an unbalanced tree, you need the rotation trick. Rebalancing means reorganize the tree without modifying its original traversing order.  </p>
<p><img src="https://velog.velcdn.com/images/sour_aguacate/post/31c0a43d-a5cc-4221-9ff9-40f72f8767d7/image.png" alt=""></p>
<p>An AVL tree is a tree that maintains height balance, so that height(node.right) - height(node.left), or skew(node) is always either -1, 0 or 1. Suppose we have a tree whose node.left is shorter than node.right by 1 in terms of height. The number of nodes in an AVL tree of height H($N_h$) is $N_{h-1}$ + $N_{h-2}$ + 1(root). </p>
<p>💡 $N_h$ &gt; $N_{h-2}$ + $N_{h-2}$ = 2 x $N_{h-2}$ 
This(2 x $N_{h-2}$) is powers of two thus this is exponential. This implies the height, h, is equal to or smaller than 2 log n.</p>
<p>Height is a subtree property in that node.height = max{node.left.height, node.right.height} + 1. When adding or deleting a node to an AVL tree, the height of a subtree might change, which in turn might make the skew value go out of range of -1, 0 and 1 (the new value is either -2 or 2). To rebalance the tree, you have to rotate it. When skew(y) is either 0 or 1(like in the picture below), you only need to rotate the tree so that y is now the root.
<img src="https://velog.velcdn.com/images/sour_aguacate/post/40c2c60a-6b9f-490e-a832-eb5b5a5fbacb/image.png" alt=""></p>
<p>On the contrary, if skew(y) is -1, the rotation gets complicated but still doable.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[관리자/사용자가 아이디를 변경할 수 있도록 설정해야할까?]]></title>
            <link>https://velog.io/@sour_aguacate/%EA%B4%80%EB%A6%AC%EC%9E%90%EC%82%AC%EC%9A%A9%EC%9E%90%EA%B0%80-%EC%95%84%EC%9D%B4%EB%94%94%EB%A5%BC-%EB%B3%80%EA%B2%BD%ED%95%A0-%EC%88%98-%EC%9E%88%EB%8F%84%EB%A1%9D-%EC%84%A4%EC%A0%95%ED%95%B4%EC%95%BC%ED%95%A0%EA%B9%8C</link>
            <guid>https://velog.io/@sour_aguacate/%EA%B4%80%EB%A6%AC%EC%9E%90%EC%82%AC%EC%9A%A9%EC%9E%90%EA%B0%80-%EC%95%84%EC%9D%B4%EB%94%94%EB%A5%BC-%EB%B3%80%EA%B2%BD%ED%95%A0-%EC%88%98-%EC%9E%88%EB%8F%84%EB%A1%9D-%EC%84%A4%EC%A0%95%ED%95%B4%EC%95%BC%ED%95%A0%EA%B9%8C</guid>
            <pubDate>Wed, 24 May 2023 16:12:30 GMT</pubDate>
            <description><![CDATA[<p>swiftER은 나의 첫 스프링부트 프로젝트이자, 처음으로 조장을 맡아 프로젝트를 총괄할 기회였다. 기존 팀 프로젝트와 달리 이번에는 기획, 데이터베이스 구조 작성 등 프로젝트의 처음과 끝을 나와 팀원들이 모두 책임져야했다. 그러다보니 평소에는 별 생각없이 사용했던 기능을 구현할 때도 다방면으로 고민을 해야 하는 경우가 생각보다 많았다. 오히려 개발 단계에 들어간 여러 고민과 숙고 덕분에 사용자인 내가 별다른 생각 없이 기능을 사용할 수 있었구나하는 생각도 들었다.</p>
<p>위의 물음은 사용자가 마이 페이지에서 자신의 회원 정보를 조회하는 기능을 만들다가 문득 떠올랐다. 대부분의 웹서비스에서 사용자가 자신의 아이디를 변경할 수 없는 것이 관례이지만 우리 서비스에서도 역시 아이디 변경 불가 원칙을 고수할 것인지 먼저 고민해보고 싶었다. 사용자는 자신의 아이디를 변경하지 못하더라도 관리자도 사용자들의 아이디를 변경하지 못하게 해야 할까? 스택 오버플로우같은 사이트들을 찾아보기도 하고 팀원들과 머리를 맞대고 고민한 결과, 관리자와 사용자 모두 아이디를 변경하지 못하는 방향으로 결론을 내렸다. 변경 불허의 근거는 다음과 같다:
<br>
네이버, 페이스북 등의 서비스는 데이터 무결성을 이유로 대부분의 경우 아이디 변경을 불허한다. 데이터 관련 이슈의 경우, 아이디를 다른 테이블에서 외래키로 참조하고 있다면 아이디가 변경되었을 때 해당 테이블에서도 값을 변경해주어야한다. heidiSQL 기준 외래키 설정에서 on update 항목의 값을 cascade로 설정하면 아이디 변경 시 해당 아이디를 참조하는 테이블의 아이디 값도 자동으로 바뀌기는 하지만 아이디를 참조하는 테이블이 많고, 아이디 변경이 많이 일어난다면 유지보수가 힘들 것이다. 같은 논리로, 만약 사용자의 아이디 변경을 허가하더라도 다른 유저의 변경 전 아이디를 사용하지 못하게 해야 할 것이다.</p>
<p>아이디 변경을 보통 불허하는 또 다른 이유로는 아이디 값이 hard code되는 부분이 있다는 것이다. 예를 들어 사용자가 자신의 개인 페이지에 다른 사람들이 방문할 수 있도록 링크를 공유하는데, 그 링크에 아이디값이 파라미터로 들어있다면 이미 공유된 링크에 대해서는 아이디가 변경되어도 아이디 파라미터값을 바꿀 수 없다.</p>
<p>보안 문제도 생각해보아야 한다. 조원의 개인적인 경험에 따르면, 조원의 스팀 계정이 해킹당하였는데 해커가 이메일 등 모든 정보를 바꾸었지만 스팀 정책 상 아이디는 바꿀 수 없었고, 그 덕분에 기존 아이디로 계정을 복구할 수 있었다고 한다. 만약 해커가 아이디까지 바꾸었다면 기존 계정에 접근할 방법이 없었을 것이다.
<br>
새로 아이디를 만드는 대신 이메일을 로그인 식별 정보로 사용하는 방법도 고민해보았다. 어차피 회원가입할 때 이메일을 입력하고 인증까지 거쳐야 하기때문에 이메일을 사용하는 일 자체는 문제가 되지 않을 것이라 생각한다. 그러나 가입 당시 등록한 이메일을 나중에 사용자가 삭제할 경우 등 나름의 문제가 있기 때문에 이메일을 사용하는 방법은 보류하였다. 로그인 식별 정보로서의 아이디, 그리고 아이디 변경 가능 여부는 추후 우리 서비스를 사용하는 사용자들이 생긴다면 다시 깊게 고민해보아야 할 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Binary Trees]]></title>
            <link>https://velog.io/@sour_aguacate/Binary-Trees</link>
            <guid>https://velog.io/@sour_aguacate/Binary-Trees</guid>
            <pubDate>Wed, 24 May 2023 15:37:04 GMT</pubDate>
            <description><![CDATA[<p>여기에 정리할 요약 노트의 원 강의는 MIT 6.006 Introduction to Algorithms, Spring 2020이다.</p>
<h3 id="binary-tree">Binary Tree</h3>
<p>A node in a binary tree typically has an item and three <code>pointers</code>: parent pointer, left pointer(child) and right pointer(child). A root is a node that does not have a parent pointer. Unlike singly or doubly linked list, you can get to a node within less than a linear time, and possibly within a logarithmic time. In a singly linked list, the item at the end has a high depth value, meaning you have to follow many pointers to get there. In a doubly linked list, you can get to the end easily but again, it takes a linear time to get to the middle of the list.</p>
<h3 id="traversal-order-of-a-binary-tree">Traversal Order of a Binary Tree</h3>
<p>A binary tree decomposes into subtrees; a subtree of x consisting of x (root of the subtree) and its descendants. It also has <code>leaves</code>, nodes with no children. The <code>depth</code> of a node is the number of its ancestors or the number of edges (an edge is a line that connects two nodes) in path from x up to the root. The <code>height</code> of a node is the number of edges in the longest downward path from x or the maximum depth in x’s subtree. All leaves have height of 0 and the height of the root is the same as the height of the tree.</p>
<p><img src="https://velog.velcdn.com/images/sour_aguacate/post/f93fd533-709c-4eb8-aa90-57bfe534ae4b/image.png" alt=""></p>
<p>When traversing a tree, you should determine the traversal order of nodes. Suppose for every node x, nodes in x.left come before x while nodes in x.right come after x. With this particular traversal order, we can define some traversal operations: </p>
<ul>
<li><p>subtree_first(node)</p>
<p>  This operation decides which node in the subtree should come first during traversal. Here, it should go to the bottom left first(node = node.left) and return the node.</p>
</li>
</ul>
<ul>
<li><p>successor(node)</p>
<p>  This operation finds the next after node in traversal. If node.right exists, meaning if the node has a right child, it should return <code>subtree_first(node.right)</code>. Else, walk up the tree (node=node.parent) until you go up to a left branch(node = node.parent.left) and return the node. You hitting the left branch is when the traversal direction becomes reverse.</p>
</li>
</ul>
<p>The operations above will be O(height)</p>
<ul>
<li><p>subtree_insert_after(node.new)</p>
<p>  This operation inserts a new node so that it comes after a particular node during traversal. If there’s no node.right, put the new node there. Else, put the new node as <code>successor(node).left</code>. Since the successor(node) operation goes down left as much as possible, the successor(node) is guaranteed to have no left child. This operation is O(height).</p>
</li>
</ul>
<ul>
<li><p>subtree_delete(node)</p>
<p>  This operation deletes a node. If the node is a leaf, you just detach it from its parent. If the node is not a leaf, there are two cases: node.left(the target node has a left child) and node.right. In case of node.left, swap the node’s item with predecessor(node)’s item and subtree_delete(predecessor). In case of node.right, you do the same but with successor(node). This operation is O(height).</p>
</li>
</ul>
<p>For a sequence, make the traversal order equal to the sequence order. For a set, make the traversal order equal to ordered by increasing item key. In a Binary Search Tree, you store integer key values in order. In the example order defined above, all the keys smaller than the root will be the root’s left children and those bigger will be its right children. Thus, find(k), find_previous and find_next operations are made easy.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Linear Sorting]]></title>
            <link>https://velog.io/@sour_aguacate/Linear-Sorting</link>
            <guid>https://velog.io/@sour_aguacate/Linear-Sorting</guid>
            <pubDate>Tue, 23 May 2023 14:15:45 GMT</pubDate>
            <description><![CDATA[<p>여기에 정리할 요약 노트의 원 강의는 MIT 6.006 Introduction to Algorithms, Spring 2020이다.</p>
<h3 id="direct-access-array-sort">Direct Access Array Sort</h3>
<p>Suppose u is small and all the keys are unique. Make a direct access array(O(u)), store each key in their respective indices(n * O(1)) and walk down the array and return the keys seen in order(O(u)). The whole process will take O(n+u), which is a linear time algorithm</p>
<p>What if u gets bigger, say, u is smaller than <code>n</code> squared. Decompose each item into two smaller numbers. For example, with <code>k</code>, you can get two smaller numbers <code>a</code> and <code>b</code>, a being k/n and b being k mod n. You can retrieve the k value later because you know k=an+b. For example, when you have a set of keys that go: [17, 3, 24, 22, 12], after the decomposition, you get a tuple of [(3,2), (0,3), (4,4), (4,2), (2,2)], or, [32, 03, 44, 42, 22]</p>
<h3 id="tuple-sort">Tuple Sort</h3>
<p>When there are many factors you can base the sorting on, you first have to rearrange the factors in order of importance. In the example above, you would say <code>a</code> is more important than <code>b</code> in that a change in the value of a leads to a greater change the value of <code>k</code>. </p>
<h4 id="most-significant-first">Most significant first</h4>
<p>First sort the tuple by <code>a</code>:</p>
<p>[03 22 32 44 42]</p>
<p>Then, sort it again by <code>b</code>:</p>
<p>[22 32 42 03 44] X</p>
<h4 id="least-significant-first">Least significant first</h4>
<p>First sort the tuple by <code>b</code>:</p>
<p>[32 42 22 03 44]</p>
<p>Then, sort it again by <code>a</code>:</p>
<p>[03 22 32 42 44] O</p>
<p>As you can see, the tuple should be sorted by the least significant first. Also note that you should use stable sorting algorithm, meaning the outcome of the first sorting should remain intact unless effected by the sortings to follow. That is why the final outcome on the right is 03 22 32 42 44, not 03 22 32 44 42. You cannot use direct access array sort with the outcome because of possible duplicates(42 and 44 in this case)</p>
<h3 id="counting-sort">Counting Sort</h3>
<p>At each key K in the direct access array, we store a pointer to a chain. The chain should remain the same order in which the elements were put. Thus, the chain should be a sequence data structure</p>
<table>
<thead>
<tr>
<th>0</th>
<th>1</th>
<th>2</th>
<th>3</th>
<th>4</th>
</tr>
</thead>
<tbody><tr>
<td>03</td>
<td></td>
<td>22</td>
<td>32</td>
<td>42</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td>44</td>
</tr>
</tbody></table>
<p>To guarantee all the elements in every chain are sorted, you can combine tuple sort and counting sort, using counting sort as an auxiliary stable sorting algorithm. This also takes O(n+u) when k is equal to or less than n squared because u is n in this specific example and the maximum amount of <code>a</code> is <code>n</code>(when k=n squared). When k is increase to n cubed, you simply divide k into three digits(when you divide k with n, you will be left with n squared and this can again be divided into the combination of a and b)</p>
<h3 id="radix-sort">Radix Sort</h3>
<p>Break up integers(max size <code>u</code>) into a base-n tuple. The number of digits is log n of u. It is the same as tuple sort on digits using counting sort from least to most significant. It takes O(n + n log n U) as long as u is smaller than n to the power of c, c being any constant, making it a linear time algorithm</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Hashing]]></title>
            <link>https://velog.io/@sour_aguacate/Hashing</link>
            <guid>https://velog.io/@sour_aguacate/Hashing</guid>
            <pubDate>Tue, 23 May 2023 14:11:54 GMT</pubDate>
            <description><![CDATA[<p>여기에 정리할 요약 노트의 원 강의는 MIT 6.006 Introduction to Algorithms, Spring 2020이다.</p>
<h3 id="comparison-model">Comparison Model</h3>
<p>A comparison model or comparison tree consists of internal nodes, each of which represents comparison operation, and leaves, each of which represents the final result of the operations, or, an item selected from the n items stored in a data structure. This is essentially a binary tree in that after an operation, based on whether the result is true or false, it decides whether to branch to this next node or the other one. Thus, each model should have <strong>n + 1</strong> leaves because the model should be able to present any item off the n items and a situation where the value user is looking for doesn’t exist in the n items. The height of the tree means the number of operations that need to be done to get to the final result. The minimal height of a comparison tree is θ(log n)</p>
<p>Is there any way to make the height shorter than θ(log n)?
<br></p>
<h3 id="direct-access-arrayhash-table-in-ram">Direct Access Array/Hash Table in RAM</h3>
<p>Suppose you have an array and an item with a key whose value is 10. You just store the item at the 10th index of the array. The find and insertion time will be constant but the length of an array can get exponentially big if the values of the keys are huge. Adding to that, if items are stored non-continuously, finding the next element will take extra time.
<br></p>
<h3 id="hashing">Hashing</h3>
<p>Instead of having an array with the height as same as the size of the largest key, you cram the <strong>u</strong> amount of keys into an array whose length is <strong>m</strong> or θ(log n), n being a smaller number than u. Storing more than two items at a same index is inevitable, thus, the question regarding efficiency in searching is how to evenly distribute keys over the array. A hash function is a function which compresses the universe of keys from 0 to u-1 to that of 0 to m-1.</p>
<p>One way to handle a collision where more than two keys need to be put in the same place is open addressing, which simply put, is to store the other key in a place yet to be occupied. This is possible when m is larger than n. Another way is to have a pointer to some other data structure where you can store different keys that could have been stored at the same index. To find a key on the array, first you have to go to that index and loop up the data structure the index is pointing at. This method is called chaining and each data structure that stores keys, or, chains should be kept to a small size so that searching for a key won’t take too much time. If we add more keys to the array, meaning we grow n and a once fixed m in return, m will stop being linear in n. Then, all you need to do is to rebuild the entire hash table with a new m.</p>
<p>Division hash function, h(k) = k mod m, mingled with some other extra steps, is used by Python and other languages for hashing. To guarantee all the keys get stored in one place given that the size of the universe of keys is huge, you can also choose which hash function to use after the user picks input. Universal Hash functions are non-deterministic or not fixed hash functions that can provide a family of hash functions to choose from. This notion adds randomness to the whole process.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Sets and Sorting]]></title>
            <link>https://velog.io/@sour_aguacate/Sets-and-Sorting</link>
            <guid>https://velog.io/@sour_aguacate/Sets-and-Sorting</guid>
            <pubDate>Tue, 23 May 2023 14:09:47 GMT</pubDate>
            <description><![CDATA[<p>여기에 정리할 요약 노트의 원 강의는 MIT 6.006 Introduction to Algorithms, Spring 2020이다.</p>
<h3 id="sets">Sets</h3>
<p>A <strong>set interface</strong> is a container that stores a sequence of iterable entities. A stored item can be retrieved with its key as every item is associated with a unique key</p>
<p>It can be implemented into an unordered array but it will be very inefficient as you’ll have to iterate the whole array to find an item till you run across the item. With an sorted array, the keys of each item being sorted in this case, finding items with keys is faster but it generally takes more time to sort the keys than to build an unordered array
<br></p>
<h3 id="sorting">Sorting</h3>
<p>In goes an array of n numbers/keys and out comes a sorted array in sorting
<br></p>
<p><strong>Permutation Sort</strong></p>
<p>Enumerate all the permutations of the input array(Ω(n!)) and check which permutation is in order(O(n)). Thus, this algorithm takes at least Ω(n! x n) time</p>
<p><strong>Selection Sort</strong></p>
<p>At each step, find the biggest item in the array and swap it out with the last item in the array. Repeat till the array is ordered. The amount of time this algorithm takes is T(n) and it is the same as T(n-1) + θ(n) as each step takes O(n) and the algorithm is recursive in that you get to sort one less element than the prior step. So sorting will take O(n²) time</p>
<aside>
💡 Let’s assume T(n) = cn² (c is a constant that doesn’t depend on n)
As we think T(n) = T(n-1) + θ(n), we can rewrite it as
cn² = c(n-1)² + θ(n) = cn² - 2cn + c + θ(n)
Thus, θ(n) = 2cn -c = O(n)

</aside>

<p><strong>Merge Sort</strong></p>
<p>First, you see every element as an array of size 1, which is naturally sorted. Then, merge the array with the one right next to it and sort the elements in order. Repeat till you have one big list whose elements are in order. The merging process per each step takes θ(n) as you have to go through every element to sort them in order. The whole algorithm takes</p>
<aside>
💡 It takes θ(n) to sort an array of size 1 so: T(1) = θ(n)
T(n) = 2T(n/2) + θ(n) because two subarrays merge to become one, and each subarray is half the size of the original big list and it takes θ(n) to merge two subarrays
Let’s assume T(n) = θ(n log n)
Let’s substitute it w/ cn log n = 2c n/2 log n/2 + θ(n)
cn log n = cn(log n - log 2) + θ(n)
θ(n) = cn log 2 both are constants so it checks out

</aside>]]></description>
        </item>
        <item>
            <title><![CDATA[Data Structures and Dynamic Arrays]]></title>
            <link>https://velog.io/@sour_aguacate/Data-Structures-and-Dynamic-Arrays</link>
            <guid>https://velog.io/@sour_aguacate/Data-Structures-and-Dynamic-Arrays</guid>
            <pubDate>Tue, 23 May 2023 14:06:18 GMT</pubDate>
            <description><![CDATA[<p>여기에 정리할 요약 노트의 원 강의는 MIT 6.006 Introduction to Algorithms, Spring 2020이다.</p>
<p><strong>Interface</strong>, or API, is the specification of what you want to do, or in other words, what data you can store and <strong>data structure</strong> is the representation of how you do it. Algorithms are needed to support data structure operations. In short, interface is a problem set and algorithms are the solution to the problem</p>
<h3 id="interfaces">Interfaces</h3>
<p>A static sequence interface has a fixed number of items it can store. The solution to the static sequence interface is a static array/list. Memory is an array of w-bit words and array is a consecutive chunk of memory. Thus, to access the array[i] is to access (the address of the array in memory + i), making the array access is constant time of O(1)</p>
<aside>
💡 O(1) per get_at/ set_at/ len
O(n) per build/ iter_seq

</aside>

<p>A dynamic sequence interface’s main focus is to insert at or delete from the middle of an array. On top of that, ways to insert/delete at before the beginning and/or after the end should be devised</p>
<h3 id="data-structures">Data Structures</h3>
<p>The two main data structure approaches/tools are arrays and pointers
<br></p>
<p><strong>Linked List</strong></p>
<p>Inserting/deleting is easy as you only need to add/remove a node and change where the pointer of the node right before it points to, hence O(1) time. However, get_at/set_at(ith element) or inserting/deleting the ith element can be anywhere from θ(i) to θ(n) as you have to follow the pointers till you find the element. If you make your linked list store a tail, or a pointer to the last node, deleting the last element will also take a linear time. Whenever a change is made to the linked list, the tail should also be updated</p>
<p><strong>Static Array</strong></p>
<p>Inserting/deleting can’t be achieved by shifting all the elements that will come after the newly inserted/deleted element as the size of a static array is fixed. This is because when a static array is created, it is allocated a certain size of array in memory and by adding an element and thus increasing the size of the array, it can touch other neighboring arrays in memory that it shouldn’t have met. Thus, the only way to achieve this is to create a new array of size n + 1 and copy the elements from the original array into the new array and this will take a linear time</p>
<p><strong>Dynamic Array</strong> (Python lists)</p>
<p>It has the size of roughly n, meaning it is θ(n) and is bigger or equal to n, which means it can be n, 2n, 10n, etc. As its size is not strictly n, there will be items to store a sequence and also, some blank ones in the end. The array will keep track of the length to tell where the blank ones start and the size of the array, occupied and blank ones put together. Thus, insert_last(x) takes a linear time and is possible unless n (interface size) = size (representation size). When n = size, you have to allocate a new bigger array and copy the elements into it just like with static arrays but much less often</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Algorithms and Computation]]></title>
            <link>https://velog.io/@sour_aguacate/Algorithms-and-Computation</link>
            <guid>https://velog.io/@sour_aguacate/Algorithms-and-Computation</guid>
            <pubDate>Tue, 23 May 2023 14:03:25 GMT</pubDate>
            <description><![CDATA[<p>유튜브의 MIT OpenCourseWare 채널에는 MIT의 다양한 학과 강의가 있다. 여기에 정리할 요약 노트의 원 강의는 MIT 6.006 Introduction to Algorithms, Spring 2020로, 교수님들이 알고리즘/데이터 구조를 자세히 설명해주시고 각각의 효율성을 수학으로 증명해주시는데 증명 과정을 차근히 보여주셔서 문과인 나도 느리지만 조금씩 이해할 수 있는 정도이다. 다만 과제로 내주시는 예제들 역시 수학적 증명이라 과제는 건너뛰고, 수업에서도 내가 이해할 수 있는 부분만 취하고자 한다.</p>
<h3 id="algorithms">Algorithms</h3>
<p>An algorithm is a fixed size solution or a function to general problems with arbitrarily sized inputs. The goal of learning algorithms is to solve computational problems in a correct and effective way. The efficiency units that signify the performance of an algorithm  are O(upper bound), Ω(lower bound) and θ(when upper and lower bounds are the same)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Transport Layer]]></title>
            <link>https://velog.io/@sour_aguacate/Transport-Layer</link>
            <guid>https://velog.io/@sour_aguacate/Transport-Layer</guid>
            <pubDate>Tue, 23 May 2023 13:44:37 GMT</pubDate>
            <description><![CDATA[<p>해당 글은 Jim Kurose 교수님의 Computer Networks 강의를 듣고 요약한 내용이다</p>
<h3 id="overview">Overview</h3>
<p>3-1 Transport Layer</p>
<ul>
<li>definitions<ul>
<li>transport layer: logical communication b/ processes</li>
<li>network layer: logical communication b/ hosts(can have many diff processes)</li>
</ul>
</li>
<li>process<ol>
<li>application layer passes a message through socket</li>
<li>transport layer determines segment header fields values and creates segment</li>
<li>transport layer passes down the segment to the network layer, to the IP protocol</li>
<li>network layer sends the segment to the receiving host</li>
<li>receiving host checks the header values, extracts application layer message and demultiplexes messages up to application via socket</li>
</ol>
</li>
<li>two principal internet transport protocols<ul>
<li>TCP</li>
<li>UDP(connectionless)</li>
</ul>
</li>
</ul>
<h3 id="transport-layer-multiplexing-and-demultiplexing">Transport Layer Multiplexing and Demultiplexing</h3>
<p>3-2 Transport Layer Multiplexing and Demultiplexing</p>
<ul>
<li>demultiplexing<ul>
<li>process by which the payloads of a datagram(received from the sender host) are directed to the designated applications</li>
<li>host uses IP addresses and port numbers specified in the transport layer segment of the datagram it received to direct segment to appropriate socket</li>
<li>all the UDP datagrams with same destination port # will be directed to the same socket</li>
<li>TCP socket is identified by both source and destination IP address and port number whereas UDP socket only requires those of destination. This means each TCP socket will be associated with a different connecting client as they all have different source IP addresses</li>
</ul>
</li>
<li>multiplexing<ul>
<li>many applications sending down messages through respective sockets to TCP and it is TCP’s job to funnel down the messages to the IP protocol</li>
</ul>
</li>
</ul>
<h3 id="connectionless-transport---udp">Connectionless Transport - UDP</h3>
<p>3-3 Connectionless Transport UDP</p>
<ul>
<li>features<ul>
<li>User Datagram Protocol, or UDP for short, provides “best effort” service, thus segments can be lost or delivered out of order</li>
<li>UDP is connectionless, meaning sender and receiver does not share handshakes or states. Since there is no connection, there is no connection establishment</li>
<li>As UDP provides relatively simple service, the header size is also relatively small</li>
<li>UDP provides no congestion control so it can function on a congested network, unlike TCP</li>
<li>All of the characteristics above make UDP suitable for applications such as streaming services, DNS, SNMP and so on</li>
</ul>
</li>
<li>UDP segment header<ul>
<li>Header includes source port #, destination port #, length of the payload(application data) and checksum field</li>
<li>Pseudo header containing source and destination addresses is prefixed to the UDP header</li>
</ul>
</li>
<li>checksum<ul>
<li>Its goal is to detect errors in transmitted segment</li>
<li>Sender turns the contents of UDP segment(including header fields and IP addresses) into a sequence of 16-bit integers. Add all the integers and the complement sum of the addition is the checksum value</li>
<li>Receiver compute the checksum of the received segment to see if it matches the checksum field</li>
<li>Checksum is not foolproof however, as the two values turning out to be equal does not necessarily mean the received segment has not been corrupted</li>
<li>HTTP3 sets security measures in application layer on top of UDP to supplement UDP’s weak protection</li>
</ul>
</li>
</ul>
<h3 id="principles-of-reliable-data-transfer">Principles of Reliable Data Transfer</h3>
<p>3-4 Principles of Reliable Data Transfer Part1</p>
<ul>
<li>abstraction and implementation<ul>
<li>While the process of sending data from one point to another is abstracted away as a uni-directional, reliable service, it really is a bi-directional message changing(NOT data transfer) process through reliable data transfer protocol, then over an unreliable channel in the network layer</li>
<li>Complexity of reliable data transfer protocol will rely on the characteristics of unreliable channel</li>
<li>Sender and receiver do not know the state of each other or what’s happening at the channel unless they are communicating via messages</li>
</ul>
</li>
<li>Reliable Data Transfer Protocol<ul>
<li>Finite State Machines are used to specify the state of sender and receiver</li>
<li>If the underlying channel is perfectly reliable, the FSMs on each end only need to send/read data from the channel. For example, on the sending side, rdt will send data to the transport layer. The transport layer’s actions then, are to turn data into a series of packets and send them through the underlying channel</li>
<li>If the underlying channel has impairments, rdt2.0 is used to recover from errors. Rdt 2.0 uses acknowledgements(ACKs) or negative acknowledgements(NAKs) whereby receiver explicitly tells sender that a packet is received okay or not. Sender retransmits the packet on receipt of NAK. Acknowledgement happens after every one packet</li>
</ul>
</li>
<li>Rdt 2.0<ul>
<li>Sender goes from one state to another: waiting for call from above for another rdt send, to waiting for ACK/NAK. If it gets an ACK, it falls back to the initial state whereas a NAK response will call for a retransmit of the packet till it gets an ACK back</li>
<li>Receiver will be waiting for the arrival of the packet and send out an ACK or NAK accordingly. If the data is found out to be not corrupt, it gets extracted and delivered up to the application layer and then the receiver sends an ACK back to the sender</li>
<li>ACK/NAK can be corrupted during communication. In such a case, sender will retransmit the current packet and add a sequence # to each packet so that the receiver can detect and discard duplicate packets</li>
</ul>
</li>
<li>Rdt 2.1<ul>
<li>Sender is in one of the four possible states: the two of which are the same as those of rdt 2.0 but with the sequence # of 0; and the remaining two, with the sequence # of 1. The initial state is waiting for call 0 from above and on receiving an ACK, it transitions to waiting for call 1 from above. Upon receiving an ACK, it goes back to the initial state and the cycle repeats</li>
<li>Receiver has two possible states: waiting for 0 from below and waiting for 1 from below. When it receives a packet of 0 in the state of waiting for 1, it will still send an ACK since when it transitions to the other state, it will receive a packet of 1 anyways</li>
<li>TCP uses only ACK along with checksum</li>
</ul>
</li>
</ul>
<br>
3-4 Principles of Reliable Data Transfer Part2

<ul>
<li><p>Rdt 3.0</p>
<ul>
<li>The underlying channel can both get corrupt or lose packets</li>
<li>Sender starts timer and waits some amount of time for ACK and retransmits the packet if it did not receive an ACK(timeout). When it receives a response, the timer stops. Corrupt packets are treated the same as lost packets that will be recovered by a later timeout retransmit. ACK with a wrong sequence number or any ACK received while waiting for call from above is ignored. When an ACK is lost or delayed, the sender will resend the packet again at timeout</li>
</ul>
</li>
<li><p>Pipeline Protocols</p>
<ul>
<li><p>Stop-and-wait behavior of the protocol limits the performance of underlying channel. A more efficient alternative is pipelined protocol. Sender sends multiple yet-to-be-acknowledged packets. The range of sequence number should be increase in this case</p>
</li>
<li><p>In Go-Back-N protocol, sender can transmit N amounts of unacknowledged packets in a row. Sender has a window of size up to N that shows the state(whether it’s been sent/ack’ed). When a timeout occurs, sender retransmit the current packet and all the packes with higher sequence # in the window. Upon receiving a packet, Receiver sends an ack for the correctly received packet so far with the highest in-order sequence #</p>
<p>  <img src="https://velog.velcdn.com/images/sour_aguacate/post/295ad9f1-cdb3-4746-b855-857a06b84822/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>- In Selective Repeat protocol, receiver can individually acknowledge all correctly received packets and it can buffer an out-of-order packet  and later deliver it to the above. Sender maintains timer for each unACKed packet

    ![](https://velog.velcdn.com/images/sour_aguacate/post/16651afc-868c-443e-8e7f-4e6f7dafb953/image.png)</code></pre><h3 id="tcp-reliability-flow-control-and-connection-management">TCP Reliability, Flow Control and Connection Management</h3>
<p>3-5 TCP Reliability, Flow Control and Connection Management part1</p>
<ul>
<li><p>TCP segment structure</p>
<ul>
<li><p>Sequence #s in the header is the byte stream # of the first byte in segment’s data</p>
</li>
<li><p>ACKs are sequence # of next byte expected from the sender. It’s cumulative in that the number shows all the byte stream before that # has been received. This means even though the receiver gets a segment and has ACK pending, it will send only one cumulative ACK</p>
<p>  <img src="https://velog.velcdn.com/images/sour_aguacate/post/c46c8baf-c927-4f81-9fd7-873f6d7ba9e3/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<ul>
<li>TCP round trip time, timeout<ul>
<li>Timeout interval will be the average value of recent measured times from segment transmission until ACK receipt + safety margin</li>
<li>usually implemented so that timer checks for the oldest unACKed segment</li>
</ul>
</li>
<li>TCP fast retransmit<ul>
<li>If sender receives 3 ACKS for same data, it will resend unACKed segment with the smallest sequence # in the current payload instead of waiting for timeout</li>
</ul>
</li>
</ul>
<p>3-5 TCP Reliability, Flow Control and Connection Management part2</p>
<ul>
<li><p>TCP flow control</p>
<ul>
<li><p>How the transport layer receives a segment is first, when the segment is brought up to the transport layer the payload is removed from the segment and is written into the socket buffers. Then an application program will perform a socket read and that’s when the data is removed from the socket buffers. Flow control allows the receiver to control the sender so that the sender won’t overflow the receiver’s buffer by transmitting too much, too fast</p>
<p>  <img src="https://velog.velcdn.com/images/sour_aguacate/post/abfeffc9-e93a-4fa4-ba93-050f3760d0cc/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<pre><code>- Receiver will notify the sender how much free space there is in the buffers so that the sender will know the limit of the amount of data it can send. It is specified in `rwnd` field in TCP header</code></pre><ul>
<li>TCP Connection Management<ul>
<li>TCP is connection oriented in that the sender and the receiver have a lot of shared state and they need to build them before establishing a connection</li>
<li>A handshake is done by the client reaching out the server(request) and the server answering back(accept) to establish a connection. This 2-way handshake doesn’t always work in network settings because of variable delays, message loss and other issues</li>
<li>TCP uses 3-way handshake. Both the client and server create a TCP socket and enter the LISTEN state. Then, the client connects to the server by sending a SYN message and a sequence number. Upon receiving it, the server enters the SYN RECEIVED state(not yet established). The server sends a SYN and ACK message back and the client finally sends an ACK message to the server. When the server receives the ACK, it enters the ESTABLISH state and that’s when the connection is established</li>
</ul>
</li>
<li>One side sends a FIN message, the other side sends a FIN and ACK message, after which it times out and closes</li>
</ul>
<h3 id="principles-of-congestion-control">Principles of Congestion Control</h3>
<ul>
<li>A congestions is when too many sources sending too much data too fast for network to handle. Long delays and packet loss can happen during congestion. It differs from flow control, which is about one sender sending data too fast for one receiver</li>
<li>End-end congestion control mainly and network layer assisted congestion control tactics are used by TCP for congestion control</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Application Layer]]></title>
            <link>https://velog.io/@sour_aguacate/Application-Layer</link>
            <guid>https://velog.io/@sour_aguacate/Application-Layer</guid>
            <pubDate>Tue, 23 May 2023 13:38:10 GMT</pubDate>
            <description><![CDATA[<p>해당 글은 Jim Kurose 교수님의 Computer Networks 강의를 듣고 요약한 내용이다. 세계적인 석학이 직접 유튜브에 강의를 촬영해서 올려주시는데 안들을 수가 없는 법. 다만 심화 이론도 곳곳에서 다루셔서 내가 이해할 수 있고 필요한 부분만 취사선택하였다. 한편, 강의가 영어로 진행되는만큼 요약 노트도 영어로 작성하였다</p>
<h3 id="http">HTTP</h3>
<ul>
<li>client(request)-server(response)<ul>
<li>Client initiates TCP connection, or, creates a socket to server on port 80</li>
<li>Server accepts TCP connection from the client</li>
<li>HTTP messages are exchanged between browser and server(HTTP connection); in the process, at most one object is sent over TCP connection</li>
</ul>
</li>
<li>statelessness, meaning the server does not store the state of the client; so a transaction at hand theoretically does not have info on the prior transactions</li>
<li>web cache to reduce load on server and reduce response time</li>
<li>conditional GET to reduce load on server and reduce response time</li>
<li>cookies to store the state of the client, or the user info</li>
</ul>
<p>이후 내용은 추가할 예정</p>
]]></description>
        </item>
    </channel>
</rss>