<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>lovelyAlien</title>
    <link>https://lovelyalien.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 9 Apr 2026 06:32:20 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>사랑우주인</managingEditor>
    <item>
      <title>NIC(Network Interface Card)란?</title>
      <link>https://lovelyalien.tistory.com/222</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. NIC(Network Interface Card)란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NIC는 &lt;b&gt;서버(또는 PC)가 네트워크와 통신하기 위한 물리적 인터페이스&lt;/b&gt;다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;패킷이 &lt;b&gt;외부로 나갈 때 반드시 거치는 마지막 관문&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;외부 패킷이 &lt;b&gt;처음으로 들어오는 입구&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;각 NIC는 &lt;b&gt;고유한 MAC 주소&lt;/b&gt;를 가진다&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  핵심&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;ldquo;패킷이 나간다&amp;rdquo;의 기준은 &lt;b&gt;NIC를 통과했는가&lt;/b&gt;다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. NIC는 어떻게 보일까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;macOS에서는 NIC가 &lt;code&gt;enX&lt;/code&gt; 형태의 &lt;b&gt;네트워크 인터페이스&lt;/b&gt;로 노출된다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;인터페이스&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;en0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;보통 Wi‑Fi (주 NIC)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;en1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;유선 Ethernet 또는 추가 NIC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lo0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Loopback (127.0.0.1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bridge0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;브리지 인터페이스&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;utunX&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;VPN 터널&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;NIC 확인&lt;/h3&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;ifconfig&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;MAC 주소 확인&lt;/h3&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;ifconfig en0 | grep ether&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. ifconfig 출력 핵심 해석 (en0 기준)&lt;/h2&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;en0: flags=&amp;lt;UP,RUNNING,BROADCAST,MULTICAST&amp;gt; mtu 1500
ether xx:xx:xx:xx:xx:xx
inet 192.168.0.16
status: active&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;중요한 포인트&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;UP / RUNNING&lt;/b&gt; &amp;rarr; NIC 정상 활성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;status: active&lt;/b&gt; &amp;rarr; 실제 네트워크 연결됨&lt;/li&gt;
&lt;li&gt;IP 존재 &amp;rarr; 외부 통신 가능 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✔️ en0가 active + IP 있음&lt;br /&gt;&amp;rarr; macOS의 &lt;b&gt;실제 네트워크 출구&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. NIC Offloading이란?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;한 줄 정의&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CPU가 하던 네트워크 처리 작업을 NIC 하드웨어에게 맡기는 성능 최적화 기법&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;왜 필요할까?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TCP 패킷 분할&lt;/li&gt;
&lt;li&gt;체크섬 계산&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 작업들을 CPU가 모두 처리하면 &lt;b&gt;부하가 매우 큼&lt;/b&gt; &amp;rarr; NIC에게 위임&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 대표적인 Offloading 기능&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;기능&lt;/th&gt;
&lt;th&gt;의미&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TSO&lt;/td&gt;
&lt;td&gt;TCP Segmentation Offload (큰 TCP를 NIC가 분할)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CHECKSUM OFFLOAD&lt;/td&gt;
&lt;td&gt;체크섬 계산을 NIC가 수행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GRO/LRO&lt;/td&gt;
&lt;td&gt;수신 패킷 병합&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;macOS &lt;code&gt;ifconfig&lt;/code&gt; 옵션 예시:&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;options=&amp;lt;TSO4,TSO6,PARTIAL_CSUM,...&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. &lt;code&gt;sudo tcpdump -i en0&lt;/code&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;tcpdump가 &lt;b&gt;보는 위치&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Application
 &amp;darr;
TCP/IP Stack (Kernel)
 &amp;darr;   &amp;larr; tcpdump가 관찰
NIC Driver
 &amp;darr;
NIC Hardware (Offloading)
 &amp;darr;   &amp;larr; TCP 분할 (TSO), 체크섬 계산
실제 네트워크&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;❗ &lt;b&gt;tcpdump는 NIC 하드웨어에서 실제 전선으로 나간 패킷을 보지 않는다&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. tcpdump 패킷 vs 실제 네트워크 패킷&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;tcpdump가 보는 것&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TCP/IP 스택 기준 &lt;b&gt;논리적 패킷&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;TCP 분할 전&lt;/li&gt;
&lt;li&gt;체크섬 미완성 상태 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;NIC가 실제로 보내는 것&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MTU 기준으로 분할된 패킷&lt;/li&gt;
&lt;li&gt;체크섬 완성&lt;/li&gt;
&lt;li&gt;전선으로 송출&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✔️ tcpdump 패킷 &amp;ne; 실제 네트워크 패킷 (Offloading 때문)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 그래서 발생하는 흔한 오해&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❓ MTU보다 큰 패킷이 보인다&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정상&lt;/li&gt;
&lt;li&gt;TSO 적용 전 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❓ 체크섬 에러처럼 보인다&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정상&lt;/li&gt;
&lt;li&gt;NIC가 나중에 계산&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❓ tcpdump가 틀린 정보를 보여준다?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;❌ 아님&lt;/li&gt;
&lt;li&gt;✔️ &lt;b&gt;OS 관점에서 정확한 정보&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. tcpdump로 알 수 있는 것 / 없는 것&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;알 수 있는 것&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OS가 패킷을 생성했는지&lt;/li&gt;
&lt;li&gt;NIC로 패킷을 넘겼는지&lt;/li&gt;
&lt;li&gt;IP / 포트 / 프로토콜&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;알 수 없는 것&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제 외부 서버 도달 여부&lt;/li&gt;
&lt;li&gt;NIC 이후(스위치/방화벽) 드롭 여부&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;10. 트러블슈팅에서의 핵심 사고 흐름&lt;/h2&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;tcpdump에 패킷 보임?
 ├─ YES &amp;rarr; OS/NIC 이전 문제 아님
 │        &amp;rarr; NIC 이후(라우터, 방화벽, 네트워크)
 └─ NO  &amp;rarr; 애플리케이션 / OS 문제&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 흐름은:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;macOS&lt;/li&gt;
&lt;li&gt;Linux&lt;/li&gt;
&lt;li&gt;Kubernetes Node&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두 동일하게 적용된다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;i&gt;이 글은 macOS 기준이지만, 개념은 Linux / Kubernetes 환경에서도 동일하게 적용된다.&lt;/i&gt;&lt;/p&gt;</description>
      <category>Network</category>
      <category>NIC</category>
      <category>Offloading</category>
      <author>사랑우주인</author>
      <guid isPermaLink="true">https://lovelyalien.tistory.com/222</guid>
      <comments>https://lovelyalien.tistory.com/222#entry222comment</comments>
      <pubDate>Tue, 16 Dec 2025 22:55:52 +0900</pubDate>
    </item>
    <item>
      <title>회선 교환 방식/ 패킷 교환 방식</title>
      <link>https://lovelyalien.tistory.com/221</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 전송 방식은 대표적 2가지 방식이 있다. 회선 교환 방식과 패킷 교환 방식&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;회선 교환 방식&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 교환 데이터 전송로(데이터 통로)를 만들고 데이터 교환을 마칠 때까지 전송로 계속 사용한다.&lt;/li&gt;
&lt;li&gt;하지만 데이터 흐리지 않을 때도 회선이 연결되어 있기 때문에 회선 이용 효율이 낮다.&lt;/li&gt;
&lt;li&gt;따라서 데이터 교환 적합한 통신 방식은 아니다.&lt;/li&gt;
&lt;li&gt;ex. 전화 회선 -&amp;gt; 통화 중 끊김 없이 실시간 음성 오고 감&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;219&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmxhrj/dJMcaj1CHEl/JdtKRFXnjjOznEtkTPA5O0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmxhrj/dJMcaj1CHEl/JdtKRFXnjjOznEtkTPA5O0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmxhrj/dJMcaj1CHEl/JdtKRFXnjjOznEtkTPA5O0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbmxhrj%2FdJMcaj1CHEl%2FJdtKRFXnjjOznEtkTPA5O0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;650&quot; height=&quot;219&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;219&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;패킷 교환 방식&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터를 패킷이라는 작은 단위로 나눠서 네트워크에 보내는 방식&lt;/li&gt;
&lt;li&gt;패킷 헤더에는 수신 컴퓨터 정보, 데이터 인덱스(몇번 째 패킷인지) 등 다양한 정보 포함&lt;/li&gt;
&lt;li&gt;패킷을 모아서 원 데이터로 복원&lt;/li&gt;
&lt;li&gt;인터넷은 패킷 교환 네트워크&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;211&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1tDUw/dJMcahpcBF6/rF1imL0onJcwEwBxxL2HS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1tDUw/dJMcahpcBF6/rF1imL0onJcwEwBxxL2HS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1tDUw/dJMcahpcBF6/rF1imL0onJcwEwBxxL2HS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1tDUw%2FdJMcahpcBF6%2FrF1imL0onJcwEwBxxL2HS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;650&quot; height=&quot;211&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;211&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;회선 교환 방식과 패킷 교환 방식 차이점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회선을 공유 하느냐
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회선 교환 방식 -&amp;gt; 회선 점유&lt;/li&gt;
&lt;li&gt;패킷 교환 방식 -&amp;gt; 회선 공유(네트워크 전체가 하나의 공유 도로망)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Network</category>
      <author>사랑우주인</author>
      <guid isPermaLink="true">https://lovelyalien.tistory.com/221</guid>
      <comments>https://lovelyalien.tistory.com/221#entry221comment</comments>
      <pubDate>Sat, 8 Nov 2025 16:32:52 +0900</pubDate>
    </item>
    <item>
      <title>92342. 양궁대회</title>
      <link>https://lovelyalien.tistory.com/220</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/92342&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/92342&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;제한사항&amp;nbsp;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1320&quot; data-origin-height=&quot;1402&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2A5U9/btsNOMMb1Rp/aPUvyCkxvdkd5aDAYKXp0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2A5U9/btsNOMMb1Rp/aPUvyCkxvdkd5aDAYKXp0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2A5U9/btsNOMMb1Rp/aPUvyCkxvdkd5aDAYKXp0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2A5U9%2FbtsNOMMb1Rp%2FaPUvyCkxvdkd5aDAYKXp0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;637&quot; data-origin-width=&quot;1320&quot; data-origin-height=&quot;1402&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;풀이&lt;/h2&gt;
&lt;pre id=&quot;code_1746636652995&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    int[] answer = {-1};
    int maxDiff = 0;
    
    public int[] solution(int n, int[] info) {
        
        
        dfs(n, 0, new int[11], info);
        
        
        return answer;
    }
    
    
    void dfs(int n, int idx, int[] ryan, int[] apeach) {
        
        
        if(idx == 11) {
            if(n &amp;gt; 0) ryan[10] +=n;
            int ryanScore = 0;
            int apeachScore = 0;
            
            for(int i = 0 ; i &amp;lt; 11; i++) {
                if(ryan[i] == 0 &amp;amp;&amp;amp; apeach[i] == 0) continue;
                if(ryan[i] &amp;gt; apeach[i]) ryanScore+=10-i;
                else apeachScore+=10-i;
            }
            
            if(ryanScore &amp;gt; apeachScore) {
                int diff = ryanScore - apeachScore;
                if(diff &amp;gt; maxDiff) {
                    answer = ryan.clone();
                    maxDiff = diff;
                } else if(diff == maxDiff) {
                    for(int i = 10 ; i &amp;gt;=0 ; i-- ) {
                        if(ryan[i] &amp;gt; answer[i]) {
                            answer = ryan.clone(); 
                            break;
                        } else if(ryan[i] &amp;lt; answer[i])
                            break;
                    }
                }
            }
            
            if(n &amp;gt; 0) ryan[10]-=n;
            return; 
        }
        
        
        // 라이언이 이기는 경우
        if(n &amp;gt; apeach[idx]) {
            ryan[idx] = apeach[idx] + 1;
            dfs(n - (apeach[idx]+1), idx+1, ryan, apeach);
            ryan[idx] = 0; // 백트래킹
        }
        
        // 라이언이 지는 경우
        dfs(n, idx+1, ryan, apeach);
            
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;회고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백트래킹으로 풀어야겠다고는 생각했는데 구현이 쉽지 않았다. 구현 과정에서 잔실수가 많았다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k 점수에 대해서 라이언이 이기려면 어피치보다 과녁을 많이 맞춰야 한다. 맞춘 과녁이 서로 같아도 어피가 이긴다. 따라서, 백트래킹 과정에서 경우의 수를 나눌 때, 어피치가 이기는 경우와 지는 경우를 고려했다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1746636908230&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 라이언이 이기는 경우
        if(n &amp;gt; apeach[idx]) {
            ryan[idx] = apeach[idx] + 1;
            dfs(n - (apeach[idx]+1), idx+1, ryan, apeach);
            ryan[idx] = 0; // 백트래킹
        }
        
        // 라이언이 지는 경우
        dfs(n, idx+1, ryan, apeach);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dfs 종료 조건인 `idx == 1 `이 될 때 탐색을 마친다. 라이언에게 주어진 화살이 남을 경우가 존재할 수 있다. 그럴 경우 0점 과녁(idx = 10)에 남은 화살을 모두 몰아준다. 하지만 이 부분에서 실수를 했다. `ryan[10] = n`으로 작성하여 기존에 쏜 화살 개수를 덮어쓰는 문제가 있었다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1746637429656&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if(idx == 11) {
            if(n &amp;gt; 0) ryan[10] +=n;
            int ryanScore = 0;
            int apeachScore = 0;
            
            for(int i = 0 ; i &amp;lt; 11; i++) {
                if(ryan[i] == 0 &amp;amp;&amp;amp; apeach[i] == 0) continue;
                if(ryan[i] &amp;gt; apeach[i]) ryanScore+=10-i;
                else apeachScore+=10-i;
            }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm/Programmers</category>
      <author>사랑우주인</author>
      <guid isPermaLink="true">https://lovelyalien.tistory.com/220</guid>
      <comments>https://lovelyalien.tistory.com/220#entry220comment</comments>
      <pubDate>Thu, 8 May 2025 02:04:44 +0900</pubDate>
    </item>
    <item>
      <title>Reflection</title>
      <link>https://lovelyalien.tistory.com/219</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;리플렉션이란&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구체적인 클래스 몰라도, &lt;b&gt;런타임&lt;/b&gt;에 클래스의 정보(메서드, 필드, 생성자)를 &lt;b&gt;읽고 조작&lt;/b&gt;할 수 있게 해주는 기능&lt;/li&gt;
&lt;li&gt;즉, 런타임에 타입을 동적으로 결정하고 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비유하자면, 리플렉션은 문을 모르고 열쇠도 없이 방 안을 들여다보고, 안에 있는 물건도 만질 수 있는 기술이다&lt;br /&gt;(보통 코드는 미리 문과 열쇠를 알아야 하지만, 리플렉션은 모른 채로 작동 가능)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;리플렉션이 필요한 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램 실행 중 어떤 클래스를 사용할지 모르는 경우&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring DI 컨테이너, ORM 매핑(JPA) 같은 시스템이 필요&lt;/li&gt;
&lt;li&gt;유연하고 확장 가능한 구조를 만들기 위해&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;어디서 Class 객체를 얻을까&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;Class.forName(&quot;클래스명&quot;)&lt;/code&gt; 호출 시 &lt;b&gt;ClassLoader&lt;/b&gt;가 해당 클래스를 JVM 메모리 안에서 찾는다.&lt;/li&gt;
&lt;li&gt;메모리에 없다면. class 파일을 찾아 로드한다.&lt;/li&gt;
&lt;li&gt;이미 메모리에 있으면 재로딩하지 않고 바로 Class 객체를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;클래스 로딩 시점은 언제&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;단계&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;클래스 로딩 여부&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;컴파일&lt;/td&gt;
&lt;td&gt;.java &amp;rarr; .class 파일 변환&lt;/td&gt;
&lt;td&gt;❌ (메모리 안 올림)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;빌드&lt;/td&gt;
&lt;td&gt;여러 class 파일을 묶어서 jar, war 파일 생성&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;실행(런타임)&lt;/td&gt;
&lt;td&gt;JVM이 프로그램을 실행하며 클래스 로드&lt;/td&gt;
&lt;td&gt;✅ (필요할 때 메모리에 로드)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;컴파일/빌드&lt;/b&gt;: 디스크에 파일만 만든다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;런타임(실행 시점)&lt;/b&gt;: JVM이 필요할 때마다 ClassLoader가 클래스를 메모리에 올린다.&lt;/li&gt;
&lt;li&gt;사용하지 않는 클래스는 끝까지 로딩되지 않을 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;요약&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리플렉션은 런타임에 ClassLoader로 로드된 Class 객체를 통해, 코드에 명시하지 않은 타입도 동적으로 조작할 수 있게 해주는 기술이다.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>Programming</category>
      <author>사랑우주인</author>
      <guid isPermaLink="true">https://lovelyalien.tistory.com/219</guid>
      <comments>https://lovelyalien.tistory.com/219#entry219comment</comments>
      <pubDate>Mon, 28 Apr 2025 01:01:32 +0900</pubDate>
    </item>
    <item>
      <title>87946. 피로도</title>
      <link>https://lovelyalien.tistory.com/218</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/87946?language=java&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/87946?language=java&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;제한사항&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1276&quot; data-origin-height=&quot;532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t5QFk/btsNuC4vHaa/FL6kWfvdxHKX1dI4EsUMXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t5QFk/btsNuC4vHaa/FL6kWfvdxHKX1dI4EsUMXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t5QFk/btsNuC4vHaa/FL6kWfvdxHKX1dI4EsUMXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft5QFk%2FbtsNuC4vHaa%2FFL6kWfvdxHKX1dI4EsUMXk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;250&quot; data-origin-width=&quot;1276&quot; data-origin-height=&quot;532&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;풀이&lt;/h2&gt;
&lt;pre id=&quot;code_1745240609132&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    static int answer = -1;
    public int solution(int k, int[][] dungeons) {
        
        int n =dungeons.length;
        
        
        boolean[] visited = new boolean[n];
        dfs(dungeons, k, 0, visited, 0);
        return answer;
    }
    
    void dfs(int[][] dungeons, int k, int offset, boolean[] visited, int result) {
    
        
        for(int i = 0 ; i&amp;lt;dungeons.length; i++) {
            if(visited[i] || k &amp;lt; dungeons[i][0]) continue; 
            
            visited[i] = true;
            dfs(dungeons, k-dungeons[i][1], i, visited, result+1);
            visited[i] = false;
        }
        
        answer = Math.max(result, answer);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;회고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력값이 자연수이고, 값의 범위가 작아서 그리디 알고리즘을 예상했는데 생각보다 단순했다. dfs를 활용한 백트래킹을 통해 해결할 수 있었다. k가 최소 필요 소모도보다 작으면 가지치기를 했다.&lt;/p&gt;</description>
      <category>Algorithm/Programmers</category>
      <author>사랑우주인</author>
      <guid isPermaLink="true">https://lovelyalien.tistory.com/218</guid>
      <comments>https://lovelyalien.tistory.com/218#entry218comment</comments>
      <pubDate>Mon, 21 Apr 2025 22:07:05 +0900</pubDate>
    </item>
    <item>
      <title>17. Letter Combinations of a Phone Number</title>
      <link>https://lovelyalien.tistory.com/217</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/letter-combinations-of-a-phone-number/description/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/letter-combinations-of-a-phone-number/description/&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;제한사항&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d5x6tN/btsNslP3HfV/3gpuK1rWk4sYP1q4tRSQI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d5x6tN/btsNslP3HfV/3gpuK1rWk4sYP1q4tRSQI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d5x6tN/btsNslP3HfV/3gpuK1rWk4sYP1q4tRSQI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd5x6tN%2FbtsNslP3HfV%2F3gpuK1rWk4sYP1q4tRSQI0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;210&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;풀이&lt;/h2&gt;
&lt;pre id=&quot;code_1745120556842&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    import java.util.*;

    class Solution {
        public List&amp;lt;String&amp;gt; letterCombinations(String digits) {
            
            Map&amp;lt;Character, List&amp;lt;String&amp;gt;&amp;gt; map = new HashMap&amp;lt;&amp;gt;();
            
            if(digits.equals(&quot;&quot;)) return new ArrayList&amp;lt;&amp;gt;();
            map.computeIfAbsent('2', k-&amp;gt; List.of(&quot;a&quot;, &quot;b&quot;, &quot;c&quot;));
            map.computeIfAbsent('3', k-&amp;gt; List.of(&quot;d&quot;, &quot;e&quot;, &quot;f&quot;));
            map.computeIfAbsent('4', k-&amp;gt; List.of(&quot;g&quot;, &quot;h&quot;, &quot;i&quot;));
            map.computeIfAbsent('5', k-&amp;gt; List.of(&quot;j&quot;, &quot;k&quot;, &quot;l&quot;));
            map.computeIfAbsent('6', k-&amp;gt; List.of(&quot;m&quot;, &quot;n&quot;, &quot;o&quot;));
            map.computeIfAbsent('7', k-&amp;gt; List.of(&quot;p&quot;, &quot;q&quot;, &quot;r&quot;, &quot;s&quot;));
            map.computeIfAbsent('8', k-&amp;gt; List.of(&quot;t&quot;, &quot;u&quot;, &quot;v&quot;));
            map.computeIfAbsent('9', k-&amp;gt; List.of(&quot;w&quot;, &quot;x&quot;, &quot;y&quot;, &quot;z&quot;));
            List&amp;lt;String&amp;gt; answer = new ArrayList&amp;lt;&amp;gt;();
            backtracking(map, digits, 0, new StringBuilder(), answer);

            return answer; 
        }

        private void backtracking(
            Map&amp;lt;Character,List&amp;lt;String&amp;gt;&amp;gt; map, String digits, int offset, StringBuilder comb,
            List&amp;lt;String&amp;gt; answer) {
                if(offset == digits.length()) {
                    answer.add(comb.toString());
                    return;
                }

                for(String l : map.get(digits.charAt(offset))) {
                    comb.append(l);
                    backtracking(map, digits, offset+1, comb, answer);
                    comb.deleteCharAt(comb.length()-1);
                }
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;회고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;숫자에 여러 알파벳이 매칭되어 있다. 숫자 조합이 입력으로 주어지고 숫자 조합으로 만들 수 있는 모든 알파벳 조합을 구하는 문제였다. dfs를 활용하여 문제를 해결하였다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. offset이 digits 길이가 되었을 때, answer에 알파벳 조합을 추가한다(add).&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 알파벳 조합(comb)을 업데이트할 때, 다음 조합을 고려해서 backtracking이 끝나면, 추가했던 알파벳을 제거하는 작업을 포함한다.&lt;/p&gt;
&lt;pre id=&quot;code_1745121021184&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for(String l : map.get(digits.charAt(offset))) {
                    comb.append(l);
                    backtracking(map, digits, offset+1, comb, answer);
                    comb.deleteCharAt(comb.length()-1);
                }&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm/LeetCode</category>
      <author>사랑우주인</author>
      <guid isPermaLink="true">https://lovelyalien.tistory.com/217</guid>
      <comments>https://lovelyalien.tistory.com/217#entry217comment</comments>
      <pubDate>Sun, 20 Apr 2025 12:50:45 +0900</pubDate>
    </item>
    <item>
      <title>macOS에서 Harbor 레지스트리 인증서 설정하기</title>
      <link>https://lovelyalien.tistory.com/216</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;MacOS에서 Docker 클라이언트가 사설 Harbor 레지스트리 통신하기 위해서 두 가지 주요 인증서 설정 작업이 필요하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Docker 전용 인증서 디렉토리에 CA 인증서 추가&lt;/h2&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1744287829132&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mkdir -p ~/.docker/certs.d/192.168.151.109/
cp ca.crt ~/.docker/certs.d/192.168.151.109/&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker 클라이언트가 특정 레지스트리와 통신할 때 사용할 인증서 제공&lt;/li&gt;
&lt;li&gt;Docker 애플리케이션에만 국한된 설정&lt;/li&gt;
&lt;li&gt;Docker 자체 인증서 검증 메커니즘에 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MacOS는 Docker Desktop을 사용하기 때문에 우분투 환경에서 설정하는 경로와 차이가 있다. 우분투 환경에서 설정 한다면 아래 명령어를 사용해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1744287978364&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mkdir -p /etc/docker/certs.d/192.168.151.109/
cp ca.crt /etc/docker/certs.d/192.168.151.109/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker 공식 문서에서 발췌한 내용은 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2422&quot; data-origin-height=&quot;1736&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciYTwu/btsNhZLY2y3/P3puufcGphpZGp5KPGrKSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciYTwu/btsNhZLY2y3/P3puufcGphpZGp5KPGrKSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciYTwu/btsNhZLY2y3/P3puufcGphpZGp5KPGrKSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciYTwu%2FbtsNhZLY2y3%2FP3puufcGphpZGp5KPGrKSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;502&quot; data-origin-width=&quot;2422&quot; data-origin-height=&quot;1736&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #e1e2e6; color: #000000; text-align: start;&quot;&gt;~/.docker/certs.d/&amp;lt;MyRegistry&amp;gt;:&amp;lt;Port&amp;gt;/client.cert&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt; 반드시 저 경로에 호스트 이름 디렉토리를 생성해서 지정해야 한다. 포트는 생략 가능하다. 마지막에는 docker restart를 진행해야 한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;b&gt;여기까지는 다른 OS도 동일하다.&lt;/b&gt; 아래 두번 째 절차는 MacOS에서 반드시 추가해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. macOS 시스템 키체인에 CA 인증서 추가&lt;/h2&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1744287856228&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ca.crt&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Docker for Mac은 macOS의 키체인(Keychain)에서도 인증서를 찾음&lt;/li&gt;
&lt;li&gt;security add-trusted-cert -d -r trustRoot -k ~/Library/Keychains/login.keychain ca.crt 명령으로 인증서 추가&lt;/li&gt;
&lt;li&gt;이 방법은 시스템 전체에 인증서를 신뢰할 수 있게 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker for Mac은 가상 환경에서 실행되므로 리눅스와 인증서 설정 방식이 다르다. 두 가지 설정 모두 적용해야 안정적으로 작동한다.&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;출처&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.docker.com/desktop/troubleshoot-and-support/faqs/macfaqs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.docker.com/desktop/troubleshoot-and-support/faqs/macfaqs/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/40822912/where-to-add-client-certificates-for-docker-for-mac&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://stackoverflow.com/questions/40822912/where-to-add-client-certificates-for-docker-for-mac&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/@mcschnei/docker-certificates-and-macos-de30e59238f8&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://medium.com/@mcschnei/docker-certificates-and-macos-de30e59238f8&lt;/a&gt;&lt;/p&gt;</description>
      <category>Programming</category>
      <author>사랑우주인</author>
      <guid isPermaLink="true">https://lovelyalien.tistory.com/216</guid>
      <comments>https://lovelyalien.tistory.com/216#entry216comment</comments>
      <pubDate>Thu, 10 Apr 2025 21:37:47 +0900</pubDate>
    </item>
    <item>
      <title>우분투 Harbor HTTPS 설정을 위한 인증서 생성</title>
      <link>https://lovelyalien.tistory.com/214</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Harbor HTTPS 설정을 위한 인증서 생성 과정&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인증 기관(CA) 인증서 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 환경이므로 외부 인증 기관 대신 자체 서명(Self-signed) 방식으로 CA 인증서를 생성한다.&lt;br /&gt;CA 인증서(ca.crt)는 CA의 개인 키(ca.key)를 기반으로 발급한다.&lt;/p&gt;
&lt;pre id=&quot;code_1744285163968&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 인증서 디렉토리 생성
mkdir ~/cert
cd ~/cert

# CA 인증서 개인 키 생성
openssl genrsa -out ca.key 4096

# CA 인증서 생성: CN에 Harbor를 설치할 서버의 IP주소 입력
openssl req -x509 -new -nodes -sha512 -days 3650 \
  -subj &quot;/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=192.168.151.109&quot; \
  -key ca.key \
  -out ca.crt&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;서버 인증서 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 인증서는 서버의 개인 키로 생성한 CSR(Certificate Signing Request)에 대해, CA가 서명함으로써 발급된다.&lt;br /&gt;CSR에는 서버의 공개 키 및 IP/도메인 등의 정보가 포함되며, 해당 정보는 인증서의 소유 주체 식별에 사용된다.&lt;/p&gt;
&lt;pre id=&quot;code_1744285182787&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1. 서버 인증서 개인 키 생성
openssl genrsa -out 192.168.151.109.key 4096

# 2. 서버 인증서 서명 요청(CSR) 생성 - IP 주소로 CN 변경
openssl req -sha512 -new \
-subj &quot;/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=192.168.151.109&quot; \
-key 192.168.151.109.key \
-out 192.168.151.109.csr

# 3. x509 v3 확장 설정 파일 생성 - DNS 대신 IP 사용
cat &amp;gt; v3.ext &amp;lt;&amp;lt;-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
IP.1=192.168.151.109
EOF

# 4. CA로 서버 인증서 서명하기
openssl x509 -req -sha512 -days 3650 \
-extfile v3.ext \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-in 192.168.151.109.csr \
-out 192.168.151.109.crt

# 5. 인증서 형식 변환 (Nginx용)
openssl x509 -inform PEM -in 192.168.151.109.crt -out 192.168.151.109.cert

# 6. Harbor에서 사용할 인증서 디렉토리 생성 및 인증서 복사
sudo mkdir -p /etc/docker/certs.d/192.168.151.109
sudo cp 192.168.151.109.cert /etc/docker/certs.d/192.168.151.109/
sudo cp 192.168.151.109.key /etc/docker/certs.d/192.168.151.109/
sudo cp ca.crt /etc/docker/certs.d/192.168.151.109/

# 7. harbor.yml 파일 수정 필요
 hostname: 192.168.151.109
 https:
   port: 443
   certificate: /etc/docker/certs.d/192.168.151.109/192.168.151.109.cert
   private_key: /etc/docker/certs.d/192.168.151.109/192.168.151.109.key

# 8. Harbor 재구성 및 재시작
cd ~/harbor
sudo ./prepare
sudo docker-compose down
sudo docker-compose up -d&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming</category>
      <author>사랑우주인</author>
      <guid isPermaLink="true">https://lovelyalien.tistory.com/214</guid>
      <comments>https://lovelyalien.tistory.com/214#entry214comment</comments>
      <pubDate>Thu, 10 Apr 2025 21:01:34 +0900</pubDate>
    </item>
    <item>
      <title>42898. 등굣길</title>
      <link>https://lovelyalien.tistory.com/213</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/42898?language=java&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/42898?language=java&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;제한사항&amp;nbsp;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;930&quot; data-origin-height=&quot;374&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L0oBa/btsNe8C9JG8/sQkhP8RDAN8b3z9eob5VDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L0oBa/btsNe8C9JG8/sQkhP8RDAN8b3z9eob5VDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L0oBa/btsNe8C9JG8/sQkhP8RDAN8b3z9eob5VDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL0oBa%2FbtsNe8C9JG8%2FsQkhP8RDAN8b3z9eob5VDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;241&quot; data-origin-width=&quot;930&quot; data-origin-height=&quot;374&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;풀이&lt;/h2&gt;
&lt;pre id=&quot;code_1744194814150&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    public int solution(int m, int n, int[][] puddles) {
        int answer = 0;
	    int[][] dp = new int[m+1][n+1];
		int[][] map = new int[m+1][n+1];
		for(int i = 0 ; i&amp;lt; puddles.length; i++) {
			int r = puddles[i][0];
			int c = puddles[i][1];
			map[r][c] = -1;
			}    
	    dp[1][1] = 1;
	    for(int i = 1 ; i &amp;lt;= m ; i++)
		    for(int j = 1; j &amp;lt;= n; j++) {
				if((i== 1 &amp;amp;&amp;amp; j ==1) || map[i][j] == -1) continue;

				dp[i][j] = (dp[i][j-1] + dp[i-1][j])  % 1000000007;
				
				
		    }
		answer = dp[m][n];
        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;회고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 단순한 DFS 문제라고 생각했지만, 이 문제는 최단 경로의 &lt;b&gt;길이&lt;/b&gt;가 아닌 &lt;b&gt;경우의 수&lt;/b&gt;를 구하는 문제이기 때문에 DFS는 시간 복잡도 측면에서 적절하지 않다고 판단했다. 출발지와 목적지가 고정되어 있고, 경로는 항상 오른쪽이나 아래쪽으로만 이동할 수 있기 때문에, 중복 계산을 방지하면서 효율적으로 결과를 구할 수 있는 &lt;b&gt;동적 계획법(DP)&lt;/b&gt;을 적용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dp[i][j]는 좌표 (i, j)까지 올 수 있는 경로의 수를 의미하며, 해당 위치가 웅덩이가 아닌 경우, 왼쪽(dp[i][j-1])과 위쪽(dp[i-1][j])에서 오는 경로의 수를 더하여 계산한다. 다만, 웅덩이인 경우는 경로가 될 수 없으므로 제외해야 한다. 즉, 핵심 점화식은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;dp[i][j] = dp[i-1][j] + dp[i][j-1] (단, 웅덩이가 아닌 경우)&lt;/li&gt;
&lt;li&gt;이때 값이 매우 커질 수 있으므로, 매 연산마다 1000000007로 나눈 나머지를 저장했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;642&quot; data-start=&quot;564&quot; data-ke-size=&quot;size16&quot;&gt;이번 문제를 통해 DP를 경로 문제에 어떻게 활용할 수 있는지를 다시 한 번 복습할 수 있었다.&lt;/p&gt;</description>
      <category>Algorithm/Programmers</category>
      <author>사랑우주인</author>
      <guid isPermaLink="true">https://lovelyalien.tistory.com/213</guid>
      <comments>https://lovelyalien.tistory.com/213#entry213comment</comments>
      <pubDate>Wed, 9 Apr 2025 19:43:36 +0900</pubDate>
    </item>
    <item>
      <title>12927. 야근 지수</title>
      <link>https://lovelyalien.tistory.com/212</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/12927&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://school.programmers.co.kr/learn/courses/30/lessons/12927&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;제한사항&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;304&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qyU66/btsNaHkKIqQ/6NlpIkW6NXmY5MAQHUx2ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qyU66/btsNaHkKIqQ/6NlpIkW6NXmY5MAQHUx2ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qyU66/btsNaHkKIqQ/6NlpIkW6NXmY5MAQHUx2ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqyU66%2FbtsNaHkKIqQ%2F6NlpIkW6NXmY5MAQHUx2ck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;228&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;304&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;풀이&lt;/h2&gt;
&lt;pre id=&quot;code_1743773165579&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.*;

class Solution {
    public long solution(int n, int[] works) {
        long answer = 0;
        // 최대 힙을 위한 람다 표현식을 사용한 Comparator 정의
        PriorityQueue&amp;lt;Integer&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;((a, b) -&amp;gt; b - a);
        for (int work : works) {
            pq.add(work);
        }

        for (int i = 0; i &amp;lt; n; i++) {
            if (pq.isEmpty()) break;
            int maxWork = pq.poll();
            if (maxWork &amp;gt; 0) {
                pq.add(maxWork - 1);
            }
        }

        while (!pq.isEmpty()) {
            int remainingWork = pq.poll();
            answer += (long) remainingWork * remainingWork;
        }

        return answer;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;회고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;야근 지수를 최소화하려면 남은 일 중 작업량이 최대인 것을 먼저 처리해야 한다. 야근 지수는 남은 작업량을 제곱하여 더하기 때문에 큰 작업량을 우선적으로 처리해야 제곱 합이 최소화될 것이다. 1시간에 작업량 1 만큼 처리할 수 있기 때문에, 1시간이 지날 때마다 남은 작업량 중 최대를 매번 찾아야 한다. 작업량 중 최대를 찾기 위해 순회(탐색) 한다면 시간 복잡도가 커질 것이다. 우선순위 큐를 이용한다면 매번 순회할 필요 없이 최대 작업량을 찾을 수 있다. 우선순위 큐는 힙 구조로 구현되었기 때문에, 삽입/삭제는 O(logn), 최대/최소 조회는 O(1) 시간 복잡도를 갖는다.&lt;/p&gt;</description>
      <category>Algorithm/Programmers</category>
      <author>사랑우주인</author>
      <guid isPermaLink="true">https://lovelyalien.tistory.com/212</guid>
      <comments>https://lovelyalien.tistory.com/212#entry212comment</comments>
      <pubDate>Fri, 4 Apr 2025 22:40:44 +0900</pubDate>
    </item>
  </channel>
</rss>