<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>ZzoeE.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Fri, 30 Sep 2022 06:09:31 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. ZzoeE.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/sohi_5" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[CSR vs SSR, 그리고 Next.js]]></title>
            <link>https://velog.io/@sohi_5/CSR-vs-SSR-%EA%B7%B8%EB%A6%AC%EA%B3%A0-Next.js</link>
            <guid>https://velog.io/@sohi_5/CSR-vs-SSR-%EA%B7%B8%EB%A6%AC%EA%B3%A0-Next.js</guid>
            <pubDate>Fri, 30 Sep 2022 06:09:31 GMT</pubDate>
            <description><![CDATA[<h2 id="1-csrclient-side-rendering이란-무엇이며-그것의-장단점에-대하여-설명해주세요">1. CSR(Client-side Rendering)이란 무엇이며, 그것의 장단점에 대하여 설명해주세요.</h2>
<h3 id="csr의-정의">CSR의 정의</h3>
<p>CSR이란 웹페이지의 렌더링이 클라이언트 브라우저에서 발생하는 것으로, 어플리케이션 구동에 필요한 파일 (HTML, CSS, JS 등)을 최초 요청에서 모두 다운로드하여 뷰가 구성된다.  </p>
<h3 id="장점">장점</h3>
<ul>
<li>서버 부담 / 후속 페이지 로드 시간 감소
최초에 필요한 파일을 모두 받아오기 때문에 사이트의 다른 페이지로 이동 시에 이미 받아놓은 JS 실행을 하기 때문에 서버에 요청할 필요가 없고, 로딩 시간 또한 빠르다. </li>
<li>사용자 경험
새로고침이 발생하지 않기 때문에 내부 컨텐츠 변경으로 인한 깜빡임 현상 등이 발생하지 않아 사용자 친화적인 환경을 제공할 수 있다.</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li>초기 로딩 속도 느림
초기에 모든 파일을 로드한 후에 뷰를 구성해야하기 때문에 앱의 규모가 커질 수록 초기 구동시간이 크게 느려진다.</li>
<li>SEO에 불리
웹 페이지의 콘텐츠가 JS를 통해 동적으로 변경되기 때문에, 과거의 검색 엔진 크롤러는 JS 실행을 하지 않아서 빈페이지를 마주하기 때문에 CSR 방식은 SEO에 매우 불리하다.  </li>
</ul>
<h2 id="2-spasingle-page-application로-구성된-웹-앱에서-ssrserver-side-rendering이-필요한-이유에-대하여-설명해주세요">2. SPA(Single Page Application)로 구성된 웹 앱에서 SSR(Server-side Rendering)이 필요한 이유에 대하여 설명해주세요.</h2>
<p>일반적인 SPA 의 렌더링 방식은 CSR을 사용하나, CSR은 SEO에 불리하다는 단점이 있다. 사용자 유입이 중요하여 검색 엔진 최적화가 우선되어야 할 경우, SSR 방식이 적합하다.</p>
<p>SSR은 서버에서 사용자에게 보여줄 페이지를 모두 렌더링하여 전달하는 방식이다. 서버에서 페이지 구성이 모두 이뤄진 뒤 전달되기 때문에 CSR 방식에 비해 SEO에 훨씬 유리하다. </p>
<h2 id="nextjs-프로젝트를-세팅한-뒤-yarn-start-스크립트를-실행했을-때-실행되는-코드를-nextjs-github-레포지토리에서-찾은-뒤-해당-파일에-대한-간단한-설명을-첨부해주세요">Next.js 프로젝트를 세팅한 뒤 yarn start 스크립트를 실행했을 때 실행되는 코드를 nextjs github 레포지토리에서 찾은 뒤, 해당 파일에 대한 간단한 설명을 첨부해주세요.</h2>
<h3 id="1-projectpackagejson">(1) PROJECT/package.json</h3>
<pre><code class="language-json">{
    ...
    &quot;scripts&quot; : {
        &quot;dev&quot;: &quot;next dev&quot;,
          &quot;build&quot;: &quot;next build&quot;,
          &quot;start&quot;: &quot;next start&quot;
    },
      ...
}</code></pre>
<p><code>create-next-app</code> 를 통해 프로젝트 생성하고, <code>package.json</code> 파일의 scripts 부분을 확인하였다.
<code>yarn start</code> 스크립트 실행 시 &quot;next start&quot;가 실행되는 것을 볼 수 있다. </p>
<h3 id="2-nextjspackages">(2) <a href="https://github.com/vercel/next.js/tree/canary/packages">next.js/packages</a></h3>
<p><img src="https://velog.velcdn.com/images/sohi_5/post/3907adc2-f615-4c23-b0f3-65a739561302/image.png" alt=""></p>
<p>next.js/packages 폴더에서 next.js 관련 package들이 나뉘어 있는 것을 발견할 수 있었다. 프로젝트 세팅하며 사용했던 <code>create-next-app</code> 패키지 등이 담겨 있다. 여기서 <code>next</code> 내부를 확인해 본다.  </p>
<h3 id="3-nextjspackagesnextlibcommandsts">(3) <a href="https://github.com/vercel/next.js/blob/canary/packages/next/lib/commands.ts">next.js/packages/next/lib/commands.ts</a></h3>
<pre><code class="language-typescript">export type cliCommand = (argv?: string[]) =&gt; void

export const commands: { [command: string]: () =&gt; Promise&lt;cliCommand&gt; } = {
  build: () =&gt; Promise.resolve(require(&#39;../cli/next-build&#39;).nextBuild),
  start: () =&gt; Promise.resolve(require(&#39;../cli/next-start&#39;).nextStart),
  export: () =&gt; Promise.resolve(require(&#39;../cli/next-export&#39;).nextExport),
  dev: () =&gt; Promise.resolve(require(&#39;../cli/next-dev&#39;).nextDev),
  lint: () =&gt; Promise.resolve(require(&#39;../cli/next-lint&#39;).nextLint),
  telemetry: () =&gt;
    Promise.resolve(require(&#39;../cli/next-telemetry&#39;).nextTelemetry),
  info: () =&gt; Promise.resolve(require(&#39;../cli/next-info&#39;).nextInfo),
}</code></pre>
<p><code>commands.ts</code> 파일에서 command가 나열되어 있는 것을 확인할 수 있었다. 그 중에서 <code>nextStart</code> 확인해보자. </p>
<h3 id="4-nextjspackagesnextclinext-startts">(4) <a href="https://github.com/vercel/next.js/blob/canary/packages/next/cli/next-start.ts">next.js/packages/next/cli/next-start.ts </a></h3>
<p><code>next-start.ts</code>에 <code>nextStart</code> 라는 함수가 선언되어 있었다. 함수의 구성은 아래와 같다. </p>
<h4 id="1-옵션-유효성-검사">1. 옵션 유효성 검사</h4>
<pre><code class="language-typescript">const validArgs: arg.Spec = {
    // Types
    &#39;--help&#39;: Boolean,
    &#39;--port&#39;: Number,
    &#39;--hostname&#39;: String,
    &#39;--keepAliveTimeout&#39;: Number,

    // Aliases
    &#39;-h&#39;: &#39;--help&#39;,
    &#39;-p&#39;: &#39;--port&#39;,
    &#39;-H&#39;: &#39;--hostname&#39;,
  }
  let args: arg.Result&lt;arg.Spec&gt;
  try {
    args = arg(validArgs, { argv })
  } catch (error) {
    if (isError(error) &amp;&amp; error.code === &#39;ARG_UNKNOWN_OPTION&#39;) {
      return printAndExit(error.message, 1)
    }
    throw error
  }</code></pre>
<p><code>arg</code>의 경우 <code>&#39;next/dist/compiled/arg/index.js&#39;</code>에서 import 해오는데, <code>next [command] [option]</code>의 형태로 받은 입력 및 여러 설정들을 처리한 것으로 보인다. 받은 입력이 정의된 형태로 들어왔는지 검사하는 부분이다.      </p>
<h4 id="2-help-옵션에-대한-처리">2. help 옵션에 대한 처리</h4>
<pre><code class="language-typescript">  if (args[&#39;--help&#39;]) {
    console.log(`
      Description
        Starts the application in production mode.
        The application should be compiled with \`next build\` first.
      Usage
        $ next start &lt;dir&gt; -p &lt;port&gt;
      &lt;dir&gt; represents the directory of the Next.js application.
      If no directory is provided, the current directory will be used.
      Options
        --port, -p      A port number on which to start the application
        --hostname, -H  Hostname on which to start the application (default: 0.0.0.0)
        --keepAliveTimeout  Max milliseconds to wait before closing inactive connections
        --help, -h      Displays this message
    `)
    process.exit(0)
  }</code></pre>
<p>--help 또는 -h 옵션이 있는 경우, <code>next start</code>에 대한 설명을 로그 찍고 실행을 종료한다. </p>
<h4 id="3-변수-선언">3. 변수 선언</h4>
<pre><code class="language-typescript"> const dir = getProjectDir(args._[0])
  const host = args[&#39;--hostname&#39;] || &#39;0.0.0.0&#39;
  const port = getPort(args)

  const keepAliveTimeoutArg: number | undefined = args[&#39;--keepAliveTimeout&#39;]
  if (
    typeof keepAliveTimeoutArg !== &#39;undefined&#39; &amp;&amp;
    (Number.isNaN(keepAliveTimeoutArg) ||
      !Number.isFinite(keepAliveTimeoutArg) ||
      keepAliveTimeoutArg &lt; 0)
  ) {
    printAndExit(
      `Invalid --keepAliveTimeout, expected a non negative number but received &quot;${keepAliveTimeoutArg}&quot;`,
      1
    )
  }

  const keepAliveTimeout = keepAliveTimeoutArg
    ? Math.ceil(keepAliveTimeoutArg)
    : undefined</code></pre>
<p>dir, host, port 등 서버 실행에 필요한 변수들 선언하고 있다. 
<code>keepAliveTimeout</code>은 프로세스 유지 시간으로, 값이 유효하지 않을 경우 에러메세지 프린트 후 종료한다.  </p>
<h4 id="4-startserver-실행">4. startServer 실행</h4>
<pre><code class="language-typescript">startServer({
    dir,
    hostname: host,
    port,
    keepAliveTimeout,
  })
    .then(async (app) =&gt; {
      const appUrl = `http://${app.hostname}:${app.port}`
      Log.ready(`started server on ${host}:${app.port}, url: ${appUrl}`)
      await app.prepare()
    })
    .catch((err) =&gt; {
      console.error(err)
      process.exit(1)
    })</code></pre>
<p><code>startServer</code> 함수는 <a href="https://github.com/vercel/next.js/blob/canary/packages/next/server/lib/start-server.ts"><code>start-server.ts</code> </a>에 정의되어 있다. </p>
<pre><code class="language-typescript">    const server = http.createServer((req, res) =&gt; {
        return requestHandler(req, res)
      })

    server.on(&#39;listening&#39;, () =&gt; {
      const addr = server.address()
      const hostname =
        !opts.hostname || opts.hostname === &#39;0.0.0.0&#39;
          ? &#39;localhost&#39;
          : opts.hostname

      const app = next({
        ...opts,
        hostname,
        customServer: false,
        httpServer: server,
        port: addr &amp;&amp; typeof addr === &#39;object&#39; ? addr.port : port,
      })

      requestHandler = app.getRequestHandler()
      upgradeHandler = app.getUpgradeHandler()
      resolve(app)
    })

    server.listen(port, opts.hostname)</code></pre>
<p><code>createServer</code>를 통해 <code>server</code>라는 웹 서버 객체를 생성했다. <code>next-start.ts</code> 에서 startServer를 호출하며 넘겨준 인자들로 세팅한 server를 실행한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[네트워크] HTTPS는 어떻게 동작할까?]]></title>
            <link>https://velog.io/@sohi_5/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-HTTPS%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EB%8F%99%EC%9E%91%ED%95%A0%EA%B9%8C</link>
            <guid>https://velog.io/@sohi_5/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-HTTPS%EB%8A%94-%EC%96%B4%EB%96%BB%EA%B2%8C-%EB%8F%99%EC%9E%91%ED%95%A0%EA%B9%8C</guid>
            <pubDate>Sat, 13 Jun 2020 00:37:05 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/sohi_5/post/b7512845-778c-4a60-9cf3-f8b59a3d97df/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-06-12%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.43.14.png" alt=""></p>
<h2 id="http와-데이터-유출-🧐">HTTP와 데이터 유출 🧐</h2>
<p>HTTPS는 HTTP의 보안이 강화된 버전이라고 설명할 수 있다. HTTPS를 설명하기에 앞서 HTTP를 간단히 정리하자면 <strong>HTML 같은 리소스들을 교환하기 위한 프로토콜</strong>이다. <strong>클라이언트는 서버에 데이터를 요청하고, 서버는 이에 대해 응답</strong>하는 구조를 갖는다. </p>
<p>HTTP를 통해 교환하는 데이터들은 <strong>텍스트</strong> 형태를 갖는다. 즉, 데이터가 전달되는 <strong>네트워크의 전송 신호를 인터셉트하면 데이터의 유출이 발생</strong>할 수 있다는 것이다. 이런 HTTP의 취약한 보안때문에 이를 막기위한 방법이 필요했고, 그 대안이 HTTPS이다.</p>
<p>현재 HTTP는 민감하지 않은 데이터를 다루는 사이트에서 사용되며, 인증이나 전자상거래 등의 데이터는 HTTPS로 다룬다. 그러나 보안에 대한 관심이 증가하여 HTTP를 사용하는 사이트를 브라우저에서 경고 메세지를 띄워주고 있으며, HTTPS로 대부분 전환해가는 추세이다.</p>
<h2 id="https">HTTPS</h2>
<p>그럼 HTTPS는 어떻게 동작하기에 HTTP의 보안을 강화할 수 있었는지 자세히 살펴보자. 일단 HTTPS의 핵심은 <strong>공개키 암호화 방식</strong>이다. 암호화와 복호화를 할 수 있는 2개의 키가 존재한다. 만약 1번 키로 데이터를 암호화 했다면, 다른 2번 키로만 복호화할 수 있다. 반대로 2번 키로 암호화 했다면, 1번 키로 복호화할 수 있는 방식이다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/059c4a9f-5a0f-482d-b524-e4f4bf731ea1/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-06-12%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%201.55.48.png" alt=""></p>
<p>생성된 2개의 키 중 하나는 공개 키 저장소에 존재한다. 또한 다른 하나는 서버가 소지하고 있다. </p>
<p><img src="https://images.velog.io/images/sohi_5/post/3a5ec351-03fa-4523-a53a-df8a2c4bbc56/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-06-12%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.56.41.png" alt="">
<img src="https://images.velog.io/images/sohi_5/post/ba4e9ebe-329c-455c-8756-cbd40a4b9047/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-06-12%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.54.15.png" alt=""></p>
<p>클라이언트가 서버에 데이터 처리를 요청할 때, 공개 키 저장소에 있던 키를 통해 데이터 암호화를 진행한다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/abeff6d8-4f1c-4b3b-9ecf-a687273eb0db/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-06-12%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.59.48.png" alt=""></p>
<p>공개 키를 통해 암호화 된 데이터를 포함하는 HTTPS 요청이 들어오면, 서버는 이에 대응하는 다른 키를 통해 복호화를 진행한다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/308319d7-dffe-49cf-9b74-2742192da3f0/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-06-12%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.04.09.png" alt=""></p>
<p>복호화된 데이터를 가지고 클라이언트의 요청을 처리하고 다시 클라이언트에 서버가 가진 키를 통해 암호화를 진행한 결과를 응답한다. 클라이언트는 이를 다시 공개 키를 통해 복호화를 진행해 데이터를 얻는다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[네트워크] HTTP부터 WebSocket까지 🚀]]></title>
            <link>https://velog.io/@sohi_5/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-HTTP%EB%B6%80%ED%84%B0-WebSocket%EA%B9%8C%EC%A7%80</link>
            <guid>https://velog.io/@sohi_5/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-HTTP%EB%B6%80%ED%84%B0-WebSocket%EA%B9%8C%EC%A7%80</guid>
            <pubDate>Tue, 02 Jun 2020 00:01:39 GMT</pubDate>
            <description><![CDATA[<h2 id="http-이전의-통신-😬">HTTP 이전의 통신 😬</h2>
<p>HTTP가 등장하기 이전의 통신은 불편한 터미널을 통해 텍스트를 주고 받는 정도였다. 지금처럼 예쁜 디자인에 역동적인 애니메이션의 웹 페이지는 상상조차 할 수 없었다.</p>
<h2 id="1989년-http의-등장">1989년, HTTP의 등장</h2>
<blockquote>
<p>Hyper Text Transfer Protocol. WWW 상에서 HTML 문서같은 리소스들의 교환을 위한 프로토콜.</p>
</blockquote>
<p>HTTP의 등장으로 터미널을 통한 딱딱한 텍스트 교환을 벗어나, HTML같이 멋진 문서를 주고 받을 수 있게 되었다. 시각적으로 크게 변화하였고, 전달하는 정보량 또한 훨씬 증가하게 되었다.</p>
<p>HTTP의 핵심은 <strong>사용자는 URL을 통해 원하는 페이지를 서버에 요청, 서버는 이에 응답</strong>한다는 것이다. 즉, URL을 이동하면 사용자의 웹 브라우저는 서버에 해당 URL에 해당하는 웹페이지를 요청한다. 서버가 응답한 HTML 문서를 브라우저가 그려낸다. </p>
<h3 id="🚨-http의-한계">🚨 HTTP의 한계</h3>
<p>언급했던 HTTP의 핵심 중 <strong>URL을 통해 서버에 요청</strong> 부분에 집중해보자. <em>서버에 요청하려면 URL을 이용하는게 당연한거 아닌가?</em> 라는 생각이 들 수 있겠지만 이전에는 지금과 상황이 달랐다. 예를 들어보자면, 회원가입 페이지가 있다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/d340de32-4beb-4f5c-af98-0f12fa65a534/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-06-01%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2011.41.11.png" alt=""></p>
<p>지금처럼 크롬같은 브라우저를 사용하던 시기가 아닌, 거의 모든 이들이 인터넷 익스플로러를 사용하던 시기의 웹사이트 회원가입 페이지를 떠올려보자. 아이디 중복 검사를 위해 버튼을 누르면, 항상 새로운 창이 생겼던 것이 기억이 날 것이다. </p>
<p>이유는 위에서 언급한 <strong>URL을 통해 서버에 요청</strong> 한다는 규약 때문이다. 사용자가 URL을 요청한다는 것은, 브라우저에서는 <em>페이지의 이동이 발생함</em>을 의미하는 것이다. 회원가입을 진행하다가 아이디 중복 검사를 하기 위해서 페이지가 이동되면, 돌아와서 모든 정보를 다시 입력해야할 것이다.</p>
<h3 id="꼼수의-등장-🎮">꼼수의 등장 🎮</h3>
<p>Flash, ActiveX, 실버라이트 등 영상이나 플래시 게임 등을 하며 봤던 이름들이 여기서 등장한다. 플래시 게임을 하며 클릭 한 번으로 웹 페이지 이동이 한 번씩 발생했기에 아주아주 불편했다. ActiveX 같은 런타임 환경을 플러그인 형태로 제공하여 이런 불상사를 해결했었다. 하지만 근본적인 해결은 아니었기에 새로운 해결 방법이 필요했다. </p>
<h2 id="구글-맵과-ajax">구글 맵과 AJAX</h2>
<p>구글은 2004년과 2005년에 각각 Gmail과 구글 맵을 발표한다. 여기서 화제가 된 것은 두 서비스가 플러그인이 아닌 AJAX라는 기술로 구현되었다는 것이다. 특히 지도 서비스는 필수적으로 ActiveX 같은 플러그인을 통해 구현해왔기에 큰 혁신이었다. 물론 이전에도 비슷하게 구현된 바 있었으나, 본격적으로 사용된 것은 이때부터라고 한다. </p>
<p>AJAX는 HTTP처럼 통신 규약을 지정한 프로토콜은 아니다. HTTP를 효과적으로 사용할 수 있는 기술이다. 때문에 아까 언급한 HTTP 흐름과 유사하다. </p>
<p><img src="https://images.velog.io/images/sohi_5/post/b6982502-7533-40ad-b7d9-3f82e1463fc6/image.png" alt="">
먼저 AJAX 이전의 HTTP 통신이다. 요청 페이지에서 확인 버튼을 누르면 브라우저는 서버에 데이터를 전달하고, 서버는 이를 받아 처리한 뒤 새로운 HTML 문서를 브라우저에 전달한다. 이 과정에서 <strong>페이지 이동</strong>이 발생한다. </p>
<p><img src="https://images.velog.io/images/sohi_5/post/d55756f8-cecd-4f94-8be8-72bb712ae795/image.png" alt="">
AJAX를 활용한 통신 흐름이다. 위와 동일하게 요청 페이지에서 내용을 입력한 뒤 확인 버튼을 누르면 JS는 DOM을 읽고, XMLHttpRequest 객체를 통해 서버에 이를 전달한다. 서버는 받은 요청을 처리하고 XML/JSON 등의 데이터를 다시 XMLHttpRequest 객체에 전달한다. HTML을 교체하는 것이 아닌, <strong>DOM을 수정</strong>하여 결과 페이지가 만들어진다. 다시 말해 페이지 이동이 발생하지 않고, 페이지 내부의 일부만 변화하는 것이다.</p>
<ul>
<li>AJAX는 HTTP를 효과적으로 사용할 수 있는 기술이다.</li>
<li>HTTP는 브라우저가 서버에 요청하지만, AJAX는 XMLHttpRequest 객체가 요청한다.</li>
<li>서버는 HTML 문서가 아닌, XML/JSON 형태를 반환하기에 페이지 이동 없이 페이지 내에서 변경 가능하다.</li>
</ul>
<h3 id="🚨-ajax의-한계">🚨 AJAX의 한계</h3>
<p>AJAX는 현재 사용하는 주 통신 방법인데, 무엇이 문제일까? 예를 들어보자면 채팅이 있다. 채팅은 실시간으로 나에게 온 채팅이 있는지 확인할 수 있어야 한다. 그러나 서버에서 데이터를 보내기 위해서는 <strong>클라이언트의 요청이 필수</strong>이다. 만약 이를 AJAX(HTTP)로 구현한다면, 몇 초 간격으로 서버에 요청을 보내 확인하거나, 서버에 연결된 시간을 늘리는 등의 방법이 있을 것이다. 하지만 너무 많은 요청은 과부하를 일으키며, 동시에 수많은 사용자의 접속 어려움 등 문제점이 발생하기에 <strong>클라이언트의 요청이 없음에도 서버에게 응답을 받을 수 있는 새로운 해결 방안</strong>이 필요했다.</p>
<h2 id="websocket의-등장-🚀">WebSocket의 등장 🚀</h2>
<p><img src="https://images.velog.io/images/sohi_5/post/6403c1c3-7f0b-416b-9586-063741fa7913/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-06-01%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.20.45.png" alt="">
앞서 살펴본 HTTP(AJAX)는 이러한 구조를 가지고 있다. 클라이언트의 리퀘스트가 발생해 서버가 이를 수신하고 해당 요청을 처리한 뒤, 결과를 다시 클라이언트에 반환하며 연결은 끊어지게 된다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/97325ad3-c9ee-4627-9216-94c91a73b6a2/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-06-01%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.22.41.png" alt="">
웹소켓은 이와 조금 다르다. 클라이언트는 요청을 하고, 서버는 응답을 하는 구조는 변하지 않으나, 통신의 흐름이 클라이언트에 의해 결정되었다면, 웹소켓은 양방향 소통이 가능하다. 클라이언트의 요청이 없이도 서버는 언제든 응답을 할 수 있고 응답이 발생한 이후에도 지속적으로 연결을 유지하는 연결 지향형 특성을 갖는다. </p>
<ul>
<li>지속적으로 연결을 유지하며, 연결 지향형이다.</li>
<li>클라이언트의 요청없이도 서버가 응답 가능한 양방향 통신 프로토콜이다.</li>
<li>접속 확립에는 HTTP가 사용되며, 이후에는 WebSocket이 독자적으로 사용된다.</li>
</ul>
<p>웹소켓은 채팅처럼 실시간으로 양방향 데이터 통신이 필요하거나, 많은 수의 동시 접속자를 수용해야할 때 사용된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[컴퓨터 구조] 캐리와 오버플로우 확실하게 구분하기]]></title>
            <link>https://velog.io/@sohi_5/%EC%BA%90%EB%A6%AC%EC%99%80-%EC%98%A4%EB%B2%84%ED%94%8C%EB%A1%9C%EC%9A%B0-%ED%99%95%EC%8B%A4%ED%95%98%EA%B2%8C-%EA%B5%AC%EB%B6%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@sohi_5/%EC%BA%90%EB%A6%AC%EC%99%80-%EC%98%A4%EB%B2%84%ED%94%8C%EB%A1%9C%EC%9A%B0-%ED%99%95%EC%8B%A4%ED%95%98%EA%B2%8C-%EA%B5%AC%EB%B6%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 14 May 2020 15:20:19 GMT</pubDate>
            <description><![CDATA[<p>컴퓨터 구조에 대해 조금이라도 배운 사람이라면 캐리와 오버플로우에 대해 떠오르는 것이 있을 것이다. 캐리는 아마 가산기가 떠오르지 않을까 생각된다. 이진수 1과 1을 더하면 출력(S)은 0, 자리올림이 발생해 캐리(C)는 1이 세팅되는 것이 기억날 것이다. 오버플로우는 개발하면서 정말 많이 들어봤을 것이다. 말 그대로 표현할 수 있는 값 범위를 넘어서다 라고 이해하고 있을 것이다. </p>
<p>캐리와 오버플로우에 대해 한 종류의 레지스터를 바탕으로 자세히 설명해보고자 한다. 레지스터는 프로세서 내부에서 데이터를 일시적으로 저장하는 아주 빠른 기억 장소이다. 다양한 레지스터 중에서, 특수 레지스터인 <strong>상태 레지스터</strong>를 알아보자.</p>
<hr>
<h2 id="상태-레지스터">상태 레지스터</h2>
<p><img src="https://images.velog.io/images/sohi_5/post/fa2e26fb-1ae7-40c8-9f63-578d0774c7d3/image.png" alt="출처: https://kimhyun2017.tistory.com/124">
상태 레지스터는 마이크로 프로세서에 탑재되는 레지스터이다. 이미지를 자세히 들여다보면 32개의 비트, 즉 4 byte 크기인 것을 알 수 있다. 각 비트는 <strong>다양한 산술 연산 결과 상태</strong>를 저장한다. 크게 제어 플래그와 조건 플래그로 나뉘는데, 이중 우리가 집중할 것은 조건 플래그의 오버플로우 플래그와 캐리 플래그이다.</p>
<p>먼저 오버플로우 플래그는 말 그대로 오버플로우 발생 시 Set 될 것이라고 예상할 수 있다. 마찬가지로 캐리 플래그 또한 자리 올림이 발생하면 Set이 될 것으로 예상된다. 2가지 상황의 플래그 상태를 예측해보도록 하자.</p>
<hr>
<h2 id="플래그-상태-예측하기">플래그 상태 예측하기</h2>
<h3 id="🔎-1">🔎 1</h3>
<p><img src="https://images.velog.io/images/sohi_5/post/915cd482-699e-44b5-aa44-1b4ecc85fef1/image.png" alt=""></p>
<p>첫 번째, <code>이진수 1111과 0001의 더하기 연산</code>이다. 결과 값은 <code>10000</code>으로 쉽게 계산할 수 있다. 그러나 4 bit 연산인데 결과 값은 5 bit로 <strong>표현할 수 있는 범위를 넘겼다.</strong> 이는 오버플로우가 발생한 것이므로 레지스터의 상태는 다음과 같이 예측할 수 있다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/b5b1642d-f39a-423b-9566-7e8fe4b31e52/image.png" alt=""></p>
<h3 id="🔎-2">🔎 2</h3>
<p><img src="https://images.velog.io/images/sohi_5/post/54796af4-70a5-44f6-bf83-f97c3438e0f6/image.png" alt=""></p>
<p>두 번째, <code>이진수 0111과 0001의 더하기 연산</code>이다. 결과 값은 <code>1000</code>으로, 오버플로우는 발생하지 않았다. 대신 자리 올림이 발생했으므로 캐리 플래그가 Set 될 것이다. </p>
<p><img src="https://images.velog.io/images/sohi_5/post/b334551b-d5bf-4cf8-bfb4-7ed7835cacc9/image.png" alt=""></p>
<hr>
<h2 id="진짜-플래그-상태">진짜 플래그 상태</h2>
<h3 id="🔎-1-1">🔎 1</h3>
<p><img src="https://images.velog.io/images/sohi_5/post/96a5cbc8-bc97-41ae-a164-81c538c80c60/image.png" alt=""></p>
<p><code>10000</code>은 표현 범위를 넘겼기 때문에 위에서 오버플로우 플래그 Set으로 예상했지만, 이 경우에는 캐리 플래그가 Set된다. </p>
<p><img src="https://images.velog.io/images/sohi_5/post/5ea211f7-b206-41b9-9a74-ace689e57453/image.png" alt=""></p>
<p><code>10000</code>은 1이 무시되지만 캐리가 일어난 것은 맞기 때문에 캐리 플래그가 Set 된다. 하지만 오버플로우 플래그가 Set 되지 않는 것은 결국 결과는 <code>0</code>으로, 하위 4 bit가 알맞은 값을 제대로 표현하고 있기 때문이다. 따라서 이 경우 캐리가 발생한 것이고, 오버플로우는 발생하지 않았다.
<img src="https://images.velog.io/images/sohi_5/post/91a443dc-c36e-4661-9c94-925aad714f73/image.png" alt=""></p>
<h3 id="🔎-2-1">🔎 2</h3>
<p><img src="https://images.velog.io/images/sohi_5/post/14d64760-9d3d-4202-87a7-5ca1b418f77b/image.png" alt="">
<code>0111 + 0001</code>의 연산으로 0이었던 최상단이 1로 바뀌었기 때문에 캐리의 발생으로 오해할 수 있다. 하지만 <strong>캐리 플래그는 최상단 비트에서 캐리가 발생했을 때 Set된다.</strong> 이 경우에서는 최상단 비트에서는 캐리가 발생하지 않고 있기 때문에 캐리 플래그는 Set되지 않는다. 대신 오버플로우 플래그가 Set되는데, 이유는 부호이다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/3c75f1fd-f205-40a0-8ae4-71a2cd51ba1b/image.png" alt="">
양수인 <code>7</code>과 <code>1</code>을 더하는 연산의 결과가 <code>-8</code>이기 때문이다. 4 bit 이진수가 표현 가능한 범위는 7 ~ -8 로, 올바른 결과인 <code>8</code>은 애초에 나타낼 수 없는 값이 아니라서 잘못된 결과가 나타난다. 즉, <strong>부호가 있는 연산에서 최대표현 숫자를 넘어서서 잘못된 결과가 나타난 경우</strong> 오버플로우 플래그가 Set 되는 것이다. 오버플로우 여부는 <strong>같은 부호를 더했을 때, 다른 부호가 나오는 것으로도 인지</strong>할 수 있다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/0de9ff99-cf09-44d2-9c6c-e83db88d6a34/image.png" alt=""></p>
<hr>
<h2 id="정리">정리</h2>
<blockquote>
<p>상태 레지스터의 캐리 플래그는 최상단 비트에서 자리올림 발생 시 Set</p>
</blockquote>
<blockquote>
<p>상태 레지스터의 오버플로우 플래그는 최대 표현 숫자를 넘기거나, 같은 부호를 더했을 때의 결과가 다른 부호 일 시 Set</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[운영체제] Context Switching]]></title>
            <link>https://velog.io/@sohi_5/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-Context-Switching-suaduxev</link>
            <guid>https://velog.io/@sohi_5/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-Context-Switching-suaduxev</guid>
            <pubDate>Thu, 07 May 2020 15:42:12 GMT</pubDate>
            <description><![CDATA[<h2 id="프로세스와-pcb">프로세스와 PCB</h2>
<p>먼저 프로세스란 <code>실행중인 프로그램 또는 작업</code>이라고 할 수 있다. CPU가 프로세스를 실행하기 위해서는 프로세스에 대한 정보가 필요한데, 이를 Context라고 한다. 각 프로세스의 Context를 저장한 공간을 PCB라고 한다.</p>
<h3 id="pcb-process-control-block">PCB (Process Control Block)</h3>
<p>PCB는 운영체제의 커널 내부에 존재한다. 또한, 각 프로세스의 생성과 동시에 생성되며, 프로세스 종료 시 함께 사라진다. </p>
<p><img src="https://images.velog.io/images/sohi_5/post/c54829db-134a-479c-b1ec-ac97174db1a6/image.png" alt="PCB">
위 이미지는 PCB 구조를 나타내고 있다. PCB는 다음과 같은 정보를 보유한다.</p>
<blockquote>
<p>1) 프로세스 식별자(Process ID)
2) 프로세스 상태(Process State) : 생성(create), 준비(ready), 실행 (running), 대기(waiting), 완료(terminated) 
3) 프로그램 계수기(Program Counter) : 이 프로세스가 다음에 실행할 명령어의 주소
4) 사용 중인 레지스터 정보
5) CPU 스케줄링 정보 : 우선 순위, 최종 실행시각, CPU 점유시간 등
6) 메모리 관리 정보(Memory limits) : 사용 가능한 메모리 공간 정보
7) 입출력 상태 정보 : 프로세스에 할당된 입출력장치 목록, 사용 파일 목록 등
8) 포인터 : 부모 프로세스에 대한 포인터, 자식 프로세스에 대한 포인터, 프로세스가 위치한 메모리 주소에 대한 포인터, 할당된 자원에 대한 포인터 정보</p>
</blockquote>
<h2 id="컨텍스트-스위칭-context-switching">컨텍스트 스위칭 (Context Switching)</h2>
<blockquote>
<p>CPU가 실행하는 프로세스가 교체되며 CPU에서 관리하는 Context가 교체되는 것을 컨텍스트 스위칭이라고 한다.</p>
</blockquote>
<p>먼저, CPU가 실행중인 프로세스의 Context는 해당 PCB에서 정보를 읽어와 CPU 내부의 레지스터가 관리한다. 그러다가 <code>인터럽트</code>가 발생하게 되면 해당 프로세스의 실행을 중지하게 된다. 인터럽트는 <code>입출력 요청, CPU 사용 시간 만료, 자식 프로세스 생성, 인터럽트 처리 대기</code> 등에 의해 발생하게 된다. </p>
<p>인터럽트가 발생하면 스케줄러에 의해 다음 프로세스가 실행이 되어야 한다. 다음 프로세스에게 차례를 넘겨주기 위해, 레지스터에서 다뤘던 종료될 프로세스의 Context를 PCB에 업데이트하게 된다. 이후에 다음 프로세스의 Context를 PCB에서 메인 메모리로 올리게 되고 CPU가 실행할 수 있게되는 것이다. </p>
<p>컨텍스트 스위칭을 통해 멀티프로세싱, 멀티스레딩을 구현할 수 있다. 그러나 Context 교체를 하는 동안 프로세스가 실행될 수 없으므로, 잦은 컨텍스트 스위칭은 오버헤드를 발생시켜 CPU의 성능을 저하시킬 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[자료구조와 알고리즘] DFS (깊이 우선 탐색)]]></title>
            <link>https://velog.io/@sohi_5/algorithmDFS</link>
            <guid>https://velog.io/@sohi_5/algorithmDFS</guid>
            <pubDate>Tue, 21 Apr 2020 10:58:25 GMT</pubDate>
            <description><![CDATA[<h2 id="프로그래머스-깊이너비-우선-탐색">프로그래머스 깊이/너비 우선 탐색</h2>
<p>2학년 1학기, 동아리에서 진행하는 알고리즘 스터디에서 DFS 문제를 선정한 적이 있었다. &lt;여행경로&gt;라는 문제였는데, 많이 헤맸고 결국 일주일 내에 해결하지 못한 것이 기억난다. 그 때 그저 &quot;내 실력이 아직 많이 모자라구나&quot;라고 생각했다. 알고리즘 문제를 풀어본 경험이 적기도 했지만, 알고리즘 공부는 전혀하지 않은 채 무작정 문제만 해결하려고 하니 벅찬 게 당연하다. 그때 풀지 못했던 DFS/BFS 문제를 해결하기 위해 제대로 공부하려고 한다.</p>
<h2 id="dfs와-bfs를-알기전에-그래프란">DFS와 BFS를 알기전에, 그래프란?</h2>
<h3 id="그래프">그래프</h3>
<blockquote>
<p>단순히 노드와 그 노드를 연결하는 간선을 하나로 모아놓은 비선형 자료구조</p>
</blockquote>
<p>아주 어려운 말은 아니지만 역시 그림으로 이해하는 것이 빠르다 😋</p>
<p><img src="https://images.velog.io/images/sohi_5/post/0c5a46f8-e8c5-4d51-831d-8d00db917916/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-04-21%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%201.03.42.png" alt=""></p>
<p>사진 속 3가지 종류 모두 그래프로, 다양한 형태를 가질 수 있다. 우리가 잘 알고있는 트리 또한 그래프 중 하나이며, 특별한 케이스이다. 즉, 그래프는 <code>연결된 객체 간의 관계를 표현하는 자료구조</code>라고 할 수 있겠다. 방향 그래프와 무방향 그래프로 나눌 수 있는데, 더 자세한 내용은 추가로 포스팅하려고 한다.</p>
<h3 id="그래프-탐색">그래프 탐색</h3>
<blockquote>
<p>그래프 탐색이란 하나의 정점으로부터 시작해 차례대로 모든 정점들을 한 번씩 방문하는 것이다. </p>
</blockquote>
<p>이 글에서 설명하려는 DFS(Depth-First Search)는 그래프 탐색이다. 추후에 다룰 예정인 BFS(Breadth-First Search) 또한 마찬가지이다. 이외에도 다익스트라(Dijkstra), 플로이드 와샬(Floyd Washall)이 있다. 각 탐색 기법은 상황에 맞춰 적절한 것을 사용한다.</p>
<h2 id="깊이-우선-탐색-dfsdepth-first-search">깊이 우선 탐색 DFS(Depth-First Search)</h2>
<p><img src="https://images.velog.io/images/sohi_5/post/221b5009-1002-468c-a68a-415ef78c3cdf/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%206.37.06.png" alt=""></p>
<p>DFS 과정에 대해 자세히 설명하기 전, 이 이미지를 통해 간략히 알아보자. 노드 1을 시작으로 차례대로  노드 9까지 순회한다. 진행되는 방향을 보면 한 가지의 끝까지 탐색하고, 그 다음 가지를 순차적으로 탐색한다. 전체적 위에서 아래로 <code>깊게</code> 탐색이 진행되는 것을 볼 수 있다.</p>
<blockquote>
<p>DFS란 특정 노드에서 시작해 다음 분기로 넘어가기 전에 해당 분기를 완벽하게 탐색하는 방법이다.</p>
</blockquote>
<p>예를 들면, 미로에서 한 루트로 계속 가다가 막다른 길이면 바로 직전 갈림길로 돌아가 길을 찾는 것이라고 할 수 있다. 깊이 우선 탐색은 전체 노드를 맹목적으로 탐색할 때 사용한다. 깊이 우선 탐색의 구현에서 중요한 것은 <strong>스택</strong>이다.</p>
<h3 id="과정">과정</h3>
<p>위에서 사용한 트리형태의 그래프의 과정을 자세히 설명하고자 한다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/fcbdab2d-9cc6-4bb9-8ec7-7bb28be3bf1c/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.05.28.png" alt="">
트리의 루트 노드인 노드 1을 기준으로 탐색을 시작한다. 스택 노드 1을 넣는다. 노드 1과 연결된 노드 중 방문하지 않은 노드가 있는지 확인한다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/19026fa3-779d-43db-95e6-2438c48496fd/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.09.37.png" alt="">
아직 방문하지 않은 노드 2를 스택에 넣어준다. 다시 노드 2와 연결된 노드 중 방문하지 않은 노드가 있는지 확인한다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/ecaacfa5-eb94-4177-9f40-70f0f810c22c/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.13.17.png" alt="">
노드 3을 스택에 넣어주고, 연결된 노드 중 방문하지 않은 노드가 있는지 확인한다. </p>
<p><img src="https://images.velog.io/images/sohi_5/post/06c1ccf6-383f-4dda-a3ba-b1bd4d4c05af/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.15.53.png" alt="">
그러나 노드 3과 연결된 노드는 노드 2뿐이며, 이미 방문했으므로 이번 분기의 탐색이 완료된 것이기 때문에 노드 3을 스택에서 빼낸다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/0760b6ed-bfe7-4746-a7e7-79ffeedc004d/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%20%EB%85%B87.17.13.png" alt="">
스택의 가장 위에 위치한 노드 2와 연결된 아직 방문하지 않은 노드가 있는지 확인한다. 그러나 존재하지 않기 때문에 노드 2를 스택에서 빼낸다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/c53e8fd8-0c9a-4e2e-89c3-3b9cc7771b46/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.19.03.png" alt="">
앞의 과정을 계속 반복한다. 노드 1과 연결된 노드 중 방문하지 않은 노드 4를 스택에 추가하고, 노드 4와 연결된 노드 5를 다시 스택에 추가한다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/7fc2bf38-288b-4e0c-9553-0f9150a43f57/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.20.48.png" alt="">
노드 5와 연결된 노드를 확인하고 방문하지 않은 노드 6을 스택에 추가한다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/209c03f6-77bd-4a35-ac8b-63d35ad7467f/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.23.03.png" alt="">
노드 6와 연결된 노드를 확인한다. 방문하지 않은 노드가 없으므로 스택에서 제거한다. 노드 5도 마찬가지로 스택에서 제거한다. 노드 4와 연결된 또다른 노드를 확인한다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/2d80c51f-03a6-46c1-ac88-8431e9ea00b8/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.25.14.png" alt="">
노드 7을 스택에 추가한다. 연결된 노드 중 방문하지 않은 것이 없으므로 스택에서 제거하고, 노드 4 또한 모두 방문했으므로 스택에서 제거한다. </p>
<p><img src="https://images.velog.io/images/sohi_5/post/2d31b1d2-f0d0-4455-968c-53767b6f78d7/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.26.57.png" alt="">
노드 1과 연결된 마지막 노드 8을 스택에 추가하고, 다음 노드를 탐색한다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/5226b43e-219f-4f29-a4fe-a30cb8f43d26/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.29.24.png" alt="">
노드 9를 스택에 추가한다. 방문할 노드가 없으며, 노드 8 또한 마찬가지 이므로 스택에서 제거한다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/00d332f2-dc0d-4666-9c35-06d7364c03cd/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.30.47.png" alt="">
방문하지 않은 노드가 더이상 존재하지 않기 때문에 노드 1을 스택에서 제거해 탐색을 마친다.</p>
<h2 id="👑-프로그래머스-문제에-적용해보자">👑 프로그래머스 문제에 적용해보자</h2>
<p>프로그래머스의 DFS 문제의 풀이를 가볍게 해보려고 한다. 물론 문제에 대한 해결방법은 다양하니 그 중 하나로 여기길 바란다.</p>
<p>1) 여행경로
<img src="https://images.velog.io/images/sohi_5/post/de43125e-6e71-4ef6-9d68-c58e7a94a734/image.png" alt=""></p>
<p>주어지는 tickets가 <code>[[&quot;ICN&quot;,&quot;A&quot;],[&quot;B&quot;,&quot;ICN&quot;],[&quot;C&quot;,&quot;B&quot;],[&quot;B&quot;,&quot;C&quot;],[&quot;B&quot;,&quot;ICN&quot;]]</code> 이라면, 아래의 형태로 나타낼 수 있다.</p>
<p><img src="https://images.velog.io/images/sohi_5/post/1b1fdbf0-9849-4b50-9cfd-fc2be8b4bff2/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202020-04-21%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%207.48.19.png" alt=""></p>
<p>이 문제는 ICN 노드를 루트 노드로 하여, 깊이 우선 탐색을 적용해 모든 티켓을 사용하는 방법을 찾아낼 수 있다. ICN 노드에서 A 노드를 먼저 방문하면 나머지 노드를 방문할 수 없으므로 답이 될 수 없다. 다음 분기에 B 노드를 먼저 방문하여 모든 티켓을 사용할 수 있으므로 <code>[&quot;ICN&quot;, &quot;B&quot;, &quot;C&quot;, &quot;B&quot;, &quot;ICN&quot;, &quot;A&quot;]</code>가 답이 될 것이다.</p>
]]></description>
        </item>
    </channel>
</rss>