<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>BOBO's Note</title>
    <link>https://bobo-dev.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 21 Jul 2026 07:01:13 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>bobo_hee</managingEditor>
    <image>
      <title>BOBO's Note</title>
      <url>https://tistory1.daumcdn.net/tistory/3926734/attach/cfe95ddaebe64e21b7fbb6824fe8724f</url>
      <link>https://bobo-dev.tistory.com</link>
    </image>
    <item>
      <title>크롤링 (Crawling)</title>
      <link>https://bobo-dev.tistory.com/117</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;크롤링(Crawling)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;크롤링이란, 웹상에 존재하는 컨텐츠를 프로그래밍으로수집하는 작업이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Scrapy&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Scrapy는 Python 기반의 오픈소스 웹크롤링 프레임워크이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Scrapy의 구성요소는 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Engine: 모든 구성요소간 데이터 흐름 관리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Scheduler: 엔진으로부터 request를 받아 큐에 저장하고 이후 엔진에 다시 반환&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Downloader: 웹 페이지 fetch해서 엔진을 거쳐 스파이더에 반환&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Spider: response를 파싱해서 아이템을 추출&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Item Pipeline: 스파이더에 의해 추출된 아이템 처리&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;859&quot; width=&quot;525&quot; height=&quot;352&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CCGXO/btrcok1VaBi/2DlDuXqbVUW7eAmhm4mDyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CCGXO/btrcok1VaBi/2DlDuXqbVUW7eAmhm4mDyK/img.png&quot; data-alt=&quot;Scrapy Data Flow&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CCGXO/btrcok1VaBi/2DlDuXqbVUW7eAmhm4mDyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCCGXO%2Fbtrcok1VaBi%2F2DlDuXqbVUW7eAmhm4mDyK%2Fimg.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;859&quot; width=&quot;525&quot; height=&quot;352&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Scrapy Data Flow&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. 스파이더로부터 엔진이 request를 받는다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. 엔진은 스케쥴러에 request를 등록하고 다음 request를 요청한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. 스케쥴러는 엔진에게 request를 반환한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;4. 엔진은 다운로더에 request를 보낸다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;5. 페이지가 다운로드되면 다운로더는 response를 생성해 엔진에 전송한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;6. 엔진은 다운로더로부터 response를 받고, 그것을 스파이더에 전송한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;7. 스파이더는 response를 처리하고 엔진에 스크랩된 아이템과 새 request를 반환한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;8. 엔진은 처리된 아이템을 아이템 파이프라인에 전송하고, 처리된 request는 스케쥴러에 보내 다음 request를 요청한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;8. 스케쥴러로부터 더이상 request가 없을 때까지 위의 과정을 반복한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;출처: &lt;a href=&quot;https://docs.scrapy.org/en/latest/topics/architecture.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.scrapy.org/en/latest/topics/architecture.html&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1629267835470&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Architecture overview &amp;mdash; Scrapy 2.5.0 documentation&quot; data-og-description=&quot;&amp;copy; Copyright 2008&amp;ndash;2021, Scrapy developers. Revision 5fd75f86. Last updated on Apr 07, 2021.&quot; data-og-host=&quot;docs.scrapy.org&quot; data-og-source-url=&quot;https://docs.scrapy.org/en/latest/topics/architecture.html&quot; data-og-url=&quot;https://docs.scrapy.org/en/latest/topics/architecture.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.scrapy.org/en/latest/topics/architecture.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.scrapy.org/en/latest/topics/architecture.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Architecture overview &amp;mdash; Scrapy 2.5.0 documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;copy; Copyright 2008&amp;ndash;2021, Scrapy developers. Revision 5fd75f86. Last updated on Apr 07, 2021.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.scrapy.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Scrapy Tutorial 따라하기&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개발환경: Pycharm2021.2 / Python3.9 / Scrapy&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;[STEP 1] test.py에서 개발환경 초기화&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1629268039528&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import scrapy
from scrapy import cmdline

# init
cmdline.execute('scrapy startproject tutorial'.split())&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위 코드를 실행하면 tutorial이라는 디렉토리가 생성되어 scrapy 프로젝트 개발환경이 생성된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;222&quot; data-origin-height=&quot;184&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgSsle/btrczqstRz8/gDM5gFIwbjYp8A2qwvLTGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgSsle/btrczqstRz8/gDM5gFIwbjYp8A2qwvLTGK/img.png&quot; data-alt=&quot;tutorial 디렉토리&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgSsle/btrczqstRz8/gDM5gFIwbjYp8A2qwvLTGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdgSsle%2FbtrczqstRz8%2FgDM5gFIwbjYp8A2qwvLTGK%2Fimg.png&quot; data-origin-width=&quot;222&quot; data-origin-height=&quot;184&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;tutorial 디렉토리&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;[STEP 2] Spider 코드 작성&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Spider는 scrapy가 웹사이트에서 데이터를 스크랩하기 위해 사용하는 클래스이다. 초기 request를 정의하고 페이지 내에서 링크를 어떻게 타고갈지, 데이터 추출을 위해 어떻게 파싱할지 등을 정의해줄 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;tutorial/tutorial/spiders/ 디렉토리 아래에 다음과 같이 quotes_spider.py 파일을 작성한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630052745547&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import scrapy

class QuoteSpider(scrapy.Spider):
    name = &quot;quotes&quot;

    def start_requests(self):
        urls = ['http://quotes.toscrape.com/page/1/',
                'http://quotes.toscrape.com/page/2/']

        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        page = response.url.split(&quot;/&quot;)[-2]
        filename = f'quotes-{page}.html'
        with open(filename, 'wb') as f:
            f.write(response.body)
        self.log(f'Saved file {filename}')&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;name: 스파이더의 이름. 프로젝트 내에서 고유해야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;start_requests(): 스파이더가 열릴 때 맨 처음 한번만 호출되는 메소드. 스파이더가 동작할 일련의 request를 반환해야 한다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;parse(): request에 콜백함수를 지정하지 않았을 때 기본으로 호출되는 콜백. Scrapy가 다운로드된 response를 처리할 때 사용된다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;start_requests()를 직접 구현하여 request를 만드는 대신, start_urls 변수에 url을 지정해줄 수도 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630053892129&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import scrapy

class QuoteSpider(scrapy.Spider):
    name = &quot;quotes&quot;

    start_urls = ['http://quotes.toscrape.com/page/1/',
                  'http://quotes.toscrape.com/page/2/']

    def parse(self, response):
        page = response.url.split(&quot;/&quot;)[-2]
        filename = f'quotes-{page}.html'
        with open(filename, 'wb') as f:
            f.write(response.body)
        self.log(f'Saved file {filename}')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;start_requests()의 default 구현에 의해 start_urls에 지정된 url로 request를 만들게 되고, 이 request들을 default 콜백인 parse() 메소드를 호출해 처리하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;[STEP 3] Spider 실행&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;scrapy 프로젝트의 최상위 디렉토리(이 경우 tutorial/)에서 다음 커맨드를 실행한다. quotes라는 이름의 스파이더를 실행시키는 커맨드이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630053322297&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;scrapy crawl quotes&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위 커맨드를 실행하면 quotes-1.html, quotes-2.html 파일이 생성된다. 지정한 url 페이지의 내용이 그대로 저장되어 있다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>etc</category>
      <author>bobo_hee</author>
      <guid isPermaLink="true">https://bobo-dev.tistory.com/117</guid>
      <comments>https://bobo-dev.tistory.com/117#entry117comment</comments>
      <pubDate>Wed, 18 Aug 2021 13:53:02 +0900</pubDate>
    </item>
    <item>
      <title>[ Baekjoon ] 1103. 게임</title>
      <link>https://bobo-dev.tistory.com/86</link>
      <description>&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1103&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.acmicpc.net/problem/1103&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1599712224303&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;1103번: 게임&quot; data-og-description=&quot;줄에 보드의 세로 크기 N과 가로 크기 M이 주어진다. 이 값은 모두 50보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에 보드의 상태가 주어진다. 쓰여 있는 숫자는 1부터 9까지의 자연수 또는 &quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/1103&quot; data-og-url=&quot;https://www.acmicpc.net/problem/1103&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/yqKAa/hyHoVozxTX/6ATVkSzqPybAs7OOjInZck/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1103&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/1103&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/yqKAa/hyHoVozxTX/6ATVkSzqPybAs7OOjInZck/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;1103번: 게임&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;줄에 보드의 세로 크기 N과 가로 크기 M이 주어진다. 이 값은 모두 50보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에 보드의 상태가 주어진다. 쓰여 있는 숫자는 1부터 9까지의 자연수 또는&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;풀이 방법&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;임의의 칸에서 움직일 수 있는 모든 칸에 대해서 DFS 방식으로 확인해보면 된다. 이때, 시간 초과가 발생할 수 있으므로 DP를 이용한다. &lt;span style=&quot;color: #333333;&quot;&gt;memo[i][j]에 board[i][j]에서 시작할 때 최대 움직일 수 있는 횟수를 저장하면, 똑같은 위치를 재방문할 때 곧바로 결과값을 알아낼 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우선 dfs() 함수에서는 현재 위치 cur에서 시작할 때, 최대 움직일 수 있는 횟수를 반환한다고 하자. 만약 현재 위치가 보드의 바깥이거나 구멍이라면 더이상 움직일 수 없으므로 0을 반환한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1599712814243&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if (!valid(cur)) return 0;
if (board[cur.r][cur.c] == 'H') return 0;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그리고 아직 방문한 적이 없다면 다음 위치 next를 계산한다. 만약 next가 이미 방문한 적 있는 위치라면 cycle이 생겼다는 의미이다. 따라서 이 경우에는 -1을 출력하고 프로그램을 종료한다. 그렇지 않다면 memo 원소를 업데이트한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1599712966942&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const static int dr[4] = { -1, 1, 0, 0 };
const static int dc[4] = { 0, 0, -1, 1 };

if (memo[cur.r][cur.c] &amp;lt;= 0) {
	visit[cur.r][cur.c] = true;
	for (int i = 0; i &amp;lt; 4; i++) {
		int next_r = cur.r + (board[cur.r][cur.c] - '0') * dr[i];
		int next_c = cur.c + (board[cur.r][cur.c] - '0') * dc[i];
		Pos next = Pos(next_r, next_c);
		if (valid(next) &amp;amp;&amp;amp; visit[next_r][next_c]) {
			printf(&quot;-1&quot;);
			exit(0);
		}
		memo[cur.r][cur.c] = max(memo[cur.r][cur.c], dfs(next) + 1);
	}
	visit[cur.r][cur.c] = false;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전체 코드는 &lt;a href=&quot;https://github.com/leebohee/problem-solving/blob/master/baekjoon/1103.cpp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;여기&lt;/a&gt;서 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Algorithm/Problem Solving</category>
      <author>bobo_hee</author>
      <guid isPermaLink="true">https://bobo-dev.tistory.com/86</guid>
      <comments>https://bobo-dev.tistory.com/86#entry86comment</comments>
      <pubDate>Thu, 10 Sep 2020 13:43:11 +0900</pubDate>
    </item>
    <item>
      <title>Segment Tree와 Indexed Tree</title>
      <link>https://bobo-dev.tistory.com/83</link>
      <description>&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;세그먼트 트리&lt;/b&gt;는 어떠한 배열이 주어졌을 때, &lt;b&gt;각 구간의 대표값&lt;/b&gt;(예. 합, 최대값 등)을 빠르게 구할 수 있는 자료구조이다. 배열의 크기가 N일 때, 임의의 구간에 대한 쿼리를 &lt;b&gt;O(logN)&lt;/b&gt;에 수행할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;인덱스 트리&lt;/b&gt;는 팬윅 트리(Fenwick Tree)라고도 하며, 세그먼트 트리처럼 각 구간의 대표값을 빠르게 구할 수 있다. 세그먼트 트리보다 구현하기 더 간단하고 속도가 빠르다는 장점이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 포스터에서는 &lt;b&gt;구간합&lt;/b&gt;을 세그먼트 트리를 이용해 빠르게 구하는 방법에 대해 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;구간합 구하기&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;배열 arr[0], arr[1], ..., arr[N-1]이 있다고 할 때, 임의의 구간 [l, r]에 대하여 구간합 arr[l] + arr[l+1] + ... + arr[r-1] + arr[r]을 구해라.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위 문제를 해결하는 가장 간단한 방법은 매번 배열을 순회하는 방법으로, 쿼리를 수행할 때마다 O(N)의 시간이 소요된다. 따라서 k번의 쿼리를 수행한다면 전체 시간복잡도는 &lt;b&gt;O(kN)&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1597557482539&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for(int i=l; i&amp;lt;=r; i++){
	sum += arr[i];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;쿼리가 많아질수록 시간복잡도는 증가하게 되는데, 이를 개선하는 방법을 생각해보자. arr[0]~arr[i]까지의 누적합을 i번째 원소에 저장하는 배열 acc_sum을 하나 선언하자. acc_sum을 초기화하는 데에 O(N)이 걸리지만, 이후 구간 [l, r]의 누적합은 acc_sum[r]-arr[l-1]로 O(1)의 시간에 알아낼 수 있다. 따라서 k번의 쿼리를 수행한다면 전체 시간복잡도는 &lt;b&gt;O(k)&lt;/b&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1597557816738&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int acc_sum[N];

// Initialize acc_sum =&amp;gt; O(N)
acc_sum[0] = arr[0];
for(int i=1; i&amp;lt;N; i++){
	acc_sum[i] = acc_sum[i-1] + arr[i];
}

// query: segment sum of [l, r] =&amp;gt; O(1)
int sum = acc_sum[r] - acc_sum[l-1];&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그러나 이 방법은 주어진 배열의 원소 값에 변경이 생긴다면 acc_sum을 다시 구해야 하므로 &lt;b&gt;O(N)&lt;/b&gt;의 시간이 발생하고, 이는 성능저하의 요인이 될 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;세그먼트 트리를 이용하면 (1) &lt;u&gt;쿼리 수행&lt;/u&gt; 및 (2) &lt;u&gt;배열의 원소 값 변경&lt;/u&gt; 모두 &lt;b&gt;O(logN)&lt;/b&gt;의 시간에 수행할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Segment Tree&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;세그먼트 트리는 기본적으로 포화 이진트리 형태이다. 주어진 배열의 원소들은 세그먼트 트리의 leaf 노드에 차례대로 저장된다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;815&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PUFHw/btqGIJDvhPc/CDMh30JPXsVftAjmdkQgk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PUFHw/btqGIJDvhPc/CDMh30JPXsVftAjmdkQgk1/img.png&quot; data-alt=&quot;Segment Tree - Leaf Node&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PUFHw/btqGIJDvhPc/CDMh30JPXsVftAjmdkQgk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPUFHw%2FbtqGIJDvhPc%2FCDMh30JPXsVftAjmdkQgk1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;815&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Segment Tree - Leaf Node&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그리고 내부 노드들은 자식 노드들의 대표값(이 글에서는 구간합)을 저장한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;823&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhc2TE/btqGJHk82Nj/AG8VO8ZfkA4KOZ2aad2jF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhc2TE/btqGJHk82Nj/AG8VO8ZfkA4KOZ2aad2jF1/img.png&quot; data-alt=&quot;Segment Tree - Internal Node&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhc2TE/btqGJHk82Nj/AG8VO8ZfkA4KOZ2aad2jF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbhc2TE%2FbtqGJHk82Nj%2FAG8VO8ZfkA4KOZ2aad2jF1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;823&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Segment Tree - Internal Node&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;세그먼트 트리 초기화를 마친 후, 구간합에 대한 쿼리를 수행한다. 루트 노드부터 시작해 원하는 구간에 대하여 쿼리를 내려보내고, 이를 종합하여 쿼리의 결과를 계산한다. 각 노드는 자신이 담당하는 구간이 쿼리의 구간에 완전히 속하면 노드 값을 반환하고, 그렇지 않으면 자식 노드들에게 쿼리를 포워드한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이때, 쿼리의 구간에 완전히 속한다는 것은 다음과 같은 경우이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;711&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/exbc9k/btqGGHs87ZY/O0aoEl3HhG6z4pQ9p3Tj30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/exbc9k/btqGGHs87ZY/O0aoEl3HhG6z4pQ9p3Tj30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/exbc9k/btqGGHs87ZY/O0aoEl3HhG6z4pQ9p3Tj30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fexbc9k%2FbtqGGHs87ZY%2FO0aoEl3HhG6z4pQ9p3Tj30%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;711&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예를 들어 구간 [3, 7]의 구간합을 구하는 쿼리는 다음과 같이 수행된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1. 루트 노드부터 구간을 검사한다. 노드의 구간이 쿼리 구간에 완전히 속하는 게 아니므로 자식 노드에게 쿼리를 포워드한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GEe9l/btqGK4NXIu7/bDZFmfhWWmYtCgTaFZwGk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GEe9l/btqGK4NXIu7/bDZFmfhWWmYtCgTaFZwGk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GEe9l/btqGK4NXIu7/bDZFmfhWWmYtCgTaFZwGk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGEe9l%2FbtqGK4NXIu7%2FbDZFmfhWWmYtCgTaFZwGk1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2. depth=1인 자식 노드들도 자신의 구간이 쿼리 구간에 완전히 속하는 게 아니므로 자식 노드에게 쿼리를 포워드한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djZGoV/btqGIKbn0YJ/kZSsuZowZ3CCVZmdW33Jn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djZGoV/btqGIKbn0YJ/kZSsuZowZ3CCVZmdW33Jn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djZGoV/btqGIKbn0YJ/kZSsuZowZ3CCVZmdW33Jn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjZGoV%2FbtqGIKbn0YJ%2FkZSsuZowZ3CCVZmdW33Jn0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;3. depth=2인 자식노드들 중, 쿼리 구간과 겹치는 구간이 없으면 0을 바로 리턴한다. 만약 쿼리 구간에 완전히 속하면 자신의 값을 리턴한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKoFmG/btqGDPFbdpq/tKTKPhvuGFDR1Y4pn5bvnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKoFmG/btqGDPFbdpq/tKTKPhvuGFDR1Y4pn5bvnk/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 49.3195%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKoFmG/btqGDPFbdpq/tKTKPhvuGFDR1Y4pn5bvnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKoFmG%2FbtqGDPFbdpq%2FtKTKPhvuGFDR1Y4pn5bvnk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgJ3fd/btqGHp6C4MP/pTBzkHyFmSxWYrI5VPFUZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgJ3fd/btqGHp6C4MP/pTBzkHyFmSxWYrI5VPFUZ0/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 49.5177%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgJ3fd/btqGHp6C4MP/pTBzkHyFmSxWYrI5VPFUZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgJ3fd%2FbtqGHp6C4MP%2FpTBzkHyFmSxWYrI5VPFUZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;4. depth=4인 노드들도 마찬가지로 완전히 속하면 자신의 값을 리턴한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mXI5K/btqGG1yc2qe/MD1kSaBmVUC88fmtKHqsj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mXI5K/btqGG1yc2qe/MD1kSaBmVUC88fmtKHqsj0/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mXI5K/btqGG1yc2qe/MD1kSaBmVUC88fmtKHqsj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmXI5K%2FbtqGG1yc2qe%2FMD1kSaBmVUC88fmtKHqsj0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XqVhw/btqGJuF8tlr/W3xcVlZfjvkQH8yfbJ6G2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XqVhw/btqGJuF8tlr/W3xcVlZfjvkQH8yfbJ6G2K/img.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XqVhw/btqGJuF8tlr/W3xcVlZfjvkQH8yfbJ6G2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXqVhw%2FbtqGJuF8tlr%2FW3xcVlZfjvkQH8yfbJ6G2K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;0&quot; height=&quot;0&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Implementation&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;세그먼트 트리를 Java로 구현해보자.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우선 SegmentTree라는 클래스를 선언하고, 주어지는 배열을 저장하는 nums 배열과 세그먼트 트리를 배열 형태로 저장한 배열 tree를 멤버변수로 갖는다. 그리고 세그먼트 트리의 깊이 depth와 leaf 노드의 개수 leafSize도 멤버변수로 갖는다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1597566260628&quot; class=&quot;java&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class SegmentTree {
	int[] nums;
	int[] tree;
	int depth;
	int leafSize;

	/* to-be-continue */
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;주어진 배열로 세그먼트 트리를 초기화하는 코드는 다음과 같다. leaf 노드라면 배열 원소 값을 저장하고 반환한다. 내부 노드라면 자식 노드에 대하여 makeTree()를 재귀적으로 호출하고, 이를 합하여 노드에 저장 후 반환한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1597566315285&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;makeTree(1, 1, nums.length);

// nodeIndex: 세그먼트 트리에서 해당 노드의 인덱스
// left: 세그먼트 트리에서 해당 노드의 구간 시작 값
// right: 세그먼트 트리에서 해당 노드의 구간 끝 값
int makeTree(int nodeIndex, int left, int right) {
	if (left == right) { // leaf node
		if (left &amp;lt;= nums.length) tree[nodeIndex] = nums[left - 1];
		else tree[nodeIndex] = 0;
		return tree[nodeIndex];
	} else { // internal node
		int mid = left + (right - left) / 2;
		tree[nodeIndex] = makeTree(nodeIndex * 2, left, mid);
		tree[nodeIndex] += makeTree(nodeIndex * 2 + 1, mid + 1, right);
		return tree[nodeIndex];
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;임의의 구간에 대한 구간합을 반환하는 함수 query()도 위와 비슷한 방식으로 작동한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1597566537373&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;query(1, 1, nums.length, 3, 7); // 구간 [3, 7]의 합

// nodeIndex: 세그먼트 트리에서 해당 노드의 인덱스
// left: 세그먼트 트리에서 해당 노드의 구간 시작 값
// right: 세그먼트 트리에서 해당 노드의 구간 끝 값
// qLeft: 질의하는 구간의 시작 값
// qRight: 질의하는 구간의 끝 값
int query(int nodeIndex, int left, int right, int qLeft, int qRight) {
	if (qLeft &amp;lt;= left &amp;amp;&amp;amp; right &amp;lt;= qRight) return tree[nodeIndex]; // 완전히 속함
	else if (qRight &amp;lt; left || right &amp;lt; qLeft) return 0; // 겹치는 구간이 없음
	else { // 자식 노드에게 쿼리를 포워드
		int mid = left + (right - left) / 2;
		return query(nodeIndex * 2, left, mid, qLeft, qRight)
				+ query(nodeIndex * 2 + 1, mid + 1, right, qLeft, qRight);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;배열의 특정 위치의 값을 변경하고 싶으면, 세그먼트 트리의 루트 노드부터 해당 leaf 노드까지 함께 업데이트 해주어야 한다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1597566810556&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int targetIndex = 2;
int targetValue = 5;
int diff = targetValue - nums[targetIndex];
nums[targetIndex] = targetValue;
st.update(1, 1, nums.length, targetIndex + 1, diff);

// nodeIndex: 세그먼트 트리에서 해당 노드의 인덱스
// left: 세그먼트 트리에서 해당 노드의 구간 시작 값
// right: 세그먼트 트리에서 해당 노드의 구간 끝 값
// index: 배열에서 변경하려는 원소의 인덱스
// diff: 변경하려는 값과 배열에서 원소의 값 사이의 차이
void update(int nodeIndex, int left, int right, int index, int diff) {
	if(nodeIndex &amp;gt;= tree.length) return;
	if(left &amp;lt;= index &amp;amp;&amp;amp; index &amp;lt;= right) {
		tree[nodeIndex] += diff;
		this.nums[index] += diff;
		int mid = left + (right - left) / 2;
		update(nodeIndex * 2, left, mid, index, diff);
		update(nodeIndex * 2 + 1, mid + 1, right, index, diff);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전체 코드&lt;/span&gt;&lt;/p&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1597566878750&quot; class=&quot;java&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package DataStructure;

import java.util.Arrays;

public class SegementTreeTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int nums[] = { 3, 2, 4, 5, 1, 6, 2, 7 };
		SegmentTree st = new SegmentTree(nums);
		System.out.println(st);
		
		System.out.println(&quot;sum of range [3, 7] is &quot; + st.query(1, 1, nums.length, 3, 7));
		System.out.println(&quot;sum of range [2, 5] is &quot; + st.query(1, 1, nums.length, 2, 5));
	
		int targetIndex = 2;
		int targetValue = 5;
		int diff = targetValue - nums[targetIndex];
		nums[targetIndex] = targetValue;
		st.update(1, 1, nums.length, targetIndex + 1, diff);
		
		System.out.println(st);
		System.out.println(&quot;sum of range [3, 7] is &quot; + st.query(1, 1, nums.length, 3, 7));
		
	
	}

}

class SegmentTree {
	int[] nums;
	int[] tree;
	int depth;
	int leafSize;

	public SegmentTree(int[] nums) {
		super();
		this.nums = nums;

		this.depth = 0;
		while (Math.pow(2, this.depth) &amp;lt; nums.length) {
			this.depth++;
		}

		this.leafSize = (int) Math.pow(2, this.depth);
		this.tree = new int[(int) Math.pow(2, this.depth + 1)];
		makeTree(1, 1, nums.length);
	}

	@Override
	public String toString() {
		return &quot;SegmentTree [nums=&quot; + Arrays.toString(nums) + &quot;, tree=&quot; + Arrays.toString(tree) + &quot;, leafSize=&quot;
				+ leafSize + &quot;, depth=&quot; + depth + &quot;]&quot;;
	}

	int makeTree(int nodeIndex, int left, int right) {
		if (left == right) {
			if (left &amp;lt;= nums.length)
				tree[nodeIndex] = nums[left - 1];
			else
				tree[nodeIndex] = 0;
			return tree[nodeIndex];
		} else {
			int mid = left + (right - left) / 2;
			tree[nodeIndex] = makeTree(nodeIndex * 2, left, mid);
			tree[nodeIndex] += makeTree(nodeIndex * 2 + 1, mid + 1, right);
			return tree[nodeIndex];
		}
	}

	int query(int nodeIndex, int left, int right, int qLeft, int qRight) {
		if (qLeft &amp;lt;= left &amp;amp;&amp;amp; right &amp;lt;= qRight)
			return tree[nodeIndex];
		else if (qRight &amp;lt; left || right &amp;lt; qLeft)
			return 0;
		else {
			int mid = left + (right - left) / 2;
			return query(nodeIndex * 2, left, mid, qLeft, qRight)
					+ query(nodeIndex * 2 + 1, mid + 1, right, qLeft, qRight);
		}
	}

	void update(int nodeIndex, int left, int right, int index, int diff) {
		if(nodeIndex &amp;gt;= tree.length) return;
		if(left &amp;lt;= index &amp;amp;&amp;amp; index &amp;lt;= right) {
			tree[nodeIndex] += diff;
			this.nums[index] += diff;
			int mid = left + (right - left) / 2;
			update(nodeIndex * 2, left, mid, index, diff);
			update(nodeIndex * 2 + 1, mid + 1, right, index, diff);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm</category>
      <category>Indexed Tree</category>
      <category>Segment tree</category>
      <category>구간 트리</category>
      <category>세그먼트 트리</category>
      <category>인덱스 트리</category>
      <author>bobo_hee</author>
      <guid isPermaLink="true">https://bobo-dev.tistory.com/83</guid>
      <comments>https://bobo-dev.tistory.com/83#entry83comment</comments>
      <pubDate>Sun, 16 Aug 2020 16:51:24 +0900</pubDate>
    </item>
    <item>
      <title>[ 프로그래머스 ] 라면공장</title>
      <link>https://bobo-dev.tistory.com/78</link>
      <description>&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/42629&quot;&gt;https://programmers.co.kr/learn/courses/30/lessons/42629&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1595860247436&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 연습 - 라면공장&quot; data-og-description=&quot;라면 공장에서는 하루에 밀가루를 1톤씩 사용합니다. 원래 밀가루를 공급받던 공장의 고장으로 앞으로 k일 이후에야 밀가루를 공급받을 수 있기 때문에 해외 공장에서 밀가루를 수입해야 합니��&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/42629&quot; data-og-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/42629&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Pohzb/hyGUJJJ2vV/YHJ7Qc9Is03aLjzhYFWoMk/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/ceLXH1/hyGWjinTi3/TP6Jr9Hs5TkybODNRgeeY1/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/42629&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/42629&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Pohzb/hyGUJJJ2vV/YHJ7Qc9Is03aLjzhYFWoMk/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/ceLXH1/hyGWjinTi3/TP6Jr9Hs5TkybODNRgeeY1/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;코딩테스트 연습 - 라면공장&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;라면 공장에서는 하루에 밀가루를 1톤씩 사용합니다. 원래 밀가루를 공급받던 공장의 고장으로 앞으로 k일 이후에야 밀가루를 공급받을 수 있기 때문에 해외 공장에서 밀가루를 수입해야 합니��&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;풀이 방법&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;하루에 밀가루를 1톤씩 사용하므로, 밀가루 재고가 &lt;i&gt;amount&lt;/i&gt;일 때 현재 날짜가 &lt;i&gt;amount&lt;/i&gt; 보다 크거나 같으면 밀가루 재고가 부족하다. 따라서 이 경우에는 그 전에 밀가루를 미리 구매해야 한다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이때, 밀가루 구매 횟수를 최소화하기 위해서는 &lt;b&gt;한번에 최대한 많이 구매할 수 있는 날에 구매&lt;/b&gt;해야 한다. 따라서 &lt;b&gt;우선순위 큐&lt;/b&gt;를 두어서 한번에 구매할 수 있는 최대 수량을 저장해나간다. 그리고 현재 날짜까지 사용할 수 있는 충분한 양의 밀가루를 구매한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1595860641708&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;while(amount &amp;lt;= dates[i]){
    amount += pq.top();
    pq.pop();
    answer++;
    if(amount &amp;gt;= k) return answer;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;한편, 밀가루 재고가 딱 떨어지는 날에 구매해야만 하는 경우가 있을 수 있다. 이 경우에는 우선순위 큐가 비어있기 때문에 먼저 우선순위 큐에 추가하도록 한다. 그리고 그 날의 수량을 -1로 업데이트하여 우선순위 큐에 한번 더 추가하더라도 문제 없도록 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1595860908809&quot; class=&quot;c++ arduino&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if(amount == dates[i]){
    pq.push(supplies[i]);
    supplies[i] = -1;
}

while(amount &amp;lt;= dates[i]){ ... }

pq.push(supplies[i]);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전체 코드는 &lt;a href=&quot;https://github.com/leebohee/problem-solving/blob/master/etc/programmers_p6.cpp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;여기&lt;/a&gt;서 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Algorithm/Problem Solving</category>
      <category>ps</category>
      <category>라면공장</category>
      <category>프로그래머스</category>
      <author>bobo_hee</author>
      <guid isPermaLink="true">https://bobo-dev.tistory.com/78</guid>
      <comments>https://bobo-dev.tistory.com/78#entry78comment</comments>
      <pubDate>Mon, 27 Jul 2020 23:43:16 +0900</pubDate>
    </item>
    <item>
      <title>Network Layer (1) - DHCP, NAT</title>
      <link>https://bobo-dev.tistory.com/76</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Network Layer&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;네트워크 계층은 단말기 뿐만 아니라 라우터, 스위치 등 모든 네트워크 노드가 갖고 있는 계층이다. 네트워크 계층은 크게 2가지 기능을 한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;Forwarding&lt;/b&gt;&lt;/span&gt;: 패킷을 노드 외부로 내보낸다. &amp;rarr; &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;Data Plane (전송부)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #6164c6;&quot;&gt;&lt;b&gt;Routing&lt;/b&gt;&lt;/span&gt;: 목적지까지의 경로를 결정한다. &amp;rarr; &lt;span style=&quot;color: #6164c6;&quot;&gt;&lt;b&gt;Control Plane (제어부)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전통적인 네트워크 구조에서는 각 라우터마다 전송부와 제어부를 갖는다. SDN(Software Defined Network)에서는 각 라우터가 전송부만 가지고, 제어부는 중앙 컨트롤러에 통합된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;IP Fragmentation / Reassembly&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;네트워크 링크는 최대 전송 크기인 MTU(Maximum Transmission Unit)을 갖고 있다. 따라서 이보다 큰 segement는 네트워크 계층에서 여러 datagram으로 쪼개서 전송하는데, 이 과정을 fragmentation이라고 한다. 반대로 쪼개진 datagram을 하나의 segment로 합치는 과정을 reassembly라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;fragmentation과 reassembly를 위해 IP 프로토콜은 헤더에서 identification, flag, offset 필드를 가진다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;identification: 파편화된 datagram이 하나의 segment를 이루는지를 식별하기 위한 값이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;flag: set되어 있으면, reassemble 해야 하는 datagram이 더 남아있다는 의미이다. 가장 마지막 segment는 flag가 unset되어 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;offset: 전체 segment에서의 해당 datagram의 offset, 바이트 단위의 offset을 8로 나눈 값을 저장한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&amp;nbsp;Subnet&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;같은 서브넷에 속하는 노드끼리는 라우터없이 바로 통신할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;342&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buNucz/btqFWBzvmFC/s8MXctZqI3t01irK9jvB7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buNucz/btqFWBzvmFC/s8MXctZqI3t01irK9jvB7k/img.png&quot; data-alt=&quot;Subnet Mask&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buNucz/btqFWBzvmFC/s8MXctZqI3t01irK9jvB7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuNucz%2FbtqFWBzvmFC%2Fs8MXctZqI3t01irK9jvB7k%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;342&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Subnet Mask&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서브넷 마스크는 IP 주소 4바이트 중 네트워크 주소와 호스트 주소를 구분하기 위한 비트이다. 서브넷 마스크를 이용하면 같은 서브넷에 속하는지 판단할 수 있다. 예를 들어 서브넷 마스크가 /24 (=255.255.255.0)이라면, 같은 서브넷에 속하는 노드는 IP 주소의 상위 3바이트가 일치한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;DHCP&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Dynamic Host Configuration Protocol의 약자로, 동적으로 IP 주소를 할당하는 프로토콜이다. DHCP는 4단계(4-way)로 동작한다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;DHCP discover&lt;/b&gt;: 호스트가 DHCP 서버를 찾기 위해 broadcast한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;DHCP offer&lt;/b&gt;: 응답할 수 있는 DHCP 서버가 할당할 수 있는 IP 주소를 담아 호스트의 메세지에 응답한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;DHCP request&lt;/b&gt;: 호스트가 해당 DHCP 서버에 받은 IP 주소를 사용하고 싶다고 요청한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;DHCP ask&lt;/b&gt;: DHCP 서버가 호스트의 요청에 응답한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;780&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWWXZr/btqFWAm3eGV/OO2TIDeVFsxuFthzCoKwY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWWXZr/btqFWAm3eGV/OO2TIDeVFsxuFthzCoKwY0/img.png&quot; data-alt=&quot;DHCP 동작 방식&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWWXZr/btqFWAm3eGV/OO2TIDeVFsxuFthzCoKwY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWWXZr%2FbtqFWAm3eGV%2FOO2TIDeVFsxuFthzCoKwY0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;780&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DHCP 동작 방식&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;NAT&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Network Address Translation의 약자로, private IP를 public IP로 변환하는 프로토콜이다. DHCP는 호스트에게 해당 서브넷에서 사용가능한 private IP 주소를 제공하는데, private IP는 그 범위 내에서만 사용할 수 있다. 따라서 외부 네트워크의 노드와 통신하기 위해서는 public IP로 변환하는 작업이 필요하다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;NAT 라우터는 outgoing 패킷의 src IP 주소와 port 번호를 자신의 IP 주소와 port 번호로 바꾸어서 내보낸다. 그리고 이러한 매핑 정보를 NAT translation table에 기록한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이후 incoming 패킷의 dest IP 주소와 port 번호를 NAT translation table을 참조해 내부 IP 주소 및 port 번호로 변환하여 들여보낸다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(+): IPv4의 주소 부족 문제를 해결할 수 있다(여러 호스트가 하나의 public IP 사용).&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(+): 외부로부터 내부 호스트들을 보호할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(-): NAT를 제공하는 노드가 망가지면 외부와 통신할 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(-): 내부 호스트들이 많아질수록 오버헤드가 커져 성능이 저하된다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;NAT Traversal&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;NAT는 내부 호스트에서 먼저 패킷을 내보낸 후에야 외부에서 패킷을 보낼 수 있다는 문제점이 있다. 즉, 외부에 있는 호스트에서 먼저 패킷을 보내고 싶어도 보낼 수 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 문제를 해결하기 위한 방법엔 여러가지가 있는데, 이러한 방법들을 NAT traversal이라고 한다. 편의를 위해 (호스트 B) &amp;rarr; (호스트 A)로 먼저 패킷을 보내고 싶다고 가정하자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;방법 1. Static Entry&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;호스트 A가 DHCP로 IP를 할당받지 않고, &lt;b&gt;고정 IP&lt;/b&gt;를 사용한 후 NAT translation table에 &lt;b&gt;static한 엔트리를 추가&lt;/b&gt;함으로써 해결할 수 있다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;외부의 호스트 B는 미리 알고있는 IP 주소 및 port 번호로 패킷을 전송하면, NAT는 static 엔트리를 참조하여 알맞게 변환한 후 포워딩해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 이 방법은 호스트 A의 public IP 주소와 port 번호가 잘 알려진 호스트의 경우만 사용할 수 있다는 한계가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;방법 2. Connection Reversal&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;제3의 서버에 호스트 A의 public IP 주소 및 port를 등록&lt;/b&gt;해둔다. 호스트 B는 제3의 서버에 connection을 요청하면, 제3의 서버가 호스트 A에게 이 요청을 포워딩한다. 그러면 호스트 A는 호스트 B에게 &lt;b&gt;역으로 먼저 connection을 요청&lt;/b&gt;한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 방법은 결국 호스트 B가 곧바로 A에게 패킷을 보낼 순 없다는 한계가 있다. 또한 호스트 B의 IP 주소 및 port 번호가 잘 알려진 경우에만 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;방법 3. Relaying&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;제3의 서버&lt;/b&gt;가 호스트 B의 패킷을 호스트 A에게&lt;b&gt; 그대로 포워딩&lt;/b&gt;해주는 방법이다. 그렇지만 제3의 서버가 관리하는 클라이언트가 많아질수록 서버의 부하가 증가한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 방법은 호스트 A와 B 모두 서로의 IP 주소 및 port 번호를 모르더라도&lt;b&gt;(잘 알려진 경우가 아니더라도) 사용&lt;/b&gt;할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;방법 4. UDP Hole Punching&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TCP가 아닌 &lt;b&gt;UDP&lt;/b&gt; 통신을 함으로써 호스트끼리 직접 통신하는 방법이다. 이 방법 역시 처음엔 &lt;b&gt;제3의 서버&lt;/b&gt;가 필요하다. 모든 호스트들은 제3의 서버에 자신을 등록해둔다. 그 후, 호스트 B에서 제3의 서버에 호스트 A의 public IP 주소와 port 번호를 요청해 알아낸다. 이후, 호스트 B는 이 정보를 그대로 이용해 호스트 A에 접속한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;TCP는 point-to-point 통신이기 때문에 호스트 A와 제3의 서버 사이의 port 번호를 알더라도 호스트 B가 이 port로 A에게 패킷을 보낼 수 없다. 그렇지만 &lt;b&gt;UDP는 가능&lt;/b&gt;하다!&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이 방법은 호스트 A, B의 IP 주소 및 port 번호가 잘 알려진 경우가 아니더라도 직접 통신할 수 있다는 장점이 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Network</category>
      <category>DHCP</category>
      <category>NAT</category>
      <category>Network Layer</category>
      <category>네트워크 계층</category>
      <author>bobo_hee</author>
      <guid isPermaLink="true">https://bobo-dev.tistory.com/76</guid>
      <comments>https://bobo-dev.tistory.com/76#entry76comment</comments>
      <pubDate>Thu, 23 Jul 2020 02:43:29 +0900</pubDate>
    </item>
    <item>
      <title>Transport Layer (1)</title>
      <link>https://bobo-dev.tistory.com/73</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Transport Layer&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전송 계층에서는 프로세스 간의 논리적 통신 기능을 제공한다. 네트워크 계층에서 호스트 간의 논리적인 전송을 담당한다면, 전송 계층에서는 &lt;b&gt;호스트 내의 프로세스 간&lt;/b&gt;의 통신을 담당한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;응용 계층에서 받은 메시지를 segment로 쪼개어 네트워크 계층에 전송하고, 반대로 네트워크 계층에서 받은 segment를 합쳐서 메시지를 만들어 응용 계층으로 올려 보낸다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대표적인 프로토콜로 TCP와 UDP가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Multiplexing / Demultiplexing&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;멀티플렉싱이란, 여러 소켓에서 전송하려는 데이터에 전송 계층의 헤더를 붙여 이 segment를 네트워크 계층으로 전달하는 작업이다. 멀티플렉싱을 통해 sender는 하나의 physical link만 있어도 여러 sending process를 관리할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;409&quot; height=&quot;NaN&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAhjFe/btqFWZGOUVR/dqQNZy1vA2d1Scb1dGymO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAhjFe/btqFWZGOUVR/dqQNZy1vA2d1Scb1dGymO0/img.png&quot; data-alt=&quot;Segment Format&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAhjFe/btqFWZGOUVR/dqQNZy1vA2d1Scb1dGymO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAhjFe%2FbtqFWZGOUVR%2FdqQNZy1vA2d1Scb1dGymO0%2Fimg.png&quot; width=&quot;409&quot; height=&quot;NaN&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Segment Format&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;반대로 디멀티플렉싱은 네트워크 계층으로부터 전달받은 segment의 헤더를 보고 올바른 소켓에 데이터를 전달하는 작업이다. 디멀티플렉싱 또한 receiver가 하나의 physical link를 가져도 여러 receiving process를 처리해줄 수 있다. TCP는 헤더에 적힌 IP 주소와 port 번호를 보고 목적지 소켓을 찾는다. UDP는 헤더에 적인 port 번호만 보고 목적지 소켓을 찾는다(connectionless이기 때문에).&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;TCP vs UDP&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;TCP는 Transmission Control Protocol의 약자로, 신뢰성 있는 데이터 전송을 보장하는 연결형 프로토콜이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;UDP는 User Datagram Protocol의 약자로, 비연결형 프로토콜이며 신뢰성보다는 속도를 중요시하는 네트워크에 사용된다. TCP에 비해 단순한 헤더 구조를 갖고, 오버헤드가 적다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 156px;&quot; border=&quot;1&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 24.9612%; height: 19px; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 38.4496%; height: 19px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;TCP&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.5891%; height: 19px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;UDP&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 24.9612%; height: 19px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Connection Setup&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 38.4496%; height: 19px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;O&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.5891%; height: 19px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;X&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 24.9612%; height: 21px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Packet Reordering&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 38.4496%; height: 21px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;O&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.5891%; height: 21px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;X&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 24.9612%; height: 19px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Reliable Transmission&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 38.4496%; height: 19px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;O&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.5891%; height: 19px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;X&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;width: 24.9612%; text-align: left; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Congestion/Flow Control&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 38.4496%; text-align: center; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;O&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.5891%; text-align: center; height: 21px;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;X&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 24.9612%; height: 19px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Multicasting / Broadcasting&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 38.4496%; height: 19px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;X&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(Point-to-Point 통신이므로)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.5891%; height: 19px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;O&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 24.9612%; height: 19px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;적용 분야&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 38.4496%; height: 19px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;패킷 손실이 허용되지 않는 서비스&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.5891%; height: 19px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;실시간 스트리밍 서비스&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;오버헤드가 적은 애플리케이션&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 24.9612%; height: 19px; text-align: left;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 38.4496%; height: 19px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;HTTP, FTP 등&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.5891%; height: 19px; text-align: center;&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;DNS, DHCP, IPTV, VoIP, RIP 등&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Checksum&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;체크섬은&amp;nbsp;&lt;b&gt;segment 내의 에러를 감지&lt;/b&gt;하기 위한 필드이다. TCP와 UDP 모두 체크섬을 사용하여 비트 오류를 검사한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;sender는 segment를 16비트 데이터로 쪼개어 다 더한 후, 이 합을 1's complement를 취해서 체크섬으로 지정한다. receiver에서는 checksum을 포함한 segment의 모든 16비트 데이터들을 합하여 11...1이 나왔는지 확인한다. 만약 11...1이라면 오류가 발생하지 않았고, 그렇지 않은 경우 전송 도중 오류가 발생했음을 감지할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;502&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CjG6d/btqFT77mcAX/KWxaa8wUVvZQXl0pSxVPO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CjG6d/btqFT77mcAX/KWxaa8wUVvZQXl0pSxVPO0/img.png&quot; data-alt=&quot;Checksum 예제&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CjG6d/btqFT77mcAX/KWxaa8wUVvZQXl0pSxVPO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCjG6d%2FbtqFT77mcAX%2FKWxaa8wUVvZQXl0pSxVPO0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;502&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Checksum 예제&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위의 예제를 보면, 16비트 데이터를 더하는데, 만약 오버플로우가 발생했으면 맨 하위 비트에 1을 더해주는 식으로 합을 구해나간다. 이후, receiver에서는 다음과 같이 16비트 데이터의 합과 체크섬을 합하여 11...1인지 확인한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;1011101110111100&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp; + 0100010001000011 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;(checksum)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;------------------------------&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;1111111111111111 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;(OK)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;만약 전송된 데이터에 비트 오류가 발생하였다면 16비트 데이터의 합이 달라지게 될 것이고, 체크섬과 합하였을 때 11...1이 나올 수 없게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;1011101&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/span&gt;10111100&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp; + 0100010001000011&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;(checksum)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;------------------------------&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;1111111&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;0&lt;/b&gt;&lt;/span&gt;11111111&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;(ERROR!!!)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Network</category>
      <category>checksum</category>
      <category>Transport layer</category>
      <category>udp</category>
      <category>전송 계층</category>
      <category>체크섬</category>
      <author>bobo_hee</author>
      <guid isPermaLink="true">https://bobo-dev.tistory.com/73</guid>
      <comments>https://bobo-dev.tistory.com/73#entry73comment</comments>
      <pubDate>Wed, 22 Jul 2020 23:34:21 +0900</pubDate>
    </item>
    <item>
      <title>Transaction Processing</title>
      <link>https://bobo-dev.tistory.com/72</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Transaction&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;트랜잭션은 DBMS의 데이터베이스를 접근하고 업데이트하는 프로그램 실행의 단위이다. 데이터베이스에서 하나의 논리적 기능을 수행하기 위한 일련의 연산 집합으로서 작업의 단위이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;트랜잭션은 여러 연산을 실행하지만, DBMS의 입장에서는 데이터베이스의 데이터를 READ/WRITE하는 연산만 중요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;370&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzIOXL/btqFUBMJgsh/ZAi5ZJF9KBMkpXV4zhIvO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzIOXL/btqFUBMJgsh/ZAi5ZJF9KBMkpXV4zhIvO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzIOXL/btqFUBMJgsh/ZAi5ZJF9KBMkpXV4zhIvO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzIOXL%2FbtqFUBMJgsh%2FZAi5ZJF9KBMkpXV4zhIvO0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;370&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;308&quot; data-origin-height=&quot;177&quot; width=&quot;253&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqrzV4/btqFUSnbzew/Raug9s9opEnK5Yrh6JMqOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqrzV4/btqFUSnbzew/Raug9s9opEnK5Yrh6JMqOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqrzV4/btqFUSnbzew/Raug9s9opEnK5Yrh6JMqOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqrzV4%2FbtqFUSnbzew%2FRaug9s9opEnK5Yrh6JMqOk%2Fimg.png&quot; data-origin-width=&quot;308&quot; data-origin-height=&quot;177&quot; width=&quot;253&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;많은 사용자의 동시 접근을 위해 트랜잭션을 concurrent하게 처리해주어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;ACID rules&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;데이터 무결성을 보장하기 위해 트랜잭션이 갖추어야 할 4가지 속성이다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Atomicity&lt;/b&gt;: 트랜잭션의 모든 연산은 완전히 반영되거나, 아예 반영되지 않아야 한다. (all or nothing)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Consistency&lt;/b&gt;: 트랜잭션이 완료되면 언제나 일관성 있는 상태여야 한다. 트랜잭션을 실행하기 전과 후의 시스템의 고정 요소 상태가 같아야 한다. &lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;A계좌와 B계좌의 합이 25,000원이라면, A계좌&amp;rarr;B계좌로 5,000원을 송금한 후에도 두 계좌의 합이 25,000원이어야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Isolation&lt;/b&gt;: 동시에 일어나는 다른 트랜잭션에 의해 영향을 받지 않아야 한다. 여러 트랜잭션이 동시에 수행되어도 그 결과는 순차적으로 실행된 결과와 같아야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Durability&lt;/b&gt;: 완료된 트랜잭션의 결과는 영구적으로 보존되어야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Transaction Status&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;트랜잭션은 5가지 상태에 놓일 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;552&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qgr66/btqFQxebyZC/XnErgiHTcCdYl3zLwkWDM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qgr66/btqFQxebyZC/XnErgiHTcCdYl3zLwkWDM1/img.png&quot; data-alt=&quot;Transaction Status&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qgr66/btqFQxebyZC/XnErgiHTcCdYl3zLwkWDM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqgr66%2FbtqFQxebyZC%2FXnErgiHTcCdYl3zLwkWDM1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;552&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Transaction Status&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;트랜잭션이 실행되면 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;active 상태&lt;/b&gt;&lt;/span&gt;에 놓인다. 이때 트랜잭션의 마지막 연산까지 수행하면 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;partially committed 상태&lt;/b&gt;&lt;/span&gt;가 된다. 이 상태는 아직 COMMIT 연산, 즉 트랜잭션에서 변경한 내용을 데이터베이스에 반영하지 않은 상태이다. 이후 &lt;b&gt;COMMIT&lt;/b&gt; 연산까지 하게 되면 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;committed 상태&lt;/b&gt;&lt;/span&gt;가 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;한편, 트랜잭션을 수행하던 도중 오류가 발생되어 중단되면 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;failed 상태&lt;/b&gt;&lt;/span&gt;가 된다. 트랜잭션에서 수행한 모든 변경 작업을 취소하고 트랜잭션 이전 상태로 되돌리는 ROLLBACK 연산을 한 후, &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;aborted 상태&lt;/b&gt;&lt;/span&gt;가 된다. aborted 상태는 트랜잭션이 비정상적으로 종료되어 &lt;b&gt;ROLLBACK&lt;/b&gt; 연산을 수행한 상태이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Conflicting Operation&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;충돌 연산이란, 같은 데이터에 대한 두 개의 연산 중 적어도 하나가 WRITE인 경우를 의미한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;WR 충돌&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;RW 충돌&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;WW 충돌&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Conflict Serializability&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;interleaved schedulte에서 충돌 연산의 수행 순서가 serial schedule에서의 순서와 같으면 conflict serializable하다고 한다. 충돌 연산의 수행 순서를 그래프로 나타내어 conflict serializable한지 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;554&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9Ior6/btqFS0sYbEl/jI5NOXpDwXhjp8gcPpHnT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9Ior6/btqFS0sYbEl/jI5NOXpDwXhjp8gcPpHnT0/img.png&quot; data-alt=&quot;Conflict Serializability Testing Graph&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9Ior6/btqFS0sYbEl/jI5NOXpDwXhjp8gcPpHnT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9Ior6%2FbtqFS0sYbEl%2FjI5NOXpDwXhjp8gcPpHnT0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;554&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Conflict Serializability Testing Graph&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;Conflict serializable한 스케쥴은 항상 &lt;b&gt;동시성과 일관성을 보장&lt;/b&gt;한다. Conflict serializable하지 않은 스케쥴의 경우, &lt;b&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;Two-Phase Locking&lt;/span&gt; 또는 &lt;span style=&quot;color: #6164c6;&quot;&gt;Timestamp Ordering&lt;/span&gt;&lt;/b&gt;을 이용해서 직렬성을 보장할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Locking&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;lock이란 어떤 트랜잭션에서 사용하는 데이터를 다른 트랜잭션에서 접근하지 못 하도록 막는 것을 의미한다. 데이터에 접근하기 전에 lock을 요청하여 허락받은 후 접근해야 하고, 이후 unlock하여 lock을 반환해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;locking의 단위가 크면 관리가 쉽지만 병행성이 낮아진다. 반대로 locking의 단위가 작으면 관리가 어렵고 locking 오버헤드가 증가하지만, 병행성이 증가한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;lock에는 2가지 종류가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Shared Lock (S-Lock)&lt;/b&gt;: 하나 이상의 트랜잭션이 얻을 수 있다. 데이터를 읽기 전에 얻어야 하는 lock으로 Read-Lock이라고도 한다. S-Lock을 가진 트랜잭션이 있을 때엔 다른 트랜잭션에서 X-Lock을 얻지 못 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Exclusive Lock (X-Lock)&lt;/b&gt;: 오직 한 트랜잭션만 얻을 수 있다. 데이터를 쓰기 전에 얻어야 하는 lock으로 Write-Lock이라고도 한다. X-Lock을 가진 트랜잭션이 있을 때엔 다른 트랜잭션에서 X-Lock 뿐만 아니라 S-Lock도 얻지 못 한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Two-Phase Locking (2PL)&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;모든 트랜잭션이 필요한 lock을 모두 얻은 후에 unlock하는 방법이다. 즉, lock과 unlock을 2단계로 수행한다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Growing(=Locking) Phase&lt;/b&gt;: 새로운 lock을 얻는 구간으로, 해당 구간에서는 어떠한 lock도 해제할 수 없다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Shrinking(=Unlocking) Phase&lt;/b&gt;: 얻은 lock을 모두 해제하는 구간으로, 해당 구간에서는 어떠한 lock도 새로 얻을 수 없다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;308&quot; data-filename=&quot;blob&quot; width=&quot;571&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbsXfX/btqFQ856v1J/xXkboMaoEh3EkO2sOxRWmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbsXfX/btqFQ856v1J/xXkboMaoEh3EkO2sOxRWmk/img.png&quot; data-alt=&quot;Two Phase Locking&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbsXfX/btqFQ856v1J/xXkboMaoEh3EkO2sOxRWmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbsXfX%2FbtqFQ856v1J%2FxXkboMaoEh3EkO2sOxRWmk%2Fimg.png&quot; data-origin-width=&quot;703&quot; data-origin-height=&quot;308&quot; data-filename=&quot;blob&quot; width=&quot;571&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Two Phase Locking&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;2PL은 항상 &lt;b&gt;직렬성을 보장&lt;/b&gt;하지만, lock을 얻는 순서에 따라 &lt;b&gt;데드락이 발생할 수 있다&lt;/b&gt;는 단점이 있다.&amp;nbsp;데드락을 예방하기 위해서는 모든 트랜잭션에서 lock을 얻는 순서를 같게 해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;368&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cG65x9/btqFUAmMjLb/ntiXkO6j66zVaj8aI6jMzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cG65x9/btqFUAmMjLb/ntiXkO6j66zVaj8aI6jMzK/img.png&quot; data-alt=&quot;Deadlock 예제&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cG65x9/btqFUAmMjLb/ntiXkO6j66zVaj8aI6jMzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcG65x9%2FbtqFUAmMjLb%2FntiXkO6j66zVaj8aI6jMzK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;368&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Deadlock 예제&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;위의 예제에서 T1의 경우 lock을 B&amp;rarr;A 순서로 얻는다. T2에서는 A&amp;rarr;B 순서로 얻는다. 따라서 데드락이 발생할 수 있다. 모든 트랜잭션에서 A&amp;rarr;B 또는 B&lt;span style=&quot;color: #333333;&quot;&gt;&amp;rarr;A 순서로 lock을 얻도록 하면 데드락이 발생하지 않는다(데드락 발생 조건 중 circular wait 만족 X).&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;한편 많은 데이터에 접근해야 하는 경우, lock을 모두 얻어야 하므로 병행성이 낮아진다는 문제점도 있다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Timestamp Ordering&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;타임 스탬프 순서 기법은 READ/WRITE 하기 전에 타임 스탬프를 부여하고, 타임 스탬프 순서에 따라 트랜잭션 작업을 수행하도록 하는 방법이다. 이 방법은 직렬성을 보장하며 데드락이 발생하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Wait-Die&lt;/b&gt;: 오래된 트랜잭션은 lock이 해제되기를 기다릴 수 있지만, 새로운 트랜잭션은 rollback되어 lock을 반환한다. Non-Preemtive한 방식이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Wound-Wait&lt;/b&gt;: 새로운 트랜잭션은 lock이 해제되기를 기다릴 수 있지만, 오래된 트랜잭션은 새로운 트랜잭션을 강제로 rollback 시키고 자신이 lock을 점유한다. Preemptive한 방식이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Database</category>
      <category>Database</category>
      <category>locking</category>
      <category>transaction</category>
      <category>데이터베이스</category>
      <category>트랜잭션</category>
      <author>bobo_hee</author>
      <guid isPermaLink="true">https://bobo-dev.tistory.com/72</guid>
      <comments>https://bobo-dev.tistory.com/72#entry72comment</comments>
      <pubDate>Tue, 21 Jul 2020 23:54:37 +0900</pubDate>
    </item>
    <item>
      <title>대칭키와 비대칭키</title>
      <link>https://bobo-dev.tistory.com/68</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Private Key Encrytion&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개인키 암호화 기법은 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;송신자와 수신자가 동일한 키로 암호화 및 복호화&lt;/b&gt;&lt;/span&gt;하는 방법이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;암호화와 복호화에 사용되는 키가 같아 &lt;b&gt;대칭키 방식&lt;/b&gt;이라고도 하며, 이 키는 외부에 노출되면 안 되므로 &lt;b&gt;비밀키 방식&lt;/b&gt;이라고도 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;742&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/V5ZBM/btqFRAHxAOy/l6RakJUT5TQBpSKp3BLnw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/V5ZBM/btqFRAHxAOy/l6RakJUT5TQBpSKp3BLnw0/img.png&quot; data-alt=&quot;Private Key Encryption&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/V5ZBM/btqFRAHxAOy/l6RakJUT5TQBpSKp3BLnw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FV5ZBM%2FbtqFRAHxAOy%2Fl6RakJUT5TQBpSKp3BLnw0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;742&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Private Key Encryption&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(+): 계산 속도가 빠르다. 즉, 암호화 및 복호화 속도가 빠르다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(+): 알고리즘이 단순하고 다양하다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(+) 파일의 크기가 공개키 기법보다 작다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(-): 사용자가 증가함에 따라 관리해야 할 키의 수가 많아진다. (모든 노드를 연결해야 하므로 n개의 노드가 있을 때,&amp;nbsp;&lt;a href=&quot;https://www.codecogs.com/eqnedit.php?latex=\frac{n(n+1)}{2}&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;img title=&quot;\frac{n(n+1)}{2}&quot; src=&quot;https://latex.codecogs.com/gif.latex?\frac{n(n+1)}{2}&quot; /&gt;&lt;/a&gt;개의 키가 필요하다.&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(-): 키의 분배 및 관리가 어렵다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예) DES, AES&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Public Key Encryption&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;공개키 암호화 기법은 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;외부에 공개된 키(=공개키, Public Key)로 암호화&lt;/b&gt;&lt;/span&gt;하고, &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;비밀리에 관리하는 키(=비밀키, Secret Key)로 복호화&lt;/b&gt;&lt;/span&gt;하는 방법이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;암호화와 복호화에 사용되는 키가 다르므로 &lt;b&gt;비대칭키 방식&lt;/b&gt;이라고도 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;736&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caHfi7/btqFTT0TDSh/9KJ9ufuScKSg0yMyEkK0t0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caHfi7/btqFTT0TDSh/9KJ9ufuScKSg0yMyEkK0t0/img.png&quot; data-alt=&quot;Public Key Encryption&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caHfi7/btqFTT0TDSh/9KJ9ufuScKSg0yMyEkK0t0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaHfi7%2FbtqFTT0TDSh%2F9KJ9ufuScKSg0yMyEkK0t0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;736&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Public Key Encryption&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;개인키 알고리즘보다 키의 길이가 길다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(+): 키의 분배가 쉽다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(+): 관리해야 할 키의 수가 적다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(-): 계산 속도가 느리다. 즉, 암호화 및 복호화 속도가 느리다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(-): 알고리즘이 복잡하다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;(-): 파일의 크기가 개인키 기법보다 크다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;예) RSA, 전자서명&lt;/span&gt;&lt;/p&gt;</description>
      <category>etc</category>
      <category>개인키</category>
      <category>공개키</category>
      <category>대칭키</category>
      <category>비대칭키</category>
      <category>암호화</category>
      <author>bobo_hee</author>
      <guid isPermaLink="true">https://bobo-dev.tistory.com/68</guid>
      <comments>https://bobo-dev.tistory.com/68#entry68comment</comments>
      <pubDate>Tue, 21 Jul 2020 15:41:37 +0900</pubDate>
    </item>
    <item>
      <title>Application Layer (2) - HTTP</title>
      <link>https://bobo-dev.tistory.com/65</link>
      <description>&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;HTTP에 대해 알아보기 전에 Web에 대해 간단하게 알아보자면,&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;웹&lt;/b&gt;&lt;/span&gt;은 클라이언트-서버 구조를 갖는 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;애플리케이션&lt;/b&gt;&lt;/span&gt;이고, &lt;b&gt;&lt;span style=&quot;color: #6164c6;&quot;&gt;HTTP&lt;/span&gt;&lt;/b&gt;은 웹의 application layer에 위치하는 &lt;span style=&quot;color: #6164c6;&quot;&gt;&lt;b&gt;프로토콜&lt;/b&gt;&lt;/span&gt;이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;헷갈리지 말자!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;HTTP&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;HTTP는 HyperText Transfer Protocol의 약자로, application 계층의 프로토콜 중 하나이다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;Client-Server&lt;/b&gt; 모델이며, &lt;b&gt;ASCII&lt;/b&gt;로 된 응답/요청 메세지를 주고받는다. HTTP 통신 방법은 대략적으로 다음과 같은 순서로 이루어진다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클라이언트가 URL을 통해&amp;nbsp;서버의 IP 주소를 알아낸다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클라이언트가 HTTP request 메시지 생성한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클라이언트가 서버의 (IP 주소, port 번호)로 TCP connection 요청한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서버는 port 번호로 기다리다가 TCP connection 요청이 들어오면 수락하고, 클라이언트에게 이를 알린다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클라이언트가 서버로 HTTP request 전송한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;서버가 request를 처리하고, 그 결과에 대해 HTTP response 메세지 생성하여 전송한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이후 서버가 TCP connection을 끊는다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;클라이언트는 받은 response 메세지로부터 결과 화면을 웹 브라우저에 띄운다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;HTTP는 기본적으로 &lt;b&gt;stateless&lt;/b&gt;한 프로토콜이다. 따라서 요청이 독립적으로 관리된다. 다시 말하자면, 서버가 클라이언트의 과거 요청 정보를 기록하지 않는다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이로 인해 서버는 간단한 디자인을 가질 수 있으나, 클라이언트 측에서는 요청할 때마다 필요한 모든 정보를 함께 보내야 한다는 불편함이 있다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;이러한 점은 쿠키 및 세션으로 일정 부분 해소할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;HTTP Message 구조&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;HTTP request message는 다음과 같은 구조를 갖는다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;440&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SKpSz/btqFQKCUaTp/jvym1XUpeH4DHsFJMvqBS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SKpSz/btqFQKCUaTp/jvym1XUpeH4DHsFJMvqBS1/img.png&quot; data-alt=&quot;HTTP Request Message&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SKpSz/btqFQKCUaTp/jvym1XUpeH4DHsFJMvqBS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSKpSz%2FbtqFQKCUaTp%2Fjvym1XUpeH4DHsFJMvqBS1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;440&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;HTTP Request Message&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;대표적인 메소드는 GET, POST, PUT, DELETE가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;&quot;&gt;GET: 서버에 자원 요청&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;&quot;&gt;POST: 서버에 새로운 자원을 전송 또는 생성&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;&quot;&gt;PUT: 서버에 존재하는 자원 변경/수정&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;&quot;&gt;DELETE: 서버에 존재하는 자원 삭제&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;&quot;&gt;GET vs POST&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;&quot;&gt;두 메소드 모두 데이터를 담아 전송할 수 있는 메소드이다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;&quot;&gt;GET은 URL에 데이터를 덧붙여 전송하는 방식이며, POST는 메세지의 body 부분에 데이터를 담아 전송하는 방식이다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;&quot;&gt;따라서 POST 방식이 좀 더 안전하고 대용량 데이터 전송에 알맞다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;span style=&quot;&quot;&gt;HTTP response message는 다음과 같은 구조를 갖는다.&lt;/span&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;436&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YSUNV/btqFP9QHTqf/jKXKtn8EkJEj6CPQTeB8Y0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YSUNV/btqFP9QHTqf/jKXKtn8EkJEj6CPQTeB8Y0/img.png&quot; data-alt=&quot;HTTP Response Message&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YSUNV/btqFP9QHTqf/jKXKtn8EkJEj6CPQTeB8Y0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYSUNV%2FbtqFP9QHTqf%2FjKXKtn8EkJEj6CPQTeB8Y0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;436&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;HTTP Response Message&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;상태 코드는 번호에 따라 다른 의미를 갖는다. 대표적인 상태 코드는 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;200번대: 성공&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;200 OK&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt; 204 No Content: 성공했으나 response로 돌려줄 리소스 없음 (헤더 정보가 의미있을 때 사용)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;300번대: Redirection 유도&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;301 Moved Permanently: 요청한 리소스가 새 URL에 존재&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;400번대: Client Error&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;403 Forbidden: 해당 리소스 접근 금지 (권한 없음)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;404 Not Found: 해당 리소스 없음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;500번대: Server Error&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;503 Service Unavailable: 유지보수 등의 이유로 서버가 일시적으로 요청 처리 못 할 때&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Network</category>
      <category>Application Layer</category>
      <category>http</category>
      <category>Network</category>
      <category>네트워크</category>
      <category>응용 계층</category>
      <author>bobo_hee</author>
      <guid isPermaLink="true">https://bobo-dev.tistory.com/65</guid>
      <comments>https://bobo-dev.tistory.com/65#entry65comment</comments>
      <pubDate>Mon, 20 Jul 2020 17:47:13 +0900</pubDate>
    </item>
    <item>
      <title>[ 프로그래머스 ] 가장 먼 노드</title>
      <link>https://bobo-dev.tistory.com/62</link>
      <description>&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/49189?language=cpp&quot;&gt;https://programmers.co.kr/learn/courses/30/lessons/49189?language=cpp&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1594279193488&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 연습 - 가장 먼 노드&quot; data-og-description=&quot;6 [[3, 6], [4, 3], [3, 2], [1, 3], [1, 2], [2, 4], [5, 2]] 3&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/49189?language=cpp&quot; data-og-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/49189?language=cpp&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b86jWH/hyGHpkGRCl/BxzEs3p364ofD5V7BTr820/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/jbxPC/hyGICiqaYe/QVYD7J4G1Eu0KvEKofH0Lk/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/49189?language=cpp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/49189?language=cpp&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b86jWH/hyGHpkGRCl/BxzEs3p364ofD5V7BTr820/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/jbxPC/hyGICiqaYe/QVYD7J4G1Eu0KvEKofH0Lk/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;코딩테스트 연습 - 가장 먼 노드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;6 [[3, 6], [4, 3], [3, 2], [1, 3], [1, 2], [2, 4], [5, 2]] 3&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;풀이 방법&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;1번 노드와 가장 멀리 떨어진 노드들의 개수를 구하는 문제이다. BFS를 이용해 거리 별로 방문하다가 가장 마지막에 방문한 노드 개수를 반환하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;우선 노드의 개수가 최대 20,000개이고, 간선의 개수는 최대 50,000개이므로 간선 정보를 인접 행렬보다는 인접 리스트에 저장하는 게 더 효율적이다. 왜냐하면 인접 행렬은 크기가 20,000*20,000인 반면, 인접 리스트는 50,000이기 때문이다. 다음과 같이 인접 리스트를 초기화하면서 1번 노드와 인접한 노드들을 큐에 넣는다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1594279470414&quot; class=&quot;c++ arduino&quot; style=&quot;display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vector&amp;lt;int&amp;gt; adj[n+1];
for(const auto&amp;amp; e: edge){
    adj[e[0]].push_back(e[1]);
    adj[e[1]].push_back(e[0]);
    if(e[0] == 1){
        q.push(e[1]);
        visit[e[1]] = true;
    }
    else if(e[1] == 1){
        q.push(e[0]);
        visit[e[0]] = true;   
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;그 후, 더 이상 방문할 노드가 없을 때까지 BFS를 실행하는데, 거리 별 노드 개수를 알아내기 위해 cnt 변수에 큐의 크기를 저장한다. 그리고 cnt 만큼만 큐에서 pop하면 1번 노드와 동일한 거리의 노드들만 for문으로 방문할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1594279650763&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;while(!q.empty()){
    cnt = q.size();
    for(int i=0; i&amp;lt;cnt; i++){
        int node = q.front();
        q.pop();
        for(int next: adj[node]){
            if(!visit[next]){
                q.push(next);
                visit[next] = true;
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;while문이 종료되었을 때, cnt는 가장 거리가 먼 노드들의 개수를 저장하고 있을 것이다. 따라서 마지막에 cnt를 반환하면 답을 구할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;전체 코드는 &lt;a href=&quot;https://github.com/leebohee/problem-solving/blob/master/etc/programmers_p5.cpp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;여기&lt;/a&gt;서 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Algorithm/Problem Solving</category>
      <category>BFS</category>
      <category>ps</category>
      <category>가장 먼 노드</category>
      <category>프로그래머스</category>
      <author>bobo_hee</author>
      <guid isPermaLink="true">https://bobo-dev.tistory.com/62</guid>
      <comments>https://bobo-dev.tistory.com/62#entry62comment</comments>
      <pubDate>Thu, 9 Jul 2020 16:28:35 +0900</pubDate>
    </item>
  </channel>
</rss>