<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.3">Jekyll</generator><link href="https://xohw91.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://xohw91.github.io/" rel="alternate" type="text/html" /><updated>2024-01-24T05:48:06+00:00</updated><id>https://xohw91.github.io/feed.xml</id><title type="html">말랑말랑 개발일기</title><subtitle>아직은 왕감자🥔 개발자</subtitle><author><name>XOHW Note</name><email>so91062412@gmail.com</email></author><entry><title type="html">[HTTP] HTTP Header</title><link href="https://xohw91.github.io/HTTP-Header/" rel="alternate" type="text/html" title="[HTTP] HTTP Header" /><published>2024-01-24T00:00:00+00:00</published><updated>2024-01-24T00:00:00+00:00</updated><id>https://xohw91.github.io/HTTP%20Header</id><content type="html" xml:base="https://xohw91.github.io/HTTP-Header/"></content><author><name>XOHW Note</name><email>so91062412@gmail.com</email></author><summary type="html"></summary></entry><entry><title type="html">[Server] 서버이전 후 hosts파일 수정하는 이유?</title><link href="https://xohw91.github.io/Windows-hosts-update/" rel="alternate" type="text/html" title="[Server] 서버이전 후 hosts파일 수정하는 이유?" /><published>2024-01-24T00:00:00+00:00</published><updated>2024-01-24T00:00:00+00:00</updated><id>https://xohw91.github.io/Windows-hosts-update</id><content type="html" xml:base="https://xohw91.github.io/Windows-hosts-update/">&lt;h1 id=&quot;️hosts-파일이란&quot;&gt;✏️hosts 파일이란?&lt;/h1&gt;

&lt;p&gt;Windosw의 hosts 파일은 호스트 이름과 IP 주소 간의 매핑 정보를 지정하는 운영체제의 설정 파일이다.
이 파일을 사용하여 특정 도메인 이름을 직접 지정된 IP 주소로 해석하도록 설정할 수 있는데
이는 일종의 로컬 DNS 매핑을 제공하여 특정 도메인을 특정 IP 주소로 해석하도록 강제할 수 있도록 하는 방법이다.&lt;/p&gt;

&lt;p&gt;서버를 새로 바꾼 후 새 서버의 IP 주소를 해당 도메인과 매핑하려면 hosts 파일을 수정해야 하는데, 
예를 들어 만약 “example.com”이라는 도메인을 새 서버의 IP 주소로 연결하려면 다음과 같이 hosts 파일을 수정할 수 있다.&lt;/p&gt;

&lt;h4 id=&quot;호스트-파일-수정하는-방법&quot;&gt;&lt;strong&gt;호스트 파일 수정하는 방법&lt;/strong&gt;&lt;/h4&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;호스트 파일 찾기 및 열기 
  C:\Windows\System32\drivers\etc\hosts 
  호스트 파일을 관리자 권한으로 실행 &amp;gt; 편집기로 열어서 수정해야 함.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;호스트 파일 편집
  호스트 파일에는 각 줄에 IP 주소와 호스트 이름이 공백으로 구분되어 있다.
  ex ) 203.0.113.10   example.com
  왼쪽은 새 서버의 실제 IP 주소이고, “example.com”은 새로 설정하려는 도메인이다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;저장 및 종료
  파일을 저장한 후에 편집기를 종료하면 끝.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;이렇게 수정하면 해당 도메인에 대한 요청은 로컬시스템에서 설정한 IP주소로 전송된다. 
이는 특정 도메인을 임시로 새 서버로 라우팅하고자할 때 유용하지만 로컬 시스템에만 영향을 미치며 외부에서는 변경되지 않기때문에
실제로 도메인을 변경하려면 DNS 레코드를 새로운 서버 IP주소로 업데이트 해야 한다.&lt;/p&gt;

&lt;h4 id=&quot;서버-이전-후에-hosts-파일을-수정하는-이유는&quot;&gt;&lt;strong&gt;서버 이전 후에 hosts 파일을 수정하는 이유는?&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;DNS(Domain Name System)의 캐시 문제를 우회하고 빠르게 도메인이 새 서버로 연결되도록 하는 것이 주목적이다.
DNS는 도메인 이름을 IP주소로 해석하는 역할을 한다. 즉, 사용자가 특정 도메인을 방문하면 브라우저나 운영체제는 DNS 서버에 해당 도메인의 IP주소를 물어보면 이때 얻은 IP주소를 이용하여 실제 서버에 접속하게 되는 것이다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;서버를 이전하면 기존 DNS 캐시에는 이전 서버의 IP주소가 남아 있을 수 있기 때문에 새 서버로의 빠른 연결이 어려울 수 있다.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;그래서 hosts 파일을 수정하면 로컬 시스템에서 직접 도메인과 IP주소를 매핑함으로써 DNS 서버를 우회하고, 빠르게 새로운 서버로 연결할 수 있는 것이다.&lt;/p&gt;

&lt;p&gt;⚠️주의할 점은 이 작업은 로컬 시스템에만 영향을 미치며 다른 사용자나 외부에서는 변경이 반영되지 않는다는 것.
전체적인 DNS 레코드 업데이트가 완료되면 해당 작업은 필요없어지며 일정 시간이 지난 후에는 DNS 변경이 전파되어 모든 사용자가 새 서버로 연결될 것이다.&lt;/p&gt;

&lt;h4 id=&quot;dns-서버-domain-name-system-server-&quot;&gt;&lt;strong&gt;DNS 서버 (Domain Name System Server) ?&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;DNS 서버는 도메인 이름을 해당 도메인에 대응하는 IP 주소로 변환하는 역할을 한다. 이 서버는 전 세계에 분산되어 있으며, 인터넷 사용자가 도메인 이름을 입력하면 해당 도메인에 대한 IP 주소를 찾아주는 역할을 하게 된다.&lt;/p&gt;

&lt;h4 id=&quot;dns-레코드-dns-record-&quot;&gt;&lt;strong&gt;DNS 레코드 (DNS Record) ?&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;DNS 서버는 도메인에 대한 정보를 담고 있는 레코드를 가지고 있는데 이 레코드에는 도메인의 IP 주소, 메일 서버 정보 등이 포함되어 있다.&lt;/p&gt;</content><author><name>XOHW Note</name><email>so91062412@gmail.com</email></author><summary type="html">✏️hosts 파일이란?</summary></entry><entry><title type="html">[Issue] HttpServletResponse</title><link href="https://xohw91.github.io/Issue-HttpServletResponse/" rel="alternate" type="text/html" title="[Issue] HttpServletResponse" /><published>2024-01-22T00:00:00+00:00</published><updated>2024-01-22T00:00:00+00:00</updated><id>https://xohw91.github.io/%5BIssue%5DHttpServletResponse</id><content type="html" xml:base="https://xohw91.github.io/Issue-HttpServletResponse/">&lt;h1 id=&quot;️-httpservletresponse-&quot;&gt;✏️ HttpServletResponse ?&lt;/h1&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpServletResponse&lt;/code&gt;는 서블릿 컨테이너에서 클라이언트로부터의 HTTP 요청에 대한 응답을 생성하는 데 사용되는 객체이다. 클라이언트로 데이터를 보내거나, 응답 헤더를 설정하거나, 리다이렉션을 수행하는 데에 활용된다.&lt;/p&gt;

&lt;h4 id=&quot;알아야-할-주요-개념&quot;&gt;&lt;strong&gt;알아야 할 주요 개념&lt;/strong&gt;&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;응답 생성 및 전송 :&lt;/strong&gt;  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpServletResponse&lt;/code&gt;는 클라이언트로 응답을 생성하고 전송하는 데 사용되는데 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getWriter()&lt;/code&gt;나 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getOutputStream()&lt;/code&gt; 메서드를 통해 응답 바디를 작성할 수 있다.&lt;/p&gt;

    &lt;p&gt;==&amp;gt; 응답 바디를 작성한다는 것은 클라이언트에게 전송될 웹 페이지의 실제 내용이나 데이터를 생성하는 것을 의미한다. HTTP 응답은 헤더와 바디로 이루어져 있으며, 헤더는 응답에 대한 메타 정보를, 바디는 실제 데이터를 포함한다.&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 응답 헤더 설정
    response.setContentType(&quot;text/plain&quot;);
  
    // 응답 바디 작성
    PrintWriter writer = response.getWriter();
    writer.println(&quot;Hello, World!&quot;);
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;​	==&amp;gt; 클라이언트가 이 서블릿에 HTTP GET 요청을 하면, 서버는 “Hello, World!”를 응답으로 전송하게 된다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;**응답 헤더 설정 **: 클라이언트로 전송되는 응답에는 헤더 정보가 포함되는데  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setHeader()&lt;/code&gt; 메서드를 사용하여 응답 헤더를 설정할 수 있다.&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;response.setHeader(&quot;Content-Type&quot;, &quot;text/html&quot;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;상태 코드 설정&lt;/strong&gt; : 응답의 상태 코드는 클라이언트에게 요청의 성공 또는 실패를 나타낸다. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setStatus()&lt;/code&gt; 메서드를 사용하여 상태 코드를 설정할 수 있다.&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;response.setStatus(HttpServletResponse.SC_OK); // 200 OK
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;리다이렉션&lt;/strong&gt; : 클라이언트를 다른 URL로 리다이렉트하는 경우에도 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpServletResponse&lt;/code&gt;가 사용된다.&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;response.sendRedirect(&quot;/new-page&quot;);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;**쿠키 추가 **: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpServletResponse&lt;/code&gt;를 사용하여 클라이언트에게 쿠키를 추가할 수 있다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;캐싱 제어&lt;/strong&gt; : &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cache-Control&lt;/code&gt; 헤더 등을 설정하여 클라이언트 및 프록시 서버에서 응답 캐싱을 제어할 수 있다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;-issue&quot;&gt;💭 &lt;strong&gt;ISSUE&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;아래 이슈때문에 HttpServletResponse에 대해 정확히 짚고 넘어가려고 이 글을 작성했다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public class MemberService implements UserDetailsService {
    private final MemberRepository memberRepository;
    private final JwtTokenService jwtTokenService; 
    private final HttpServletResponse response;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;해당 로직은 내가 실무하면서 MemberService 내에서 로그인 처리하면서 작성한 것이다.
로그인에 성공하면 jwt토큰을 발급하고 쿠키에 저장하는 방식으로 로직을 작성했는데
문제는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpServletResponse&lt;/code&gt;를 전역변수에 선언하는 짓(?)을 해버려서 수정을 하게 됐다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpServletResponse&lt;/code&gt;&lt;/strong&gt; &lt;strong&gt;를 왜 전역변수에 선언하면 안될까?&lt;/strong&gt;
이를 이해하려면 아래 객체지향 프로그래밍의 기본 원칙 중 하나인 “의존성 주입”에 관한 내용을 먼저 이해해야 한다.&lt;/p&gt;

&lt;p&gt;의존성 주입은 클래스가 직접 필요로 하는 의존성(다른 클래스나 객체에 대한 의존)을 외부에서 주입받도록 하는 디자인 패턴 중 하나이다. 이 패턴을 통해 클래스 간의 결합도를 낮추고 유연한 코드를 작성할 수 있는데, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpServletResponse&lt;/code&gt;를 전역변수로 선언하는 것은 해당 클래스가 내부적으로 자신이 필요로 하는 의존성을 직접 생성하고 유지하는 것이며, 이는 의존성 주입 원칙을 위배하는 것이다. 
대신, 해당 클래스가 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HttpServletResponse&lt;/code&gt;를 필요로 하는 메서드나 생성자를 통해 외부에서 주입받도록 하는 것이 권장된다. 위 로직에서처럼 전역변수로 선언하여 전역 상태를 가지는 것은 다중 스레드 환경에서 예기치 못한 동작을 초래할 수 있기 때문에 특히 웹 애플리케이션과 같이 다수의 동시 요청을 처리하는 환경에서는 신중해져야 한다. 이러한 이유로 의존성 주입을 통해 필요한 의존성을 명시적으로 주입받도록 하는 것이 바람직 함.&lt;/p&gt;

&lt;p&gt;**&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;또한, &lt;/code&gt; **HttpServletResponse를 전역 변수로 선언하게 되면 해당 객체의 상태를 여러 메서드에서 공유하게 되고, 이는 다중 스레드 환경에서 예기치 못한 동작을 초래할 수 있다. 때문에 필요한 메서드에 매개변수로 전달하는 방식이 더 나은 설계 방식이다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;나같은 경우는 response를 사용하는 메서드의 파라미터에 HttpServletResponse를 선언해서 사용하도록 수정했다.&lt;/strong&gt;&lt;/p&gt;</content><author><name>XOHW Note</name><email>so91062412@gmail.com</email></author><summary type="html">✏️ HttpServletResponse ?</summary></entry><entry><title type="html">[1152] Baek joon</title><link href="https://xohw91.github.io/baek-joon-1152/" rel="alternate" type="text/html" title="[1152] Baek joon" /><published>2024-01-22T00:00:00+00:00</published><updated>2024-01-22T00:00:00+00:00</updated><id>https://xohw91.github.io/baek-joon-%5B1152%5D</id><content type="html" xml:base="https://xohw91.github.io/baek-joon-1152/">&lt;p&gt;&lt;img src=&quot;/images/2024-01-22-baek-joon-[1152]/image-20240123144442658.png&quot; alt=&quot;image-20240123144442658&quot; /&gt;&lt;/p&gt;

&lt;p&gt;문장을 입력받아서 공백 기준으로 split해서 배열의 length를 세어주는 간단한 문제라 생각했으나 디테일한 부분을 놓쳐 꽤 긴 시간 헤매서 정리해본다.&lt;/p&gt;

&lt;p&gt;우선 Scanner의 next()와 nextLine()의 차이에 대한 내용을 까먹어서 next()로 배열을 자꾸 받으려고 시도하니 Index Length 오류가 발생했다..&lt;/p&gt;

&lt;p&gt;참고로 next()는 공백 문자(스페이스, 탭, 개행 등)을 기준으로 다음 토큰을 읽어오기 때문에 “Hello World”를 하게 되면 Hello와 World가 각각의 변수에 들어간다. 즉, 사용자가 입력한 데이터를 공백 문자 전까지만 읽어오기 때문에  &lt;strong&gt;배열로 들어가는 게 아니다!!!!&lt;/strong&gt; 단어 단위로 읽어온다.&lt;/p&gt;

&lt;p&gt;반면, nextLine()은 개행문자(Enter)를 기준으로 한 줄 전체를 읽어 온다.
그렇기 때문에 nextLine().split(““)을 하게 되면 배열에 담기게 되는 것!&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;import java.beans.PropertyEditorSupport;
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String input = sc.nextLine();
        // 문자열 양 끝의 공백 제거 후 공백을 기준으로 나눔
        String[] words = input.trim().split(&quot; &quot;);
        // split(&quot; &quot;) 메서드는 주어진 문자열을 공백으로 나눌 때, 연속된 공백도 분리하여 빈 문자열을 생성한다.
        // 즉, split을 공백으로 나누면은 문장의 첫 글자가 공백일 경우 &quot;&quot; 가 들어가게 됨.

        words = removeEmptyStrings(words);
        System.out.println(words.length);

    }

    private static String[] removeEmptyStrings(String[] words) {
        int count = 0;
        // 공백이 아닌 배열 값의 개수를 센다.
        for (String s : words) {
            if (!s.isEmpty()) {
                count++;
            }
        }

        // 공백이 아닌 개수만큼의 크기의 배열을 만든다.
        String[] result = new String[count];
        int index = 0;
        for (String s : words) {
            if (!s.isEmpty()) { // 공백이 아닐 때 result에 s를 더함.
                result[index++] = s;
            }
        }

        return result;
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;또 한가지 간과한 것은 split(“ “)을 하게되면 주어진 문자열을 공백으로 나누게 되는데, 연속된 공백도 분리하여 빈 문자열을 생성한다. 즉, 입력된 문자열을 공백으로 나누어 배열로 만들 때 공백이 연속되어 있으면 그 사이에 빈 문자열이 생성된다.&lt;/p&gt;

&lt;p&gt;예를 들어 “Hello  World”를 split(“ “)을 하게되면 결과 배열은 [“Hello”, “”, “”, “World”] 처럼 생성된다. 
왜냐면 Hello와 World 사이에 공백이 연속하여 두 개 들어갔기 때문이다. 
공백을 빈 문자열 처리한다는 게 아무리 봐도 이해는 안되지만 이해안될 땐 외우는 수 밖에……………..&lt;/p&gt;

&lt;p&gt;아무튼, 위의 문제에서는 removeEmptyStrings()메서드를 따로 빼서 배열을 파라미터로 전달받으면 공백이 아닌 배열 값의 개수(count)를 세고,
공백이 아닌 개수만큼의 크기의 배열을 만들어서 공백을 제외한 배열인 result를 만든다.
이 result의 length를 출력해주면 문제 해결!&lt;/p&gt;</content><author><name>XOHW Note</name><email>so91062412@gmail.com</email></author><summary type="html"></summary></entry><entry><title type="html">[Java] Socket</title><link href="https://xohw91.github.io/Socket/" rel="alternate" type="text/html" title="[Java] Socket" /><published>2024-01-19T00:00:00+00:00</published><updated>2024-01-19T00:00:00+00:00</updated><id>https://xohw91.github.io/Socket</id><content type="html" xml:base="https://xohw91.github.io/Socket/">&lt;p&gt;간단한 소켓 통신을 통해 서버와 클라이언트 간의 채팅을 구현하는 예제를 통해 공부를 해보았다.
까먹지 않기 위해 기록 기록….👀&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;package com.example.test;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Iterator;
import java.util.Vector;

class Server extends Thread {
    /*
    Server class
    서버 역할을 하는 클래스. 클라이언트의 연결을 기다리고 연결된 클라이언트들에 대한 처리를 담당함.
     */

    Vector&amp;lt;ClientHandler&amp;gt; clientList = new Vector&amp;lt;&amp;gt;();

    /*
    Vector는 자바에서 제공하는 동기화된 컬렉션 클래스 중 하나로 스레드 간에 안전하게 사용할 수 있도록 동기화 돼 있음.
    Vector는 배열과 유사하지만 크기가 동적으로 조절되며 동기화가 보장되기 때문에 여러 스레드에서 안전하게 사용할 수 있다.

    서버에 연결된 각 클라이언트를 나타내는 클래스인 ClientHandler 객체를 담는 Vector를 생성한다.
    Vector를 사용하는 이유는 다수의 클라이언트가 동시에 서버에 연결되고 서로 다른 스레드에서 이 벡터를 조작할 수 있기 때문에
    동기화된 자료 구조를 사용해 스레드 안전성을 보장하려는 목적이다.

     */

    ServerSocket ss;
    boolean running = true;

    public void run() { // 스레드가 실행할 코드를 정의하는 메서드. 안의 로직은 스레드가 시작되면 실행 됨.
        try {
            ss = new ServerSocket(8090); // ServerSocket 객체를 생성하여 클라이언트의 연결을 수락할 준비
            // new ServerSocket(0) 시스템에서 사용 가능한 포트를 자동으로 할당
            System.out.println(&quot;Server running on port: &quot; + ss.getLocalPort());
            while (running &amp;amp;&amp;amp; !Thread.currentThread().isInterrupted()) {
                System.out.println(&quot;Waiting client...&quot;);
                Socket s = ss.accept(); // accept()을 호출, 클라이언트가 연결 요청을 할 때까지 블록됨.

                /**
                 *    public Socket accept() throws IOException {
                 *         if (isClosed()) // 소켓이 닫혔는가?
                 *             throw new SocketException(&quot;Socket is closed&quot;);
                 *         if (!isBound()) // 소켓이 바인딩 되었는가? ==&amp;gt; 클라이언트의 연결을 수락할 준비가 되었는가?
                 *             throw new SocketException(&quot;Socket is not bound yet&quot;);
                 *         Socket s = new Socket((SocketImpl) null);
                 *         implAccept(s);
                 *         return s;
                 *     }
                 *   ==&amp;gt; ServerSocket 에서 제공되는 메서드로 클라이언트와의 실제 연결이 수락되면 클라이언트와 통신할 수 있는 Socket객체를 반환함.
                 *         연결 요청이 없는 경우에는 블록되어 대기,
                 */

                // 클라이언트가 연결을 시도하면 `accept`는 해당 클라이언트와 통신할 수 있는 Socket 객체를 반환한다.
                System.out.println(&quot;Client connected.&quot;);

                /*
                this는 현재 Server 객체를 가르킨다.
                ClientHandler가 생성자에서 this를 사용하는 이유는 새로운 클라이언트가 서버에 연결되었을 때,
                이 클라이언트와 관련된 작업을 Server 객체의 메서드 등을 통해 수행하기 위함이다.
                ==&amp;gt; 즉, 생성자를 통해 'Server' 객체를 전달받아 'ClientHandler' 객체가 해당 서버의 기능을 활용할 수 있는 것.
                    서버와 클라이언트 간의 통신을 관리하고 다른 클라이언트에게 메시지를 브로드캐스팅하는 등의 작업을
                    'Server'객체의 메서드를 호출하여 수행할 수 있음.
                 */
                ClientHandler client = new ClientHandler(this, s);
                /*
                클라이언트와의 연결이 수락되면 `ClientHandler` 클래스의 인스턴스를 생성하고,
                clientList에 이 클라이언트 핸들러를 추가한다.
                */
                clientList.add(client);
                /*
                client의 start()는 ClientHandler의 메서드가 아니라 Thread의 메서드이다.
                ClientHandler는 Thread를 상속받았기 때문에 start()를 실행할 수 있는 것.

                public void start() {
                    synchronized (this) {
                        // zero status corresponds to state &quot;NEW&quot;.
                        if (holder.threadStatus != 0)
                            throw new IllegalThreadStateException();
                        start0();
                    }
                }

                ==&amp;gt; start()는 스레드를 시작하는 역할을 한다.
                start()를 호출하면 새로운 스레드가 생성되어 비동기적으로 실행된다.
                한번 스레드가 시작되면 다시 시작할 수 없으며, 이미 시작된 스레드를 다시 시작하려고 하면 IllegalThreadStateException가 발생함.
                synchronized (this)는 여러 스레드가 동시에 start()를 호출하지 못하도록 동기화를 제공함.
                start0() 메서드가 호출되기 전에 synchronized (this) 블록 내에서 현재 스레드의 상태를 확인하고, 이미 시작된 스레드인지 확인함.
                start0() 메서드는 실제로 네이티브 코드로 작성된 메서드로 스레드를 시작하는 로우 레벨의 작업을 수행한다.

                해당 클라이언트와의 통신을 담당할 새로운 스레드로 시작하는 시점은 start()할 때임!!!!!!!!!!
                start() ==&amp;gt; start0() ==&amp;gt; Thread를 상속받은 ClientHandler의 run() ==&amp;gt;
                 */
                client.start();
            }
        } catch (Exception e) {
            System.out.println(&quot;Server - error occurred. system will be down.&quot;);
            System.out.println(&quot;Error in ClientHandler.run(): &quot; + e.getMessage());
            shutdown();
            /*
            예외가 발생하면 해당 예외를 캐치하고 오류 메시지를 출력한다.
            그 후 shutdown 메서드를 호출하여 서버 및 클라이언트의 연결을 종료함.
            */
        }
    }

    void shutdown() {
        this.running = false;
        Iterator&amp;lt;ClientHandler&amp;gt; it = clientList.iterator();
        while (it.hasNext()) {
            ClientHandler client = it.next();
            client.disconnect();
            it.remove();
        }
        if (ss != null) try { ss.close(); } catch (Exception e) {}
    }

    void broadcast(String s) {
        for (ClientHandler client : clientList) {
            client.sendMessage(s);
        }
    }

}

class ClientHandler extends Thread {

    Server server;
    boolean running = true;
    Socket socket;
    BufferedReader in;
    PrintWriter out;

    public ClientHandler(Server server, Socket s) throws Exception {
        this.server = server;
        this.socket = s;
    }

    void disconnect() {
        System.out.println(&quot;ClientHandler.disconnect()&quot;);
        running = false;
        if (in != null) try { in.close(); } catch (Exception e) {}
        if (out != null) try { out.close(); } catch (Exception e) {}
        server.clientList.remove(this);
    }

    // sendMessage()는 서버에서 모든 클라이언트에게 메시지를 전송하는 역할을 함.
    void sendMessage(String msg) {
        out.println(msg);
        out.flush();
    }

    public void run() {
        try {
            System.out.println(&quot;ClientHandler.run()&quot;);
            // 클라이언트와의 연결된 소켓에서 출력 스트림을 얻어온다.
            out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
            // 클라이언트와의 연결된 소켓에서 입력 스트림을 얻어온다.
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out.println(&quot;Welcome!&quot;);
            out.flush(); // 버퍼에 남아있는 모든 데이터를 비워줘야함. 안비우면 메시지 출력 안 될 수도 있음.
        } catch (Exception e) {
            System.out.println(&quot;error occurred.&quot;);
            e.printStackTrace();
        }

        while (running &amp;amp;&amp;amp; !Thread.currentThread().isInterrupted()) { // 클라이언트가 계속해서 연결중이라면? 
            try {
                String line = in.readLine(); // 입력 받아서 
                System.out.println(&quot;message received - &quot; + line); // 출력
                if (&quot;exit&quot;.equals(line)) { // 만약에 exit를 입력했다면 break하고 disconnet() 호출
                    // ==&amp;gt; 해당 클라이언트의 ClientHandler 스레드가 종료되고, 클라이언트와 서버와의 연결 끊어짐
                    break;
                }
                if (&quot;down&quot;.equals(line)) { // down을 입력했다면 shutdown() ==&amp;gt; disconnet() 호출
                    server.shutdown(); // exception
                    // ==&amp;gt; 전체 서버 종료, 당연히 ClientHandler 스레드도 종료
                    break;
                }

                // 만약 exit와 down 외의 입력값이 들어온다면 broadcast()로 클라이언트가 입력한 값을 파라미터로 보냄
                server.broadcast(line);
            } catch (Exception e) {
                System.out.println(&quot;error occurred. connection will be closed.&quot;);
                e.printStackTrace();
                break;
            }
        }
        disconnect();
    }

}

class ConsoleClient extends Thread {

    boolean running = true;
    Socket socket;
    BufferedReader in;
    PrintWriter out;
    ConsoleReader console;

    public ConsoleClient() throws Exception {
        this.socket = new Socket(&quot;localhost&quot;, 8090);
        this.console = new ConsoleReader(this);
        this.console.start();
    }

    void sendMessage(String message) {
        System.out.println(&quot;ConsoleClient.sendMessage: &quot; + message);
        out.println(message);
        out.flush();
    }

    void disconnect() {
        System.out.println(&quot;ConsoleClient.disconnect()&quot;);
        running = false;
        if (in != null) try { in.close(); } catch (Exception e) {}
        if (out != null) try { out.close(); } catch (Exception e) {}
        console.shutdown();
    }

    public void run() {
        System.out.println(&quot;ConsoleClient.run()&quot;);
        try {
            in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            out = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
        } catch (Exception e) {
            System.out.println(&quot;error occurred.&quot;);
            e.printStackTrace();
            running = false;
        }
        System.out.println(&quot;stream created.&quot;);
        while (running &amp;amp;&amp;amp; !Thread.currentThread().isInterrupted()) {
            try {
                String line = in.readLine();
                if (line == null) {
                    disconnect();
                    break;
                }
                System.out.println(line);
            } catch (Exception e) {
                System.out.println(&quot;ConsoleClient - error occurred. system will be down.&quot;);
                System.out.println(&quot;Error in ClientHandler.run(): &quot; + e.getMessage());
                e.printStackTrace();
                running = false;
                break;
            }
        }
    }

}

class ConsoleReader extends Thread {
    ConsoleClient cc;
    boolean running = true;
    ConsoleReader(ConsoleClient cc) {
        this.cc = cc;
    }
    void shutdown() {
        running = false;
        this.interrupt();
    }
    public void run() {
        System.out.println(&quot;ConsoleReader.run()&quot;);
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        try {
            while (running
                    &amp;amp;&amp;amp; !Thread.currentThread().isInterrupted()) {
                System.out.print(&quot;input: &quot;);
                String line = in.readLine();
                if (line == null) {
                    running = false;
                    cc.disconnect();
                    break;
                }
                System.out.println(&quot;&amp;gt; &quot; + line);
                cc.sendMessage(line);
            }
        } catch (Exception e) {
            System.out.println(&quot;Error in ConsoleReader.run(): &quot; + e.getMessage());
            e.printStackTrace();
        }
    }
}

public class SocketTest {
    public static void main(String[] args) throws Exception {
        if (args.length &amp;gt; 0) {
            if (&quot;server&quot;.equals(args[0])) {
                new Server().start();
            } else if (&quot;client&quot;.equals(args[0])) {
                new ConsoleClient().start();
            }
        } else {
            System.out.println(&quot;사용법: java SocketTest &amp;lt;server/client&amp;gt;&quot;);
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Server Class&lt;/code&gt; 클래스:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Server&lt;/code&gt; 클래스는 서버 역할을 하는 클래스로, 클라이언트의 연결을 기다리고 연결된 클라이언트들에 대한 처리를 담당한다.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;서버는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServerSocket&lt;/code&gt;을 사용하여 run()에 특정 포트(여기서는 8088)에서 클라이언트의 연결을 수락한다.&lt;/p&gt;

    &lt;p&gt;==&amp;gt; 무한 루프인 이유는 여러 클라이언트의 연결을 관리하기 위함임.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Server&lt;/code&gt; 클래스는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClientHandler&lt;/code&gt; 스레드를 생성하여 클라이언트와의 통신을 처리한다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClientHandler&lt;/code&gt; 클래스:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClientHandler&lt;/code&gt; 클래스는 각 클라이언트의 통신을 처리하는 스레드이다.&lt;/li&gt;
  &lt;li&gt;각 클라이언트와의 입출력 스트림을 생성하고, 클라이언트로부터 메시지를 수신하여 서버에 브로드캐스팅한다.&lt;/li&gt;
  &lt;li&gt;클라이언트가 “exit”을 보내면 해당 클라이언트의 스레드를 종료하고 연결을 닫는다.&lt;/li&gt;
  &lt;li&gt;“down”을 받으면 서버를 종료시키고 클라이언트 연결도 종료한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConsoleClient&lt;/code&gt; 및 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConsoleReader&lt;/code&gt; 클래스:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConsoleClient&lt;/code&gt; 클래스는 클라이언트 역할을 하는 클래스로, 서버에 연결하여 콘솔에서 메시지를 입력하고 서버로 전송한다.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConsoleReader&lt;/code&gt; 클래스는 콘솔에서 입력을 읽어와서 서버로 전송하는 역할을 하는 스레드이다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SocketTest&lt;/code&gt; 클래스 (메인 클래스):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SocketTest&lt;/code&gt; 클래스는 프로그램의 진입점으로, 명령행 매개변수에 따라 서버 또는 클라이언트 역할을 수행한다.&lt;/li&gt;
  &lt;li&gt;“server”를 인자로 주면 서버로 동작하고, “client”를 인자로 주면 클라이언트로 동작한다.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;️sockettest-클래스의-프로세스에-대한-순서&quot;&gt;✏️&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SocketTest&lt;/code&gt; 클래스의 프로세스에 대한 순서&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;프로그램 실행:&lt;/strong&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;프로그램을 실행할 때 명령행 인자로 “server” 또는 “client”를 전달한다.&lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;“server”를 인자로 주면 서버로 동작하며, “client”를 인자로 주면 클라이언트로 동작한다.
&lt;img src=&quot;/images/2024-01-19-Socket/image-20240124143131051.png&quot; alt=&quot;image-20240124143131051&quot; /&gt;&lt;/p&gt;

        &lt;p&gt;&lt;img src=&quot;/images/2024-01-19-Socket/image-20240124143223274.png&quot; alt=&quot;image-20240124143223274&quot; /&gt;&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;서버 동작:&lt;/strong&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;“server”를 명령행 인자로 받았을 경우, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Server&lt;/code&gt; 클래스의 인스턴스를 생성하고 스레드로 시작한다.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Server&lt;/code&gt; 클래스는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ServerSocket&lt;/code&gt;을 사용하여 클라이언트의 연결을 기다리고, 연결되면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ClientHandler&lt;/code&gt; 스레드를 생성하여 해당 클라이언트와의 통신을 담당한다.&lt;/li&gt;
      &lt;li&gt;서버는 브로드캐스팅을 통해 연결된 모든 클라이언트에게 메시지를 전송한다.&lt;/li&gt;
      &lt;li&gt;“down” 메시지를 받으면 서버를 종료하고 클라이언트 연결도 종료한다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;클라이언트 동작:&lt;/strong&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;“client”를 명령행 인자로 받았을 경우, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConsoleClient&lt;/code&gt; 클래스의 인스턴스를 생성하고 스레드로 시작한다.&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConsoleClient&lt;/code&gt; 클래스는 서버에 소켓 연결을 시도하고, 연결이 성공하면 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConsoleReader&lt;/code&gt; 스레드를 생성하여 사용자의 콘솔 입력을 읽어와 서버로 전송한다.&lt;/li&gt;
      &lt;li&gt;서버에서 받은 메시지를 화면에 출력한다.&lt;/li&gt;
      &lt;li&gt;“exit” 메시지를 입력하면 클라이언트 프로그램을 종료한다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;통신 프로세스:&lt;/strong&gt;&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;클라이언트에서 서버로 메시지를 전송할 때는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConsoleClient&lt;/code&gt;의 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sendMessage&lt;/code&gt; 메서드를 사용한다.&lt;/li&gt;
      &lt;li&gt;서버는 받은 메시지를 모든 클라이언트에게 브로드캐스팅한다.&lt;/li&gt;
      &lt;li&gt;서버에서 “exit” 메시지를 받으면 해당 클라이언트와의 연결을 종료하고, “down” 메시지를 받으면 서버와 모든 클라이언트의 연결을 종료한다.&lt;/li&gt;
    &lt;/ul&gt;

    &lt;h1 id=&quot;️-로컬에서-테스트를-진행해보자&quot;&gt;✏️ 로컬에서 테스트를 진행해보자&lt;/h1&gt;

    &lt;ol&gt;
      &lt;li&gt;
        &lt;p&gt;SocketTest.java가 있는 디렉토리에서 cmd창을 연다.
   ==&amp;gt; 아래 명령어를 실행함.
       D:\workspace_inteliJ\test\src\main\java\com\example\test&amp;gt;javac -encoding UTF-8 -d . SocketTest.java
   	나같은 경우에는 encoding 오류가 나서 -encoding UTF-8 옵션을 주고 컴파일을 함. 컴파일하고나면 class파일이 생성될 것.&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;아래 사진처럼 -cp를 사용하여 클래스 패스 위치를 설정(JVM이 클래스 파일 및 라이브러리 파일을 검색하는 경로를 지정)해줌과 동시에 SocketTest 클래스에 인자인 ‘server’ 전달, 실행한다. 다른 cmd창을 켜서 같은 방법으로 client도 실행함.&lt;/p&gt;

        &lt;p&gt;&lt;img src=&quot;/images/2024-01-19-Socket/image-20240124144258193.png&quot; alt=&quot;image-20240124144258193&quot; /&gt;&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;client 창에서 메시지를 입력하면 server cmd창에 그대로 broadcast된다.&lt;/p&gt;

        &lt;p&gt;&lt;img src=&quot;/images/2024-01-19-Socket/image-20240124144500597.png&quot; alt=&quot;image-20240124144500597&quot; /&gt;&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ol&gt;</content><author><name>XOHW Note</name><email>so91062412@gmail.com</email></author><summary type="html">간단한 소켓 통신을 통해 서버와 클라이언트 간의 채팅을 구현하는 예제를 통해 공부를 해보았다. 까먹지 않기 위해 기록 기록….👀</summary></entry><entry><title type="html">[Server] Windows에서 WSL(Linux 개발환경) 구축하는 법</title><link href="https://xohw91.github.io/Windows%EC%97%90%EC%84%9C-WSL(Linux-%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD)-%EA%B5%AC%EC%B6%95%ED%95%98%EB%8A%94-%EB%B2%95/" rel="alternate" type="text/html" title="[Server] Windows에서 WSL(Linux 개발환경) 구축하는 법" /><published>2024-01-18T00:00:00+00:00</published><updated>2024-01-18T00:00:00+00:00</updated><id>https://xohw91.github.io/Windows%EC%97%90%EC%84%9C%20WSL(Linux%20%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD)%20%EA%B5%AC%EC%B6%95%ED%95%98%EB%8A%94%20%EB%B2%95</id><content type="html" xml:base="https://xohw91.github.io/Windows%EC%97%90%EC%84%9C-WSL(Linux-%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD)-%EA%B5%AC%EC%B6%95%ED%95%98%EB%8A%94-%EB%B2%95/">&lt;h1 id=&quot;wslwindows-subsystem-for-linux이란&quot;&gt;WSL(Windows Subsystem for Linux)이란?&lt;/h1&gt;

&lt;p&gt;WSL란 Windows 운영 체제에서 Linux 환경을 실행할 수 있도록 하는 기술로, Windows10부터 도입됐으며 사용자들이 Windows에서 Linux 명령어 및 유틸리티를 실행하고 Linux 배포판을 설치할 수 있도록 한다. 
Virtual Box같은 가상머신을 사용하지 않고도 개발자들이 Windows에서 Linux 기반의 개발 작업이 가능하도록 하는데 목적이 있다.&lt;/p&gt;

&lt;p&gt;나같은 경우도 회사 컴퓨터 OS가 Windows인데 Linux 환경에 대한 공부&amp;amp;실습을 하기 위해 설치하게 됐다. (사수의 권유로!)&lt;/p&gt;

&lt;h4 id=&quot;설치방법&quot;&gt;&lt;strong&gt;설치방법&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;[]: https://learn.microsoft.com/en-us/windows/wsl/install&lt;/p&gt;

&lt;p&gt;설치 자체는 어렵지 않아서 MS 공식 문서를 참고하면 금방 설치가 가능하지만, 아래에서 꼼꼼하게 기록해보려고 한다. 
Ubuntu 설치 후 mariadb, apache2, tomcat9 설치까지의 내용을 담았다.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STEP 1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Windows 키 + Pause 를 눌러서 시스템 창을 키고, 시스템 &amp;gt; 선택적 기능 &amp;gt; 기타 Windows 기능 클릭&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118091609865.png&quot; alt=&quot;image-20240118091609865&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STEP 2 &lt;/code&gt; 선택적 기능 창에서 아래 기능을 체크하고 확인 &amp;gt; 컴퓨터 재시작&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Linux용 Windows 하위 시스템&lt;/li&gt;
  &lt;li&gt;Windows 하이퍼바이저 플랫폼&lt;/li&gt;
  &lt;li&gt;가상 머신 플랫폼&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118091402326.png&quot; alt=&quot;image-20240118091402326&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STEP 3 &lt;/code&gt; 명령 프롬프트 실행&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118092219787.png&quot; alt=&quot;image-20240118092219787&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STEP 4&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;wsl –list –online&lt;/strong&gt; 명령어를 입력하면 설치할 수 있는 배포판 목록이 나온다.
여기서 나는 맨 위의 &lt;strong&gt;Ubuntu&lt;/strong&gt; 로 설치 진행했다.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118092526223.png&quot; alt=&quot;image-20240118092526223&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STEP 5 &lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;wsl –install -d Ubuntu&lt;/strong&gt; 로 Ubuntu 설치&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118092927952.png&quot; alt=&quot;image-20240118092927952&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;나같은 경우에는 설치완료하고나니 Error 떴다. ==&amp;gt; WslRegisterDistribution failed with error: 0x800701bc
찾아보니 Linux 커널 업데이트 패키지를 다운로드 하지 않아서 발생하는 오류&lt;/p&gt;

    &lt;p&gt;&lt;strong&gt;wsl –update&lt;/strong&gt; 명령어 실행 &amp;gt; 설치완료하니 에러는 사라짐.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118093002277.png&quot; alt=&quot;image-20240118093002277&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STEP 6 &lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;명령프롬프트 창에서 아래같이 화살표 눌러서 Ubuntu창을 띄움.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118093434118.png&quot; alt=&quot;image-20240118093434118&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;접속할 username과 password를 입력해준다.
&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118093732794.png&quot; alt=&quot;image-20240118093732794&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STEP 7 &lt;/code&gt; 설치 명령 순서 (순서대로 진행하면 됨)&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;sudo :&lt;/strong&gt; 사용자가 superuser, root 권한으로 명령을 실행할 수 있도록 하는 명령어다. sudo 명령어를 사용하면 일반 사용자도 일시적으로 슈퍼 유저의 권한을 얻을 수 있음. 주로 시스템 관리, 패키지 설치, 설정 변경 등의 작업에서 필요하다.&lt;/p&gt;

    &lt;p&gt;⚠️ &lt;strong&gt;su 명령어와의 차이점?&lt;/strong&gt;  sudo와는 다르게 현재 사용자 계정에서 다른 사용자로 전환하는 데 사용됨. 기본적으로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt;계정으로 전환되는 데 사용됨. (root 비번 필요)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;sudo apt update :&lt;/strong&gt; APT (Advanced Package Tool) 패키지 관리시스템을 업데이트하는 명령어. 이 명령어를 실행하면 시스템의 패키지 목록이 최신 상태로 업데이트 됨. 이 과정을 통해 사용자는 최신 소프트웨어 및 보안 업데이트를 적용할 수 있음. 
&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118094255817.png&quot; alt=&quot;image-20240118094255817&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;sudo apt install aptitude :&lt;/strong&gt;  APT 패키지 관리 시스템을 통해 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aptitude&lt;/code&gt;라는 패키지를 설치하는 명령어. 
aptitude는 패키지 관리 도구 중 하나로, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt&lt;/code&gt;와 마찬가지로 패키지의 설치, 제거, 업그레이드 등을 수행하는 데 사용되며,  패키지 간의 의존성을 더욱 효과적으로 처리하는 특징이 있다. 즉, 이 명령어를 실행하면 시스템에 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aptitude&lt;/code&gt; 패키지가 설치되며, 이를 이용하여 패키지 관리 및 시스템 유지보수 작업을 수행할 수 있다.&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118094123942.png&quot; alt=&quot;image-20240118094123942&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;**sudo aptitude update : **APT 패키지 관리 시스템을 통해 시스템의 패키지 목록을 최신 상태로 업데이트하는 명령어이다. 
&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118094355783.png&quot; alt=&quot;image-20240118094355783&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;aptitude search mariadb :&lt;/strong&gt; APT 패키지 관리 시스템을 통해 시스템에 설치 가능한 MariaDB 패키지를 검색하는 명령어
&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118094042851.png&quot; alt=&quot;image-20240118094042851&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;sudo aptitude install mariadb-server :&lt;/strong&gt;  APT 패키지 관리 시스템을 통해 MariaDB 서버를 설치하는 명령어&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;sudo mariadb-secure-installation :&lt;/strong&gt; MariaDB를 더 안전하게 구성하기 위한 초기 설정을 수행하는 명령어이다. 이 명령어를 실행하면 다양한 보안 관련 옵션을 설정하고 비밀번호를 설정하는 등의 단계를 따를 수 있음.&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;루트 비밀번호 설정 : MariaDB의 루트 게정에 대한 비밀번호를 설정한다.&lt;/li&gt;
      &lt;li&gt;익명 사용자 제거 : 익명으로 접속할 수 있는 사용자를 제거한다.&lt;/li&gt;
      &lt;li&gt;원격 접속 금지 : 원격에서의 접속을 차단한다.&lt;/li&gt;
      &lt;li&gt;테스트 데이터베이스 제거 : 테스트용으로 생성된 데이터베이스를 제거한다.&lt;/li&gt;
      &lt;li&gt;권한 새로고침 : 변경된 권한을 적용하기 위해 MariaDb를 재시작한다.&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118094521437.png&quot; alt=&quot;image-20240118094521437&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STEP 8 &lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;mariadb 설치 후 &lt;strong&gt;sudo mariadb&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118094745201.png&quot; alt=&quot;image-20240118094745201&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;create user test@’localhost’ identified by ‘test’;&lt;/strong&gt; : &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test&lt;/code&gt;라는 사용자 계정을 만듬, 맨 마지막의 ‘test’는 비밀번호임.
&lt;strong&gt;create database testdb;&lt;/strong&gt; : &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;testdb&lt;/code&gt;라는 databases 생성&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;grant all privileges on textdb.* to test@’localhost’&lt;/strong&gt; : test 계정에 testdb에 대한 모든 권한 부여&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STEP 9 &lt;/code&gt; apache2, tomcat9 설치&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;sudo aptitude install apache2 :&lt;/strong&gt;  APT 패키지 관리 시스템을 통해 Apache 웹 서버를 설치하는 명령어
&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118095338952.png&quot; alt=&quot;image-20240118095338952&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;sudo aptitude install tomcat9 :&lt;/strong&gt; APT 패키지 관리 시스템을 통해 Apache Tomcat 9를 설치하는 명령어
&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118095453499.png&quot; alt=&quot;image-20240118095453499&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;이-과정을-모두-완료했다면--설치-완료&quot;&gt;이 과정을 모두 완료했다면 ✅ 설치 완료&lt;/h4&gt;

&lt;p&gt;⚠️&lt;strong&gt;참고&lt;/strong&gt; wsl –help를 치면 여러 옵션을 볼 수 있음.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/2024-01-18-HTTP-API-설계예시/image-20240118092359459.png&quot; alt=&quot;image-20240118092359459&quot; /&gt;&lt;/p&gt;</content><author><name>XOHW Note</name><email>so91062412@gmail.com</email></author><summary type="html">WSL(Windows Subsystem for Linux)이란?</summary></entry><entry><title type="html">[Java] Exception</title><link href="https://xohw91.github.io/Exception/" rel="alternate" type="text/html" title="[Java] Exception" /><published>2024-01-16T00:00:00+00:00</published><updated>2024-01-16T00:00:00+00:00</updated><id>https://xohw91.github.io/Exception</id><content type="html" xml:base="https://xohw91.github.io/Exception/">&lt;h1 id=&quot;️예외란&quot;&gt;✏️예외란?&lt;/h1&gt;

&lt;p&gt;예외를 제대로 이해하기 위해선 예외와 오류의 차이점을 알아야 한다. 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;오류(error)&lt;/code&gt;는 시스템 레벨에서 비정상적인 상황이 발생하는 것으로, 예측불가하므로 개발자는 오류에 대한 처리는 신경쓰지 않는다.
하지만 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;예외(Exception)&lt;/code&gt;는 개발자가 자신이 구현한 로직에서 예외를 예측하고, 그에 따른 예외처리를 신경써야 한다.&lt;/p&gt;

&lt;h4 id=&quot;-예외-클래스&quot;&gt;📖 &lt;strong&gt;예외 클래스&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;모든 예외 클래스는 Throwable 클래스를 상속받고있으며, Throwable을 상속받은 클래스는 다시 Error와 Exception로 나뉜다.
우리가 살펴봐야 할 건 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Exception&lt;/code&gt;이며 Exception의 수많은 자식 클래스를 살펴볼 필요가 있다.
자식 클래스는 다시 Checked Exception과 Unchecked Exception으로 나눠지는데 무슨 차이인지 알아보자.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Checked Exception&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;체크 예외는 try~catch로 예외를 잡아서 처리하거나 throws 예외를 필수로 선언해야 한다. 그렇지 않으면 컴파일 오류가 남&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;특징 :&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;RuntimeException 상속을 받지 않았다.&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;예외 처리 코드 &lt;strong&gt;필수&lt;/strong&gt;&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;확인 시점은 컴파일 단계&lt;/p&gt;

        &lt;p&gt;ex) &lt;strong&gt;IOException, SQLException, ClassNotFoundException&lt;/strong&gt;&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;장점 : 컴파일러를 통해 문제를 잡아주기때문에 개발자가 실수로 예외를 누락하지 않도록 도와줌.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;단점 : 개발자가 결국은 체크 예외를 반드시 잡거나 던지도록 처리해야하기 때문에 번거로움.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class CheckedExceptionExample {
    public static void main(String[] args) {
        try {
            // 파일을 읽어오는 작업
            BufferedReader reader = new BufferedReader(new FileReader(&quot;example.txt&quot;));
            String line = reader.readLine();
            System.out.println(&quot;파일 내용: &quot; + line);
            reader.close();
        } catch (IOException e) {
            // Checked Exception인 IOException 처리
            System.err.println(&quot;파일을 읽어오는 도중 오류 발생: &quot; + e.getMessage());
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Unchecked Exception (RuntimeException)&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;런타임 예외는 컴파일 과정에서는 문제를 발견하지 못하고, 정상적으로 컴파일 된 후 프로그램 실행 중에 발생하는 오류사항들이다.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Unchecked Exception&lt;/code&gt;은 이런 런타임 예외를 상속한다. ==&amp;gt; RuntimeException 상속받음.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;예외 발생 시 런타임 중지(프로그램종료)가 된다. 예를 들면 NullException이나 Index length에 대한 오류&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public class UncheckedExceptionExample {
    public static void main(String[] args) {
        try {
            // 배열의 길이를 초과하여 접근하는 작업
            int[] numbers = {1, 2, 3};
            System.out.println(&quot;배열 요소: &quot; + numbers[5]);  // 여기서 ArrayIndexOutOfBoundsException 발생
        } catch (ArrayIndexOutOfBoundsException e) {
            // Unchecked Exception인 ArrayIndexOutOfBoundsException 처리
            System.err.println(&quot;배열 인덱스 초과: &quot; + e.getMessage());
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;일반적으로 checked Exception을 만나면 더 구체적인 Unchecked Exception을 발생시켜 정확한 정보를 전달하고 로직의 흐름을 끊는다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class ConvertCheckedToUncheckedExample {
    public static void main(String[] args) {
        try {
            readDataFromFile(&quot;example.txt&quot;);
        } catch (RuntimeException e) {
            // Unchecked Exception인 경우 처리
            System.err.println(&quot;데이터 처리 중 오류 발생: &quot; + e.getMessage());
        }
    }

    private static void readDataFromFile(String fileName) {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(fileName));
            String line = reader.readLine();

            // 파일 형식이 잘못되었을 때 Unchecked Exception으로 변환하여 던짐
            if (line != null &amp;amp;&amp;amp; line.contains(&quot;invalidFormat&quot;)) {
                throw new RuntimeException(&quot;잘못된 파일 형식입니다.&quot;);
            }

            System.out.println(&quot;파일 내용: &quot; + line);
        } catch (IOException e) {
            // Checked Exception인 IOException 처리
            System.err.println(&quot;파일을 읽어오는 도중 오류 발생: &quot; + e.getMessage());
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                // 예외 무시 또는 로깅
                System.err.println(&quot;리더 닫기 중 오류 발생: &quot; + e.getMessage());
            }
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;위 코드에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readDataFromFile&lt;/code&gt; 메서드에서 파일을 읽는 도중에 예외가 발생하면, 이를 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RuntimeException&lt;/code&gt;으로 변환하여 상위 메서드인 main메서드 던지고 있다. 즉, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readDataFromFile&lt;/code&gt; 메서드에서 발생한 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RuntimeException&lt;/code&gt;은 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; 메서드에서 호출한 부분에서 잡히게 된다. 이로 인해 Checked Exception을 처리하다가 특정 조건에서 Unchecked Exception으로 변환하여 던지면, 호출자는 이 Unchecked Exception을 처리하면서도 예외 정보를 전달하고 로직의 흐름을 끊을 수 있다.
이를 테면, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; 메서드에서는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RuntimeException&lt;/code&gt;을 잡아서 처리하면서도, 이 예외에 담긴 정보를 통해 문제의 원인을 파악하고 적절한 조치를 취할 수 있게 된다.&lt;/p&gt;

&lt;h4 id=&quot;-throw-vs-throws-&quot;&gt;📖 throw vs throws ?&lt;/h4&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;throw&lt;/code&gt; 는 예외를 명시적으로 발생시킬 때 사용된다. 개발자가 직접 예외를 생성하여 프로그램의 실행을 중단하고자 할 때 사용하는 것이다. 일반적으로 throw new ExceptionType(“Exception Message”); 형태로 사용됨.  throw문은 발생되면 즉시 현재 메서드에서 빠져나가게 되며, throw 아래에 있는 코드는 실행되지 않고, 예외가 발생한 시점부터 해당 메서드를 빠져나가게 됨.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;throws&lt;/code&gt;는 메서드에서 발생할 수 있는 예외를 메서드 선언부에 명시할 때 사용된다. 메서드에서 특정 예외를 처리하지 않고, 메서드를 호출한 곳으로 예외를 전파할 때 사용된다. 여러 개를 선언할 때 쉼표로 구분하게 된다.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;public void exampleMethod() throws IOException, CustomException {
    // 메서드 구현
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;즉, 둘의 차이를 간단히 말하면, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;throw&lt;/code&gt;는 예외를 발생시키는 데 사용되고, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;throws&lt;/code&gt;는 메서드에서 발생할 수 있는 예외를 선언하는 데 사용됩니다. 이들은 서로 다른 역할을 수행하며, 함께 사용될 수 있다. 예를 들어, 메서드 내에서 예외를 발생시키고, 이 예외를 메서드 선언부에서 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;throws&lt;/code&gt;로 선언하여 메서드를 호출한 곳으로 전파할 수 있다.&lt;/p&gt;

&lt;h4 id=&quot;--예외-처리handling&quot;&gt;📖  예외 처리(Handling)&lt;/h4&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CheckedException&lt;/code&gt; 처리&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CheckedException&lt;/code&gt;은 컴파일러가 예외 처리를 강제하는 예외로, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;try ~ catch&lt;/code&gt; 문이나 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;throws&lt;/code&gt; 절을 사용하여 예외를 처리해야한다.&lt;/li&gt;
  &lt;li&gt;throws(의존관계) 로 처리한다. 이 말은 더 상위 메서드로 예외를 전파하는 등의 조치를 취하라는 것.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;UncheckedException(RuntimeException)&lt;/code&gt; 처리&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Checked E xception이어도 더 구체적인 UnCheckedException으로 발생시킨다.
    &lt;ul&gt;
      &lt;li&gt;예를 들어 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IOException&lt;/code&gt; (CheckedException)이 발생하면 이를 좀 더 구체적인 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RuntimeException&lt;/code&gt;으로 변환하여 예외를 발생시킨다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;throw로 exception을 던지고 ExceptionHandler로 처리한다.
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;throw&lt;/code&gt; 문을 사용하여 예외를 발생시키고, 이를 처리하는 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ExceptionHandler&lt;/code&gt;를 통해 예외를 처리한다. ExceptionHandler는 해당 예외에 대한 특별한 처리를 수행하는 코드 블록이며, 주로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;catch&lt;/code&gt; 블록에서 예외를 처리하는데 사용된다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;️eprintstacktrace&quot;&gt;⚠️e.printStackTrace()&lt;/h4&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e.printStackTrace()&lt;/code&gt;에서 기존 예외를 포함하여 스택 트레이스를 출력하는 것은 디버깅 및 예외 추적을 도움으로써 발생한 예외에 대한 정보를 보다 상세하게 확인할 수 있도록 하는 것이다. 스택 트레이스를 출력하는 것은 아래의 이유에 있다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;디버깅 용이성&lt;/li&gt;
  &lt;li&gt;문제의 근본 원인 파악&lt;/li&gt;
  &lt;li&gt;전체적인 컨텍스트 파악&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;java.lang.Exception: 예외 메시지
	at 패키지명.클래스명.메서드명(파일명:라인번호)
	at 패키지명.클래스명.다른메서드명(파일명:라인번호)
	...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</content><author><name>XOHW Note</name><email>so91062412@gmail.com</email></author><summary type="html">✏️예외란?</summary></entry><entry><title type="html">[10811] Baek joon</title><link href="https://xohw91.github.io/baek-joon-10811/" rel="alternate" type="text/html" title="[10811] Baek joon" /><published>2024-01-16T00:00:00+00:00</published><updated>2024-01-16T00:00:00+00:00</updated><id>https://xohw91.github.io/baek-joon-%5B10811%5D</id><content type="html" xml:base="https://xohw91.github.io/baek-joon-10811/">&lt;p&gt;&lt;img src=&quot;/images/2024-01-16-baek-joon-[10811]/image-20240116095811011.png&quot; alt=&quot;image-20240116095811011&quot; /&gt;&lt;/p&gt;

&lt;p&gt;배열 순서를 거꾸로 뒤집는 문제…
분명 학원 다닐 때  풀었던 문제같은데 까먹어서 기록해봄.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

         int N = sc.nextInt();
         int M = sc.nextInt();

         // 바구니 배열 초기화
         int[] baskets = new int[N];
         for (int i = 0; i &amp;lt; N; i++) {
             baskets[i] = i + 1;
         }

         // M번 순서를 역순으로 만듦
         for (int m = 0; m &amp;lt; M; m++) {
             int start = sc.nextInt() - 1;
             int end = sc.nextInt() - 1;

             // 범위의 중간을 기준으로 역순으로 바꿈
             while (start &amp;lt; end) {
                 int temp = baskets[start];
                 baskets[start] = baskets[end];
                 baskets[end] = temp;

                 start++;
                 end--;
             }
         }

         // 결과 출력
         for (int i : baskets) {
             System.out.print(i + &quot; &quot;);
         }
     }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;범위의 중간을 기준으로 역순으로 바꾸는 이유는
만약, baskets라는 배열에 1, 2, 3, 4, 5라는 배열 값이 들어있을 때, 
arr[0] 과 arr[4] / arr[1]과 arr[3] 을 바꿔줘야 중간값인 3을 기준으로 순서가 뒤바뀌는 것이기 때문임.
이 중간값을 start++; 와 end–;를 이용해서 (start &amp;lt; end) 조건을 만족할 때로 찾아주면 됨.&lt;/p&gt;

&lt;p&gt;처음 시도했을 때는 이 중간값에서 값바꾸는걸 멈춰야하는데 계속 바꿔줘서 값이 이상하게 나옴.
&lt;strong&gt;배열 순서를 뒤집는 문제는 중간값에 신경쓰자…&lt;/strong&gt;&lt;/p&gt;</content><author><name>XOHW Note</name><email>so91062412@gmail.com</email></author><summary type="html"></summary></entry><entry><title type="html">HTTP Method</title><link href="https://xohw91.github.io/HTTP-Method/" rel="alternate" type="text/html" title="HTTP Method" /><published>2024-01-11T00:00:00+00:00</published><updated>2024-01-11T00:00:00+00:00</updated><id>https://xohw91.github.io/HTTP%20Method</id><content type="html" xml:base="https://xohw91.github.io/HTTP-Method/">&lt;h1 id=&quot;http-api-uri-설계&quot;&gt;HTTP API URI 설계&lt;/h1&gt;

&lt;p&gt;리소스 식별, URI 계층 구조 활용해야 한다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;회원&lt;/strong&gt;을 조회해라.
&lt;strong&gt;회원&lt;/strong&gt;을 등록해라.
&lt;strong&gt;회원&lt;/strong&gt;정보를 수정해라.&lt;/p&gt;

&lt;p&gt;위 개념에서 리소스는 “회원”이고, “조회해라, 등록해라, 수정해라”는 리소스를 대상으로 하는 행위이다.
그렇기 때문에 리소스는 명사, 행위는 동사이다.&lt;/p&gt;

&lt;p&gt;행위(메서드)는 어떻게 구분할까? HTTP 메서드로 구분하게 된다.&lt;/p&gt;

&lt;h1 id=&quot;️http-메서드&quot;&gt;✏️HTTP 메서드&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;GET&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;리소스 조회할  사용&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;서버에 전달하고 싶은 데이터는 query(쿼리 파라미터, 쿼리 스트링)를 통해서 전달&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;메시지 바디를 사용해서 데이터를 전달할 수 있지만, 지원하지 않는 곳이 많다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;POST : 요청 데이터 처리, 주로 등록에 사용&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;요청 데이터 처리&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;메시지 바디를 통해 서버로 요청 데이터 전달&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;주로 신규 데이터 등록, 변경된 프로세스를 바꿀 때 사용함.&lt;/p&gt;

        &lt;ul&gt;
          &lt;li&gt;
            &lt;p&gt;새 리소스를 생성(등록)&lt;/p&gt;
          &lt;/li&gt;
          &lt;li&gt;
            &lt;p&gt;요청 데이터 처리 : 단순히 데이터를 생성하거나 변경하는 것을 넘어서 프로세스를 처리해야 하는 경우&lt;/p&gt;

            &lt;p&gt;ex) 주문 &amp;gt; 결제완료 &amp;gt; 배달시작 &amp;gt; 배달완료 처럼 단순히 값 변경을 넘어 프로세스의 상태가 변경되는 경우&lt;/p&gt;

            &lt;p&gt;때문에 POST 결과로 새로운 리소스가 생성되지 않을 수도 있음.&lt;/p&gt;
          &lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;서버는 요청 데이터를 처리&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;PUT : 리소스를 대체, 해당 리소스가 없으면 생성&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;클라이언트에서 서버로 리소스를 보내는데 이 리소스로 대체할 때&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;​        ex) 파일을 폴더에 넣는데 기존의 똑같은 파일이 있으면 덮어 써버리는 개념&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;클라이언트가 리소스 위치를 정확히 알고 URI 지정, &lt;strong&gt;POST와의 차이점&lt;/strong&gt;이다.&lt;/p&gt;

    &lt;p&gt;⚠️ 주의할 점은 “리소스를 완전히 대체한다”는 개념을 정확히 이해해야 한다는 것이다.&lt;/p&gt;

    &lt;p&gt;기존에 있던 리소스인  username, age와는 달리 새 리소스를 age만 보낸다면 덮어쓰기때문에 기존의 username, age 모두 사라짐.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;PATCH : 리소스 부분 변경&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;리소스를 부분적으로 변경, 회원의 이름이나 특정 필드를 몇 개 바꿀 때 사용&lt;/p&gt;

    &lt;p&gt;PUT과는 달리 부분적인 변경이 가능하다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;DELETE : 리소스 삭제&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;삭제 요청&lt;/p&gt;

&lt;h1 id=&quot;http-메서드의-속성&quot;&gt;HTTP 메서드의 속성&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;안전(Safe)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;호출해도 리소스를 변경하지 않는다.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;멱등(Idempotent)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;f(f(x)) = f(x)&lt;/li&gt;
  &lt;li&gt;한 번 호출하든 두 번 호출하든 100번 호출하든 결과가 똑같다.&lt;/li&gt;
  &lt;li&gt;멱등 메서드
    &lt;ul&gt;
      &lt;li&gt;GET : 한 번 조회하든, 두 번 조회하든 같은 결과가 조회된다.&lt;/li&gt;
      &lt;li&gt;PUT : 결과를 대체한다. 따라서 같은 요청을 여러 번 해도 최종 결과는 같다.&lt;/li&gt;
      &lt;li&gt;DELETE : 결과를 삭제한다. 같은 요청을 여러 번 새도 삭제된 결과는 똑같다.&lt;/li&gt;
      &lt;li&gt;POST : 멱등이 아니다. 두 번 호출하면 같은 결제가 중복해서 발생할 수 있다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;멱등은 언제 쓸까?&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;자동 복구 매커니즘을 생각해보자.
DELETE를 호출했는데 서버에서 응답이 없을 때, 클라이언트가 다시 자동으로 DELETE를 요청함.
DELETE는 &lt;strong&gt;멱등하기 때문에&lt;/strong&gt;  자동 복구 매커니즘을 사용해도 된다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;재요청하는 중간에 다른 곳에서 리소스를 변경해 버리면?&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;사용자1 : GET -&amp;gt; username : A, age:20&lt;/li&gt;
      &lt;li&gt;사용자2 : PUT -&amp;gt; username : A, age:30&lt;/li&gt;
      &lt;li&gt;사용자1 : GET -&amp;gt; username : A, age:30 ==&amp;gt; 사용자 2의 영향으로 바뀐 데이터 조회&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;&lt;strong&gt;멱등은 외부 요인으로 중간에 리소스가 변경되는 것 까지는 고려하지 않는다.&lt;/strong&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;캐시가능(Cacheable)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;캐시 가능한 메서드는 응답 결과를 캐시에 저장하고 나중에 동일한 요청에 대한 응답으로 사용할 수 있는 메서드이다. 
주로 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET&lt;/code&gt; 메서드가 이에 해당하며, 캐시 기능을 활용하여 성능을 향상시킬 수 있음.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;응답 결과 리소스를 캐시해서 사용해도 될까?&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;웹 브라우저에 요청했던 이미지를 다시 요청할 필요 없이 웹브라우저 내부에 저장이 됨. (이걸 캐시라 함) 
==&amp;gt; GET, HEAD, POST, PATCH 캐시 가능하지만 실제로는 GET, HEAD 정도만 캐시로 사용한다. 
       GET은 url만 키로 잡고 캐시를 하면 되는데 POST, PATCH는 본문 내용까지 캐시 키로 고려해야 해 구현이 쉽지 않다.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;</content><author><name>XOHW Note</name><email>so91062412@gmail.com</email></author><summary type="html">HTTP API URI 설계</summary></entry><entry><title type="html">[HTTP] HTTP란? 개념와 특징, 구조</title><link href="https://xohw91.github.io/HTTP/" rel="alternate" type="text/html" title="[HTTP] HTTP란? 개념와 특징, 구조" /><published>2024-01-10T00:00:00+00:00</published><updated>2024-01-10T00:00:00+00:00</updated><id>https://xohw91.github.io/HTTP</id><content type="html" xml:base="https://xohw91.github.io/HTTP/">&lt;h1 id=&quot;️-http-hypertext-transfer-protocol&quot;&gt;✏️ HTTP (HyperText Transfer Protocol)&lt;/h1&gt;

&lt;p&gt;HyperText 문서를 통해서 연결할 수 있는 html을 전송하는 프로토콜로 처음 사용되었으나
현재는 HTML, TEXT, IMAGE, 음성, 영상, 파일, JSON, XML(API) 등 거의 모든 형태의 데이터 전송이 가능하며, 서버 간에 데이터를 주고 받을 때도 대부분 HTTP를 사용한다.&lt;/p&gt;

&lt;p&gt;HTTP/1.1, HTTP/2의 기반 프로토콜은 TCP 프로토콜 위에 동작을 하며, HTTP/3는 UDP기반으로 개발되어 있다.
현재 HTTP/1.1 주로 사용하며 HTTP/2, HTTP/3도 점점 증가하는 추세다.&lt;/p&gt;

&lt;h1 id=&quot;️http의-특징&quot;&gt;✏️HTTP의 특징&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;클라이언트와 서버 구조로 되어있다.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Request Response 구조. 클라이언트가 서버에 요청을 보내고, 응답을 대기한다.
서버가 요청에 대한 결과를 만들어서 응이 오면 그 응답 결과를 열어서 클라이언트가 동작을 하게 된다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Stateless&lt;/strong&gt;, 무상태 프로토콜을 지향한다&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;서버가 클라이언트의 상태를 보존하지 않는다는 의미다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Stateful (상태유지): 서버가 클라이언트의 이전 상태를 보존하는 것.&lt;/li&gt;
&lt;/ul&gt;

&lt;h6 id=&quot;아래의-예시에서-상태유지와-무상태를-이해해보자&quot;&gt;&lt;em&gt;아래의 예시에서 상태유지와 무상태를 이해해보자.&lt;/em&gt;&lt;/h6&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Stateful&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;고객: 노트북 얼마에요?&lt;br /&gt;점원: 100만원입니다.&lt;br /&gt;&lt;br /&gt;고객: 2개 주세요.&lt;br /&gt;점원: 200만원입니다. 카드 혹은 현금 어떻게 결제하시겠어요?&lt;br /&gt;&lt;br /&gt;고객: 카드로 결제해주세요.&lt;br /&gt;점원: 200만원 결제됐습니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;==&amp;gt; 질문을 할 때마다 정보를 상기시켜주지 않아도 클라이언트가 요청을 할 수 있다.&lt;br /&gt;하지만 이렇게 상태를 유지해야하는 경우에는 대화마다 점원이 바뀐다면 의사소통하기 어려움.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Stateless&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;고객: 노트북 얼마에요?&lt;br /&gt;점원: 100만원입니다.&lt;br /&gt;&lt;br /&gt;고객: 2개 주세요.&lt;br /&gt;점원: 뭐를 2개 드릴까요? &lt;br /&gt;고객: 노트북입니다.&lt;br /&gt;점원: 200만원입니다. 카드 혹은 현금 어떻게 결제하시겠어요?&lt;br /&gt;&lt;br /&gt;고객: 카드로 결제해주세요.&lt;br /&gt;점원: 뭐를, 몇 개, 어떻게 결제해드릴까요? &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;==&amp;gt; 무상태에는 위처럼 말하면 안되고, 클라이언트는 요청을 할 때마다 요청 정보를 매번 말해야 한다. &lt;br /&gt;즉, Stateful(상태유지)때와는 달리 필요한 데이터를 매번 말해야 하는 것.&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;상태유지는 중간에 다른 점원으로 바뀌면 안된다. (중간에 다른 점원으로 바뀔 때 상태 정보를 다른 점원에게 미리 알려줘야 함.)
하지만 무상태는 중간에 다른 점원으로 바뀌어도 된다. 갑자기 고객이 증가해도 점원 대거 투입할 수 있다.(=클라이언트 요청이 갑자기 증가해도 서버를 대거 투입할 수 있다.) 또한 무상태는 응답 서버(점원)를 쉽게 바꿀 수 있다. 즉, 무한한 서버 증설이 가능한 것이다.&lt;/p&gt;

&lt;p&gt;즉, 무상태는 클라이언트가 애초에 요청할 때 필요한 데이터를 다 담아서 서버에 보내버리기 때문에 중간에 아무 문맥이 필요하지 않고, 요청을 받던 서버가 아닌 다른 서버가 받아도 괜찮은 것이다.&lt;/p&gt;

&lt;h4 id=&quot;️stateless의-한계&quot;&gt;⚠️Stateless의 한계&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;로그인과 같은 상태를 유지해야하는 경우에는 어쩔수없이 사용해야하는 경우가 있다.&lt;/li&gt;
  &lt;li&gt;전송되는 데이터량이 크다.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;이러한 한계에도 웹 애플리케이션을 설계할 때는 최대한 무상태로 설계하는 것이 바람직하다.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;비연결성&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;TCP/IP 연결 같은 경우에는 소켓을 연결한 다음 요청을 보내서 응답을 받게되는데 이 연결은 유지가 된다.
클라이언트1이 요청을 보내 응답을 받고, 다시 클라이언트2, 클라이언트3이 서버에 접속해서 요청&amp;gt;응답을 받아도 클라이언트1은 여전히 연결이 계속 유지되는 것.
이렇게 연결을 유지하는 모델은 계속 서버와 연결을 유지해야한다는 단점을 가지고 있다.&lt;/p&gt;

&lt;p&gt;연결을 유지하지 않는 모델은 클라이언트가 요청을 하고 응답을 받게되면 바로 연결을 끊는다. 이렇게 하면 서버는 연결 유지를 하지 않아도 되고, 최소한의 자원을 사용한다는 장점을 가진다.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HTTP&lt;/strong&gt;는 기본적으로 연결을 유지하지 않는 모델이다. 일반적으로 초 단위 이하의 빠른 속도로 응답하기 때문에 1시간동안 수 천 명이 서비스를 사용해도 실제 서버에서 동시에 처리하는 요청은 수십개 이하로 매우 적다. ex) 계속 연속해서 검색 버튼을 누르지 않는다. 
서버 자원을 매우 효율적으로 사용할 수 있는 것이다.&lt;/p&gt;

&lt;h4 id=&quot;️비연결성의-한계&quot;&gt;⚠️비연결성의 한계&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;TCP/IP연결을 새로 맺는 다는 것은 3way handshake, SYN/ACK하는 시간이 추가된다는 뜻.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;HTML뿐만 아니라 이미지, CSS, 자바스크립트 등 수많은 자원이 함께 다운로드가 된다.&lt;/p&gt;

    &lt;p&gt;==&amp;gt; 그래서 HTTP는 지속연결(Persistent Connection)을 기본적으로 사용하는데 
       지속연결이 되면, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;요청/HTML응답 &amp;gt; 요청/자바스크립트 응답 &amp;gt; 요청/이미지응답 &amp;gt; 종료&lt;/code&gt;
       이 과정이 연결, 연결종료를 반복하지 않고 가능하다.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;-stateless를-기억하자&quot;&gt;✅ Stateless를 기억하자.&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;같은 시간에 딱 맞추어 발생하는 대용량 트래픽 (ex.1시에 치킨 이벤트)을 다룰 때는 특히.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;이런 이벤트 설계할 때는 순수한 HTML 정적 페이지를 우선 뿌리고, 사용자들이 한번 보게 한 다음 시간을 벌고 이벤트 버튼을 누르도록 유도해야 함.&lt;/p&gt;

    &lt;p&gt;==&amp;gt; 새로운 요청이 들어올 때마다 자유롭게 서버 확장이 가능하므로, 수평적 확장이 가능하게 하여 트래픽이 증가할 때 자원을 효과적으로 할당함.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;️http-메시지&quot;&gt;✏️HTTP 메시지&lt;/h1&gt;

&lt;p&gt;HTTP의 요청메시지와 응답메시지는 구조가 다르다.&lt;/p&gt;

&lt;p&gt;먼저 HTTP 메시지는 아래와같은 구조를 가진다.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;start-line(시작라인)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;header(헤더)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;empty line(공백라인..CRLF)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;message body&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;[HTTP 요청 메시지]&lt;/strong&gt;&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;GET /seach?q=hello&amp;amp;hl=ko HTTP/1.1  ==&amp;gt; 시작라인&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Host : www.google.com ==&amp;gt; 헤더&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;==&amp;gt; 공백라인&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;요청메시지도 본문에 필요한 메시지 body 가질 수 있음.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[HTTP 응답메시지]&lt;/strong&gt;&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;HTTP/1.1 200 OK&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Content-Type: text/thml;charset=UTF-8&lt;br /&gt;Content-Length: 3423&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;==&amp;gt; 공백라인&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&amp;lt;html&amp;gt;&lt;br /&gt;    &amp;lt;body&amp;gt; … &amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;br /&gt;==&amp;gt; http 응답 메시지 (html이면 html내용이 들어있게 됨.)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;blockquote&gt;
  &lt;p&gt;시작라인&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;stat-line 는 크게 request-line / status-line 로 나눌 수 있다.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;request-line(요청라인) :&lt;/strong&gt; HTTP  Request 메시지의 시작 부분으로, 클라이언트가 서버에게 요청하는 내용을 정의&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;구조: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Method(메서드) SP Request-URI(요청 URI) SP HTTP-Version(HTTP 버전) CRLF&lt;/code&gt;&lt;/p&gt;

        &lt;p&gt;예: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GET /index.html HTTP/1.1&lt;/code&gt;&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;**Status-Line (상태 라인): **HTTP Response 메시지의 시작 부분으로, 서버가 클라이언트에게 응답하는 내용을 정의&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;구조: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTP-Version(HTTP 버전) SP Status-Code(상태 코드) SP Reason-Phrase(상태 이유 구문) CRLF&lt;/code&gt;&lt;/p&gt;

        &lt;p&gt;예: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTTP/1.1 200 OK&lt;/code&gt;&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;헤더&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;HTTP 전송에 필요한 모든 부가 정보 
메시지 바디의 크기, 압축, 인증, 요청 클라이언트(브라우저)정보, 메시지 바디의 내용, 서버 애플리케이션 정보, 캐시 관리 정보 등이 있음.&lt;/li&gt;
  &lt;li&gt;필요 시 임의의 헤더 추가 가능&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;메시지 바디&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
  &lt;li&gt;실제 전송할 데이터&lt;/li&gt;
  &lt;li&gt;HTML 문서, 이미지, 영상, JSON 등등 byte로 표현할 수 있는 모든 데이터 전송 가능&lt;/li&gt;
&lt;/ul&gt;</content><author><name>XOHW Note</name><email>so91062412@gmail.com</email></author><summary type="html">✏️ HTTP (HyperText Transfer Protocol)</summary></entry></feed>