<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Do better Do best</title>
        <link>https://velog.io/</link>
        <description>대한민국의 미래를 묻는다면 고개를 들어 나를 쳐다보거라</description>
        <lastBuildDate>Tue, 10 Jun 2025 17:07:49 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Do better Do best</title>
            <url>https://velog.velcdn.com/images/korea_no_1/profile/e3dc6df8-a960-482c-809b-290c62296eac/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Do better Do best. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/korea_no_1" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[정보처리기사]]></title>
            <link>https://velog.io/@korea_no_1/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC</link>
            <guid>https://velog.io/@korea_no_1/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC</guid>
            <pubDate>Tue, 10 Jun 2025 17:07:49 GMT</pubDate>
            <description><![CDATA[<h2 id="주요-개념">주요 개념</h2>
<h3 id="1장">1장</h3>
<ul>
<li><p><strong>스크럼</strong> : <strong>팀</strong>이 중심이 되어 개발의 효율성을 높이는 기법</p>
<ul>
<li>PO (Product Owner) 제품 책임자</li>
<li>SM (Scrum Master) 스크럼 마스터</li>
<li>DT (Development Team) 개발팀</li>
</ul>
</li>
<li><p><strong>스프린트(Sprint)</strong> : 실제 개발 작업을 진행하는 과정으로, 보통 2~4주 정도의 기간 내에서 진행함</p>
</li>
<li><p><strong>XP(eXtreme Programming)</strong> : XP는 수시로 발생하는 고객의 <strong>요구사항에 유연하게 대응하기 위해 고객의 참여와 개발 과정의 반복을 극대화</strong>하여 개발 생산성을 향상시키는 방법</p>
<ul>
<li><strong>XP의 5가지 핵심 가치</strong><ul>
<li>의사소통(Communication)</li>
<li>단순성(Simplicity)</li>
<li>용기(Courage)</li>
<li>존중(Respect)</li>
<li>피드백(Feedback)</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>리팩토링(Refactoring)</strong> : 
기존 코드를 기능 변경 없이 구조나 디자인을 개선하는 과정</p>
<ul>
<li><strong>리팩토링(Refactoring)의 목적</strong> :
프로그램을 쉽게 이해하고 수정하여 빠르게 개발하기 위해서 </li>
</ul>
</li>
<li><p><strong>데이터베이스 관리 시스템(DBMS; DataBase Management System)</strong>
사용자와 데이터베이스 사이에서 사용자의 요구에 따라 <strong>정보를 생성해 주고, 데이터베이스를 관리해 주는 소프트웨어</strong> 이다. </p>
</li>
<li><p><strong>웹 애플리케이션 서버(WAS; Web Application Server)</strong>
사용자의 요구에 따라 변하는 <strong>동적인 콘텐츠를 처리하기 위해 사용되는 미들웨어</strong>이다.</p>
<ul>
<li>데이터 접근, 세션 관리, 트랜잭션 관리 등을 위한 라이브러리를 제공하는 것으로 주로 데이터베이스 서버와 연동해서 사용한다. </li>
</ul>
</li>
<li><p><strong>요구사항 개발 프로세스</strong>(출.석.명.확)
도출(Elicitation) -&gt; 분석(Analysis) -&gt; 명세(Specification) -&gt; 확인(Validation)</p>
<p>요구사항 도출은 시스템, 사용자, 개발자 등 <strong>시스템 개발에 관련된 사람들이 서로 의견을 교환하여 요구사항</strong>을 어떻게 수정할 것인지를 <strong>식별하고 이해하는 과정</strong>이다.</p>
<ul>
<li>소프트웨어 개발 생명 주기(SDLC) 동안 지속적으로 반복된다. </li>
</ul>
</li>
<li><p><strong>프로토타이핑(Prototyping)</strong>
프로토타이핑은 프로토타입(견본품)을 통해 효과적으로 요구 분석을 수행하면서 <strong>명세서를 산출하는 작업</strong>으로, 가장 단순한 형태는 설명을 위해 종이에 대략적인 순서나 형태를 그려 보여주는 것이다.</p>
</li>
</ul>
<blockquote>
<p>요구사항 명세에서 기능 요구항은 빠짐없이 기록하지만, 비기능 요구사항은 필요한 것만 기술한다. </p>
</blockquote>
<ul>
<li><p><strong>자료 흐름도(DFD)</strong>
<img src="https://velog.velcdn.com/images/korea_no_1/post/a453248b-807a-401b-826c-7ed85d14cd01/image.png" alt=""></p>
</li>
<li><p><strong>요구사항 분석용 CASE(자동화 도구)</strong>
요구사항 분석용 CASE는 <strong>요구사항을 자동으로 분석하고, 요구사항 분석 명세서를 기술하도록 개발된 도구</strong>를 의미한다. </p>
<ul>
<li><p>대표적인 요구사항 분석용 CASE</p>
<ul>
<li><strong>SADT</strong>(필기 20.9)<ul>
<li>시스템 정의, 소프트웨어 요구사항 분석, 시스템/소프트웨어 설계를 위한 도구</li>
<li>SoftTech 사에서 개발</li>
<li>구조적 요구 분석을 하기 위해 블록 다이어그램을 채택한 자동화 도구</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>HIPO(Hierarchy Input Process Output)</strong></p>
<ul>
<li>HIPO는 시스템의 분석 및 설계 또는 문서화에 사용되는 기법으로, <strong>시스템 실행 과정인 입력·처리·출력의 기능을 표현한 것</strong>이다</li>
<li>하향식 소프트웨어 개발을 위한 문서화 도구이다.</li>
</ul>
</li>
</ul>
<ul>
<li><p><strong>UML(Unified Modeling Language)</strong>
unified : 통일된</p>
<ul>
<li><p>UML은 시스템 분석, 설계, 구현 등 <strong>시스템 개발 과정</strong>에서 시스템 개발자와 고객 또는 개발자 상호 간의 <strong>의사소통이 원활하게 이루어지도록 표준화한 대표적인 객체지향 모델링 언어</strong>이다.</p>
</li>
<li><p>UML 구성 요소</p>
<ul>
<li><p>사물(Things)
<img src="https://velog.velcdn.com/images/korea_no_1/post/a4419c3b-c2a2-48d6-9314-a1c67a963ab0/image.png" alt=""></p>
</li>
<li><p>관계(Relationships)</p>
<ul>
<li>관계는 연관, 집합, 포함, 일반화 관계가 있다. 
<img src="https://velog.velcdn.com/images/korea_no_1/post/65ba0458-d2e9-48b1-b213-4e6ebfb4fc95/image.png" alt=""></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code>     - 연관 관계
       ![](https://velog.velcdn.com/images/korea_no_1/post/b183b648-826b-44e0-91ff-2c5cfb5e4096/image.png)
     - 집합(Aggregation) 관계
     ![](https://velog.velcdn.com/images/korea_no_1/post/9533baf3-5059-48f7-806d-a778c3482b69/image.png)

        전체(whole)와 부분(part)로 나누어 지며, 비어있는 다이아몬드가 있는 쪽이 전체이다. 해당 내용을 보면 school에는 student와 teacher가 있으며, student와 teacher은 다른 school로 갈 수 있다. 

      - 포함(Composition) 관계
      ![](https://velog.velcdn.com/images/korea_no_1/post/5f29af19-8cea-4fdc-8345-f451e4be6c76/image.png)

         포함 관계는 집합 관계의 특수한 형태로, 포함하는 사물의 __변화가 포함__되는 사물에게 영향을 미치는 관계이다. 

       - 일반화(Generalization) 관계
       ![](https://velog.velcdn.com/images/korea_no_1/post/dcfe8823-199d-42cb-88ea-3df32f007aad/image.png)

       일반화 관계는 __하나의 사물이 다른 사물에 비해 더 일반적이거나 구체적인 관계__이다. 
       &gt; 예를 들어 사람은 여자와 남자보다 일반적인 개념이고, 반대로 여자와 남자는 사람보다 구체적인 개념이다. 

       - 의존(Dependency) 관계
       ![](https://velog.velcdn.com/images/korea_no_1/post/0dd54738-a493-4897-8ff2-726ec532fd88/image.png)
       &gt; 사람은 자동차를 이용하여서 출퇴근을 한다. 이 경우 보통 같은 자동차를 이용한다. 하지만 자동차에 주유를 할 때, 특정 주유소에 있는 특정 주유기만을 사용하지 않는다. 이 같이 주유 서비스를 받을 때마다 달라지는 주유기같은 것을 의존 관계로 표현한다. 

         의존 관계는 연간 관계와 같이 사물 사이에 서로 연관은 있으나 필요에 의해 __서로에게 영향을 주는 짧은 시간 동안만 연관을 유지하는 관계__이다. 

         하나의 사물과 다른 사물이 소유 관계는 아니지만 사물의 변화가 다른 사물에도 영향을 미치는 관계이다. 

         영향을 받는 사물(이용자)이 영향을 주는 사물(제공자) 쪽으로 점선 화살표를 연결하여 표현하다. 



       - 실체화(Realization) 관계
       ![](https://velog.velcdn.com/images/korea_no_1/post/a9af6c68-28a0-4716-9a11-d5c8e4b31ee7/image.png)
       &gt; 비행기는 날 수 있고 새도 날 수 있다. 그러므로 비행기와 새는 날 수 있다는 행위로 그룹화 할 수 있다. </code></pre><blockquote>
<p>사람, 자동차, 컴퓨터, 동물 등과 같이 우리 주위에서 사용되는 물질적이거나 개념적인 것을 개체(Entity)라고 한다. 이러한 개체를 컴퓨터 내부에 추상적으로 표현한 것을 사물(Things) 또는 객체(Object)라고 하느데, 다이어그램을 표현할 때는 사물보다는 객체라는 표현을 주로 사용한다. </p>
</blockquote>
<ul>
<li><p><strong>다이어그램(Diagram)</strong></p>
<ul>
<li>다이어그램은 사물과 관계를 도형으로 표현한 것이다.</li>
<li>여러 관점에서 시스템을 가시화한 뷰(View)를 제공함으로써 의사소통에 도움을 준다</li>
<li>정적 모델링에서는 주로 구조적 다이어그램을 사용한다</li>
<li>동적 모델링에서는 주로 행위 다이어그램을 사용한다 </li>
</ul>
</li>
<li><p><strong>UML 다이어그램 종류</strong>
<img src="https://velog.velcdn.com/images/korea_no_1/post/ceced722-5229-4b1c-ab17-269f454477ff/image.png" alt=""></p>
<ul>
<li><p><strong>클래스 다이어그램</strong>
<img src="https://velog.velcdn.com/images/korea_no_1/post/8922c86a-6089-46fe-9a36-ad02eaaf2ccb/image.png" alt="">
클래스, 인터페이스, 추상 클래스 등 객체 지향 프로그래밍에서 사용되는 모든 요소를 보여준다. 3개의 직사각형으로 구성되며 맨 위부터 이름, 속성, 메소드가 명시되어 있다.
속성은 클래스의 상태를 나타내며 메소드는 클래스가 수행할 수 있는 작업을 나타낸다. 또한 클래스와 클래스 간의 관계는 일반적으로 상속, 연관, 집합, 의존 등으로 표현한다.   </p>
</li>
<li><p><strong>다중성 표시 방법</strong>
<img src="https://velog.velcdn.com/images/korea_no_1/post/068e4887-9cf0-4f68-8673-10fb6b159389/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<ul>
<li><p><strong>객체 다이어그램</strong>
<img src="https://velog.velcdn.com/images/korea_no_1/post/1ece4e21-1cf8-4b16-a560-2f4077eeafaf/image.png" alt="">
클래스 다이어그램과 유사하지만, 클래스 간의 관계를 보여주는 클래스 다이어그램과 달리 객체 다이어그램은 객체 간의 관계를 보여준다. 이는 객체 간의 상호작용을 파악할 수 있다. </p>
</li>
<li><p><strong>상태 다이어그램</strong>(기출 문제)</p>
<ul>
<li>하나의 객체가 자신이 속한 클래스의 상태 변화 혹은 다른 객체와의 상호 작용에 따라 상태가 어떻게 변화하는지를 표현함</li>
<li>럼바우(Rumbaugh) 객체지향 분석 기법에서 동적 모델링에 활용됨
<img src="https://velog.velcdn.com/images/korea_no_1/post/c1c44fca-1d49-4f2a-9e57-e55734f591ae/image.png" alt=""></li>
</ul>
</li>
</ul>
<ul>
<li><p><strong>스테레오 타입(Stereotype)</strong>  is not 고정관념</p>
<ul>
<li>스테레오 타입은 <strong>UML에서 표현하는 기본 기능 외에 추가적인 기능을 표현하는 것</strong> 이다. </li>
<li>길러멧(Guilemet)이라고 부르는 겹화살괄호« » 사이에 표현할 형태를 기술한다 </li>
<li>«incluede» : 연결된 다른 UML 요소에 대해 포함 관계에 있는 경우</li>
<li>«extends» : 연결된 다른 UML 요소에 대해 확장 관계에 있는 경우</li>
</ul>
</li>
<li><p><strong>컴포넌트(Component)</strong>
컴포넌트는 문서, 소스코드, 파일 라이브러리 등과 같은 모듈화된 자원으로, 재사용이 가능하다.</p>
</li>
<li><p><strong>인터페이스</strong>
클래스나 컴포넌트의 저체 또는 일부분의 동작(Operation)을 모아 놓은 것이며, 클래스가 외부적으로 가시화되는 행동을 표현한다.</p>
</li>
<li><p><strong>관계(Relationship)</strong></p>
<ul>
<li>시스템(System)
<img src="https://velog.velcdn.com/images/korea_no_1/post/0fbcce80-3e89-423a-9d52-96ee495b3329/image.png" alt=""></li>
<li>액터(Actor)
<img src="https://velog.velcdn.com/images/korea_no_1/post/5b386bb9-9dad-4ed0-80fd-7852a965c8d6/image.png" alt=""><ul>
<li>유스케이스(UseCase)
<img src="https://velog.velcdn.com/images/korea_no_1/post/b0ba0b23-9f97-4fb2-aecf-1c2a7a90beb0/image.png" alt=""></li>
<li>관계(Relationship)</li>
<li>연관 관계
<img src="https://velog.velcdn.com/images/korea_no_1/post/2cb9dd6b-1051-411f-8547-5e0a901b98be/image.png" alt=""></li>
<li>포함 관계(Include)
<img src="https://velog.velcdn.com/images/korea_no_1/post/bc455db9-4c42-4064-b471-c66e7cc8d148/image.png" alt=""></li>
<li>확장 관계(Extend)
<img src="https://velog.velcdn.com/images/korea_no_1/post/5009ec4e-7d75-44f9-a8e4-f9cf6cb7cadf/image.png" alt=""></li>
<li>일반화 관계(Generalization)
<img src="https://velog.velcdn.com/images/korea_no_1/post/cf6e31a9-76f3-4740-9560-19bc309817d5/image.png" alt=""></li>
</ul>
</li>
</ul>
<ul>
<li><strong>활동(Activity) 다이어그램</strong><ul>
<li><strong>사용자의 관점에서 시스템이 수행하는 기능을 처리흐름에 따라 순서대로 표현</strong>한 것이다.</li>
<li>하나의 유스케이스 안에서 혹은 유스케이스 사이에 발생하는 복잡한 처리의 흐름을 명확하게 표현할 수 있다</li>
<li>자료 흐름도와 유사하다</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/c0753121-de1b-4d6c-8178-7a8cd5d21fd4/image.png" alt=""></p>
<blockquote>
<p><strong>스윔레인(Swim Lane)</strong>
액티비티 수행을 담당하는 주체를 구분하는 선
가로 또는 세로 실선을 그어 구분한다. </p>
<blockquote>
<p>수영 경기장에서 각 선수별로 레인을 지정하여 해당 레인 안에서만 경기를 진행하도록 구분하는 것처럼 활동 다이어그램에서 사용되는 스윔레인도 액터나 시스템별로 처리 흐름이 진행되는 부분을 구분하기 위한 구분선이다.   </p>
</blockquote>
</blockquote>
</li>
<li><p><strong>객체지향 방법론의 구성 요소</strong></p>
<ul>
<li><strong>객체(Object)</strong> : 데이터와 데이터를 처리하는 함수를 묶어 놓은 하나의 소프트웨어 모듈</li>
<li><strong>클래스(Class)</strong> : 공통된 속성과 연산을 갖는 객체의 집합으로 객체의 일반적인 타입(Type)</li>
<li><strong>메시지(Message)</strong> : 객체들 간에 상호작용을 하는 데 사용되는 수단으로, 객체에게 어떤 행위를 하도록 지시하는 명령 또는 요구사항</li>
</ul>
</li>
<li><p><strong>객체지향 방법론의 기본 원칙</strong>  </p>
<ul>
<li><strong>캡슐화(Encapsulation)</strong> : 데이터와 데이터를 처리하는 함수를 하나로 묶는 것</li>
<li><strong>정보 은닉(Information Hiding)</strong> : 캡슐화에서 가장 중요한 개념으로, 다른 객체에게 자신의 정보를 숨기고 자신의 연산만을 통하여 접근을 허용하는 것</li>
<li><strong>추상화(Abstraction)</strong> : 불필요한 부분을 생략하고 객체의 속성 중 가장 중요한 것에 중점을 두어 개략화하는것</li>
<li><strong>상속성(Inheritance)</strong> : 이미 정의된 상위 클래스의 모든 속성과 연산을 하위 클래스가 물려받는 것</li>
<li><strong>다형성(Polymorphism)</strong> : 메시지에 의해 객체가 연산을 수행하게 될 때 하나의 메시지에 대해 각 객체가 가지고 있는 고유한 방법으로 응답할 수 있는 능력</li>
</ul>
</li>
<li><p><strong>컴포넌트(Component)</strong>
문서, 소스코드, 파일, 라이브버리 등과 같은 모듈화된 자원으로, 재사용이 가능하다. </p>
</li>
<li><p><strong>컴포넌트 기반(CBD) 방법론</strong>
컴포넌트를 조합하여 하나이 새로운 애플리케이션을 만드는 방법론</p>
</li>
<li><p><strong>소프트웨어 재사용 방법</strong></p>
<ul>
<li><strong>합성 중심(Composition-Based)</strong> : 
전자 칩과 같은 소프트웨어 부품, 즉 블록을 만들어서 끼워 맞춰 소프트웨어를 완성시키는 방법으로, 블록 구성 방법이라고도 함 </li>
<li><strong>생성 중심(Generation-Based)</strong> : 
<strong><code>추상화 형태로 써진 명세를 구체화</code></strong>하여 프로그램을 만드는 방법으로, 패턴 구성 방법이라고도 함</li>
</ul>
</li>
</ul>
<blockquote>
<h3 id="소프트웨어-재사용과-재공학의-차이">소프트웨어 재사용과 재공학의 차이</h3>
<p>재사용의 경우, 이미 개발되어 인정받은 소프트웨어를 다른 소프트웨어 개발이나 유지에 사용하는 것이며
재공학의 경우, 새로운 요구에 맞도록 기존 시스템을 이용하여 보다 나은 시스템을 구축하고, 새로운 기능을 추가하여 소프트웨어 성능을 향상시키는 것이다. 
재사용 방법에는 합성 중심과 생성 중심이 있다.</p>
</blockquote>
<ul>
<li><p><strong><code>CASE(Computer Aided Software Engineering)</code></strong>  </p>
<ul>
<li>CASE는 <strong>소프트웨어 개발 과정에서 사용되는</strong> 요구분석, 설계, 구현, 검사 및 디버깅 <strong>과정 전체 또는 일부를 컴퓨터와 전용 소프트웨어 도구를 사용하여 자동화하는 것</strong>이다. <blockquote>
<p> <strong>CASE의 주요기능</strong></p>
<ul>
<li>소프트웨어 생명 주기 전 단계의 연결</li>
<li>다양한 소프트웨어 개발 모형 지원</li>
<li>그래픽 지원</li>
</ul>
</blockquote>
</li>
</ul>
<blockquote>
<p><strong>CASE Tool(자동화 도구)</strong>
자동호 도구는 소프트웨어 공학과 관련된 직업 중에서 하나의 작업을 자동화하는 패키지를 의미한다</p>
</blockquote>
</li>
<li><p><strong>하향식 비용 산정 기법</strong>
하향식 비용 산정 기법은 <strong>과거의 유사한 경험을 바탕으로 전문 지식이 많은 개발자들이 참여한 회의를 통해 비용을 산정하는</strong> 비과학적인 방법이다.</p>
</li>
</ul>
<p>산정 기법으로는 전문가 감정 기법, 델파이 기법이 있다</p>
<p>전문가 감정 기법의 경우 <strong>경험이 많은 두 명 이상의 전문가에게 비용 산정을 의뢰하는 기법</strong>이다.</p>
<p>델파이 기법의 경우 <strong>전문가 감정 기법의 주관적인 편견을 보완하기 위해 많은 전문가의 의견을 종합하여 산정하는 기법</strong>이다. </p>
<ul>
<li><strong>상향식 비용 산정 기법</strong>
상향식 비용 산정 기법은 프로젝트의 <strong>세부적인 작업 단위별로 비용을 산정한 후 집계하여 전체 비용을 산정하는 기법</strong>이다. </li>
</ul>
<p>산정 기법으로는 LOC(원시 코드 라인 수), 개발 단계별 인월수 기법, 수학적 산정 기법이 있다. </p>
<ul>
<li><p>LOC(원시 코드 라인 수, source Line of Code) 기법
계산 방법 : 예측치 = a+4m+b/6 (a:낙관치 b: 비관치, m:기대치(중간치))</p>
</li>
<li><p>개발 단계별 인월수(Effort Per Task) 기법</p>
<ul>
<li>각 기능을 구현시키는 데 필요한 노력을 생명 주기의 각 단계별로 산정하는 기법이다</li>
<li>LOC 기법을 보완하기 위해 만들어졌기 때문에 LOC 기법보다 정확하다. </li>
</ul>
</li>
</ul>
<blockquote>
<p>LOC 기법에 의하여 소프트웨어 개발에 소요되는 노력이 40PM(Programmer-Month)으로 계산되었다. 개발에 소요되는 기간이 5개월이고, 1인당 인건비가 100만원 이라면, 이 프로젝트에 소요되는 개발 비용은 얼마인지 구하시오</p>
<blockquote>
<p>개발 비용 = 노력(인월)x단위 비용(1인당 월평균 인건비) 
40 x 1,000,000 = 40,000,000</p>
</blockquote>
</blockquote>
<ul>
<li><p><strong>수학적 산정 기법</strong></p>
</li>
<li><p><strong><code>COCOMO(COnstructive COst MOdel)</code></strong></p>
<ul>
<li>COCOMO 모형은 원시 프로그램의 규모인 LOC에 의한 <strong>비용 산정 기법</strong>이다.</li>
<li>비용 산정 결과는 프로젝트를 완성하는 데 필요한 노력(Man-Month)으로 나타난다.</li>
<li>보헴(Boehm)이 제안하였다</li>
</ul>
</li>
<li><p><strong>COCOMO의 소프트웨어 개발 유형</strong></p>
<ul>
<li><p>조직형(Organic Mode)</p>
<ul>
<li>기관 내부에서 개발된 중·소 규모의 소프트웨어</li>
<li>일괄 자료 처리나 과학기술 계산용, 비즈니스 자료 처리용 등의 5만(50KDSI)라인 이하의 소프트웨어를 개발하는 유형</li>
<li>사무 처리용, 업무용, 과학용 응용 소프트웨어 개발에 적합함</li>
</ul>
<p>cf.. KDSI : 전체 라인수를 1,000라인 단위로 묶은 것(=Kilo LOC)</p>
</li>
<li><p>반분리형(Semi-Detached Mode)</p>
<ul>
<li>조직형과 내장형의 중간형 소프트웨어</li>
<li>트랜잭션 처리 시스템이나 운영체제, 데이터베이스 관리 시스템 등의 30만(300KDSI) 라인 이하의 소프트웨어를 개발하는 유형</li>
<li>컴파일러, 인터프리터와 같은 유틸리티 개발에 적합함</li>
</ul>
</li>
<li><p>내장형(Embedded Mode)</p>
<ul>
<li>초대형 규모의 소프트웨어</li>
<li>트랜잭션 처리 시스템이나 운영체제 등의 30만(300KDSI) 라인 이상의 소프트웨어를 개발하는 유형</li>
<li>신호기 제어 시스템, 미사일 유도 시스템, 실시간 처리 시스템 등의 시스템 프로그램 개발에 적합함</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>COCOMO 모형의 종류</strong>
기본형, 중간형, 발전형이 있다</p>
</li>
</ul>
<ul>
<li><p><strong>Putnam 모형</strong>
Putnam 모형은 <strong>소프트웨어 생명 주기의 전 과정 동안에 <code>사용될 노력의 분포를 예상하는 모형</code></strong>이다.
Putnam(푸트남)이 제안하였으며, Rayleigh-Norden 곡선의 노력 분포도를 기초로 한다. 또한, 개발 기간이 늘어날수록 프로젝트의 적용 인원의 노력이 감소한다. </p>
</li>
<li><p><strong><code>기능 점수(FP, Function Point) 모형</code></strong>
기능 점수 모형은 <strong>소프트웨어의 기능을 증대시키는 요인별</strong>로 가중치를 부여하고, 요인별 가중치를 합산하여 총 기능 점수를 산출하며, 총 기능 점수와 영향도를 이용하여 기능 점수(FP)를 구한 후 이를 이용해서 비용을 산정하는 기법이다. </p>
</li>
<li><p><strong><code>SLIM</code></strong></p>
</li>
<li><p><em>Rayleigh-Norden 곡선*</em>과 <strong>Putnam 예측 모델</strong>을 기초로 하여 개발된 자동화 추정 도구</p>
</li>
<li><p><strong>PERT 차트</strong>
<img src="https://velog.velcdn.com/images/korea_no_1/post/235e51f9-fe09-473c-aa1b-961f8933b648/image.png" alt=""></p>
</li>
</ul>
<p>프로젝트에 필요한 전체 작업의 상호 관계를 표시하는 네트워크로, 작업들간의 상호 관련성, 결정 경로, 경계 시간, 자원 할당 등을 제시하는 프로젝트 일정 계획 기법이다. </p>
<ul>
<li><p><strong>간트 차트</strong>
<img src="https://velog.velcdn.com/images/korea_no_1/post/69b8db0e-2cf0-4fd9-a525-429e9c2b4643/image.png" alt=""></p>
<ul>
<li>프로젝트 각 작업들의 시작과 종료에 대한 작업 일정을 표시하는 프로젝트 일정표로, 시간선(Time-Line)차트라고도 한다.</li>
<li>막대로 표시하며, 수평 막대의 길이는 각 작업(Task)의 기간을 나타낸다.</li>
</ul>
</li>
<li><p><strong>프로젝트 관리(Project Management)</strong>
일정 관리, 비용 관리, 인력 관리, 위험 관리, 품질 관리가 있다</p>
</li>
</ul>
<ul>
<li><strong>CMMI(Capability Maturity Model Integration)</strong><ul>
<li>CMMI는 <strong>소프트웨어 개발 조직의 업무 능력 및 조직의 성숙도를 평가하는 모델</strong>이다. </li>
<li>초기, 관리, 정의, 정량적 관리, 최적화 -&gt; <strong><code>기.관.정.량.화</code></strong></li>
</ul>
</li>
</ul>
<ul>
<li><p><strong>SPICE</strong>
소프트웨어 개발 표준 중 정보 시스템 분야에서 <strong>소프트웨어의 품질 및 생산성 향상을 위해 소프트웨어 프로세스를 평가 및 개선하는 국제 표준</strong>으로, 공식 명칭은 <strong>ISO/IEC 15504</strong>인 것.</p>
</li>
<li><p><strong>소프트웨어 개발 프레임워크</strong></p>
<ul>
<li>개발해야 할 애플리케이션의 일부분이 이미 내장된 클래스 라이브러리로 구현이 되어 있다.</li>
<li>따라서, 그 기반이 되는 부분을 찾아 확장 및 이용하는 것으로 볼 수 있다</li>
<li>JAVA 기반의 대표적인 소프트웨어로는 스프링(Spring)이 있다.</li>
</ul>
</li>
<li><p><strong><code>소프트웨어 개발 프레임워크 특성</code></strong></p>
<ul>
<li>모듈화(Modularity) : 프레임워크는 캡슐화를 통해 모듈화를 강화하고 설계 및 구현의 변경에 따른 영향을 최소화함으로써 소프트웨어의 품질을 향상 시킨다</li>
<li>재사용성(Reusability) : 프레임워크는 다시 사용이 가능한 모듈들을 제공함으로써 예산 절감, 생산성 향상, 품질 보증이 가능하다</li>
<li>제어의 역흐름(Inversion of Control) : 개발자가 관리하고 통제해야 하는 객체들의 제어를 프레임워크에 넘김으로써 생산성을 향상시킴</li>
<li>확장성(Extensibility) : 프레임워크는 다형성(Polymorphism)을 통한 인터페이스의 확장이 가능하여 다양한 형태와 기능을 가진 애플리케이션 개발이 가능함.</li>
</ul>
<p>cf. 다형성 : 하나의 인터페이스나 타입을 통해 여러 다른 형태의 객체를 참조하고 조작할 수 있는 기능</p>
</li>
</ul>
<h3 id="n장">N장</h3>
<h4 id="디자인-패턴">디자인 패턴</h4>
<blockquote>
<p><strong>디자인 패턴(Design Pattern) 이란?</strong>
디자인 패턴은 개발하면서 발생하는 <strong>반복적인 문제</strong>들을 어떻게 해결할 것인지에 대한 <strong>해결 방안</strong>으로 실제 현업에서 비즈니스 요구 사항을 프로그래밍으로 처리하면서 만들어진 다양한 해결책 중에서 많은 사람들이 인정한 <strong>모범 사례(Best Practice)</strong> 이다. 
이러한 디자인 패턴은 객체 지향 4대 특성(캡슐화, 상속, 추상화, 다형성)과 설계 원칙(SOLID)을 기반으로 구현되어 있다. </p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/14dcb19a-79e9-4587-a57f-613fa078d10e/image.png" alt=""></p>
<h4 id="생성-패턴creational-pattern">생성 패턴(Creational Pattern)</h4>
<ul>
<li><strong>Singleton(싱글톤 패턴)</strong> : 하나의 클래스 인스턴스를 전역에서 접근 가능하게 하면서 해당 인스턴스가 한 번만 생성되도록 보장하는 패턴이다. </li>
<li><strong>Factory Method(팩토리 메서드 패턴)</strong> : 객체를 생성하기 위한 인터페이스를 정의하고, 서브클래스에서 어떤 클래스의 인스턴스를 생성할지 결정하는 패턴이다. </li>
<li><strong>Abstract Factory(추상 팩토리 패턴)</strong> : 관련된 객체들의 집합을 생성하는 인터페이스를 제공하며, 구체적인 팩토리 클래스를 통해 객체 생성을 추상화하는 패턴이다. </li>
<li><strong>Builder(빌더 패턴)</strong> : 복잡한 객체의 생성 과정을 단순화하고, 객체를 단계적으로 생성하며 구성하는 패턴이다. </li>
<li><strong>Prototype(프로토타입 패턴)</strong> : 객체를 복제하여 새로운 객체를 생성하는 패턴으로, 기존 객체를 템플릿으로 사용하는 패턴이다. </li>
</ul>
<h4 id="구조-패턴structural-pattern">구조 패턴(Structural Pattern)</h4>
<ul>
<li><strong>Adapter(어댑터 패턴)</strong> : 인터페이스 <u>호환성을 제공하지 않는 클래스를 사용하기 위해</u> 래퍼(Wrapper)를 제공하는 패턴이다. </li>
<li><strong>Bridge(브릿지 패턴)</strong> : 추상화와 구현을 분리하여 두 가지를 독립적으로 확장할 수 있는 패턴이다.</li>
<li><strong>Composite(컴포지트 패턴)</strong> : 개별 객체와 복합 객체를 동일하게 다루어, <u>트리 구조의 객체</u>를 구성하는 패턴</li>
<li><strong>Decorator(데코레이터 패턴)</strong> : 객체에 <u>동적으로 새로운 기능을 추가</u>하여 객체를 확장할 수 있는 패턴</li>
<li><strong>Proxy(프록시 패턴)</strong> : 다른 객체에 대한 대리자(Proxy)를 제공하여 접근 제어, 지연 로딩 등을 구현하는 패턴</li>
<li><strong>Facade(퍼사드(정면) 패턴)</strong> : 서브시스템을 더 쉽게 사용할 수 있도록 단순한 인터페이스를 제공하는 패턴이다.</li>
<li><strong>Flyweight(플라이웨이트 패턴)</strong> : 공유 가능한 객체를 통해 메모리 사용을 최적화하는 패턴이다.</li>
</ul>
<h4 id="행위-패턴behavioral-pattern">행위 패턴(Behavioral Pattern)</h4>
<ul>
<li><strong>Command(커맨드 패턴)</strong> : 요청을 객체로 캡슐화하여 요청을 매개변수화 하고, 요청을 큐에 저장하거나 로깅하고 실행을 지연시킨다. </li>
<li><strong>Interpreter(인터프리터 패턴)</strong> : 언어나 문법에 대한 해석기를 제공하여, 주어진 언어로 표현된 문제를 해결하는 패턴이다.</li>
<li><strong>Iterator(이터레이터 패턴)</strong> : 컬렉션 내의 요소들에 접근하는 방법을 표준화하여 컬렉션의 내부 구조에 독립적으로 접근할 수 있는 패턴이다. -&gt; 순차적 접근</li>
<li><strong>Mediator(중재자 패턴)</strong> : 객체 간의 상호 작용을 캡슐화하여, 객체 간의 직접적인 통신을 방지하는 패턴이다.</li>
<li><strong>Observer(옵저버 패턴)</strong> : 객체 간의 일대다 종속 관계를 정의하여 한 객체의 상태 변경이 다른 객체들에게 알려지도록 한다.</li>
<li><strong>Visitor(방문자)</strong> : 각 클래스들의 데이터 구조에서 처리 기능을 분리하여 별도로 구성함으로써, 클래스를 수정하지 않고도 새로운 연산의 추가가 가능함</li>
<li><strong>Stratege(전략 패턴)</strong> : 알고리즘을 정의하고, 실행 중에 선택할 수 있게 한다.</li>
<li><strong>State(상태 패턴)</strong> : 객체의 상태를 캡슐화하고, 상태 전환을 관리한다.</li>
<li><strong>Chain of Responsibility(책임 연쇄 패턴)</strong> : 요청을 보내는 객체와 이를 처리하는 객체를 분리하여, 다양한 처리자 중 하나가 요청을 처리한다</li>
<li><strong>Memento(메멘토(기억/기념) 패턴)</strong> : 객체의 내주 상태를 저장하고 복원할 수 있는 기능을 제공하는 패턴이다</li>
<li><strong>Template Method(템플릿 메서드 패턴)</strong> : 알고리즘의 구조를 정의하면서 하위 클래스에서 각 단계의 구현을 제공하는 디자인 패턴이다.</li>
</ul>
<h4 id="테스트-설계-기법">테스트 설계 기법</h4>
<ul>
<li><p>구문 or 문장 커버리지 </p>
<ul>
<li>조건 : 문장 1회 </li>
<li>모든 문장이 적어도 한 번 실행</li>
<li>테스트 Suite에 실행된 구문이 몇 퍼센트인지를 측정</li>
</ul>
</li>
<li><p>분기 or 결정 커버리지 </p>
<ul>
<li>조건 : T/F </li>
<li>모든 결정의 분기가 적어도 한번씩은 실행되어야 함</li>
</ul>
</li>
<li><p>조건 커버리지(분기 커버리지 하위)</p>
<ul>
<li>조건 : T/F</li>
<li>전체 조건식의 결과와 관계없이 각 개별 조건식이 참/거짓 한번 모두 갖도록 수행</li>
</ul>
</li>
<li><p>조건/결정 커버리지</p>
<ul>
<li>조건 : TT/FF</li>
<li>전체 조건식 참/거짓 한번씩 하면서 개별 조건식 참/거짓 모두 한번씩 갖도록 함</li>
</ul>
</li>
<li></li>
</ul>
<h3 id="9장">9장</h3>
<h4 id="암호-알고리즘">암호 알고리즘</h4>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/aedc4077-bfdd-488b-af1f-727c98808c51/image.png" alt=""></p>
<p>비밀키(개인키)와 공개키의 차이</p>
<ul>
<li><p>비밀키(개인키)는 <strong>동일한 키로 데이터를 암호화하고 복호화</strong> 한다.</p>
<ul>
<li>대칭 암호 기법 또는 단일키 암호화 기법이라고 한다</li>
</ul>
</li>
<li><p>공개키 기법은 데이터를 <strong>암호화할 때 사용하는 공개키(Public Key)</strong>는 사용자에게 <strong>공개</strong>하고, <strong>복호화할 때의 비밀키</strong>는 관리자가 <strong>비밀리에 관리</strong>한다.</p>
</li>
</ul>
<h4 id="양방향-알고리즘의-종류">양방향 알고리즘의 종류</h4>
<ul>
<li>DES : 미국 NBS에서 발표한 개인키 암호화 알고리즘
 블록 크기 : 64비트 , 키 길이 : 56비트  / DES를 3번 적용한 3DES도 있다</li>
<li>AES : DES의 한계를 느낀 NIST가 발표
블록 크기 : 128 비트 , 키 길이에 따라 AES-128, -192, -256 으로 분류</li>
<li>RSA : MIT에서 만들었으며, 큰 숫자를 <strong>소인수분해</strong>하기 어렵다는 것에 기반하여 만들어짐</li>
<li>ECC : 1985년 RSA암호 방식으로 이산대수 문제를 <strong>타원곡선</strong>으로 옮겨 기밀성과 효율성을 높였다.</li>
<li>IDEA : 스위스의 라이와 <strong>메시</strong>가 만듦</li>
<li>Skipjack : 클리퍼 칩(Clipper Chip)이라는 IC칩에 내장
주로 <strong>음성 통신 장비에 삽입</strong>되어 음성 데이터를 암호화</li>
<li>TKIP : <strong>무선랜 보안</strong></li>
</ul>
<h4 id="서비스-공격-유형">서비스 공격 유형</h4>
<h2 id="cs">CS</h2>
<h3 id="웹-서버와-wasweb-application-server의-차이점">웹 서버와 WAS(Web Application Server)의 차이점</h3>
<blockquote>
<p><strong>웹 서버</strong>
웹 브라우저 클라이언트로부터 HTTP 요청을 받아들이고, HTML 문서와 같은 웹 페이지를 반환하는 컴퓨터 프로그램</p>
</blockquote>
<p>웹 서버란, 사용자가 웹 브라우저(Chrome)에서 어떠한 페이를 요청하면 웹 서버에서 그 요청을 받아 <strong><code>정적 컨텐츠를 제공하는 서버</code></strong>이다. 여기서 정적 컨텐츠란 단순 HTML 문서, CSS, Javascript, 이미지, 파일 등 즉시 응답 가능한 컨텐츠 이다. </p>
<p>그렇다면, 웹 서버는 정적만 제공하냐?
-&gt; 그것은 아니다. 웹 서버가 동적 컨텐츠를 요청 받으면 WAS에게 해당 요청을 넘겨주고, WAS에서 처리한 결과를 사용자에게 전달해주는 역할도 한다. </p>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/70efb93b-ea3c-4f14-ab61-8e809faecafa/image.png" alt=""></p>
<blockquote>
<p><strong>WAS</strong>
인터넷 상에서 HTTP 프로토콜을 통해 사용자 컴퓨터나 장치에 애플리케이션을 수행하는 미들웨어로서, 주로 동적 서버 컨텐츠를 수행하는 것으로 웹 서버와 구별이 되며, 주로 데이터베이스 서버와 같이 수행한다. </p>
</blockquote>
<p>WAS는 웹 서버와 웹 컨테이너가 합쳐진 형태로, 웹 서버 단독으로 처리할 수 없는 <strong><code>데이터베이스의 조회나 다양한 로직 처리가 필요한 동적 콘텐츠를 제공</code></strong>한다. 덕분에 사용자의 다양한 요구에 맞춰 웹 서비스를 제공할 수 있다. WAS는 JSP, Servlet 구동환경을 제공해주기 때문에 <strong>웹 컨테이너</strong> 혹은 <strong>서블릿 컨테이너</strong> 라고도 불린다. </p>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/19b32d2f-caf4-49cd-a946-f492ef817e97/image.png" alt=""></p>
<blockquote>
<h3 id="💡-그렇다면-was만-써도-되겠네-답은-❌">💡 그렇다면 WAS만 써도 되겠네!? 답은 (❌)</h3>
<p>WAS는 DB조회 및 다양한 로직을 처리하는데 집중해야 해서 단순한 정적 컨텐츠는 웹 서버에서 맡기며 기능을 분리시켜 <strong>서버 부하를 방지</strong>해야해. 만약 WAS가 정적 콘텐츠 요청까지 처리하면, 부하가 커지고 동적 콘텐츠 처리가 지연되면서 수행 속도가 느려지고 이로 인해 페이지 노출 시간이 늘어나는 문제가 발생하여서 효율성이 크게 떨어져</p>
</blockquote>
<p><strong><code>웹 서버를 WAS 앞에 두고 필요한 WAS들을 Web Server에 플러그인 형태로 설정하면 더욱 효율적인 분산 처리가 가능하다</code></strong></p>
<h3 id="umlunified-modeling-language을-사용하는-이유">UML(Unified Modeling Language)을 사용하는 이유</h3>
<blockquote>
<p>많은 사람들이 모여 작업을 수행하다 보면 같은 대상물을 보고도 서로 다르게 표현하여 의사소통에 문제가 생기는 경우가 있다. 이러한 문제를 해결하기 위해 공통된 표현 방법을 만들어서 사용하는 것이다. 
UML은 공통된 표현법을 사용하는 개발할 대상물을 <strong>다이어그램</strong>으로 표현하는 도구이다.  </p>
</blockquote>
<h3 id="클래스class와-객체object의-차이">클래스(Class)와 객체(Object)의 차이</h3>
<blockquote>
<p>클래스는 객체를 생성하기 위한 설계도 또는 템플릿이고, 객체는 클래스에 의해 생성된 실체 또는 인스턴스이다. 클래스는 객체의 속성(데이터)과 행동(메서드)을 정의하며, 객체는 이러한 정의를 기반으로 메모리에 할당되어 실제 사용되는 개체를 의미한다. </p>
</blockquote>
<p><strong><code>클래스 : 붕어빵 틀</code>
<code>객체(인스턴스) : 붕어빵</code></strong> -&gt; 객체 하나하나를 인스턴스라고 부르며, 대체로 객체와 인스턴스는 혼용해서 표현한다.</p>
<p><code>객체들이 가질 수 있는 속성과 동작을 추상적으로 표현한 것이 클래스(Class)이다.</code></p>
<h3 id="활동activity-다이어그램의-요소-중-액션action과-액티비티activity의-차이점을-간략히-서술하시오">활동(Activity) 다이어그램의 요소 중 액션(Action)과 액티비티(Activity)의 차이점을 간략히 서술하시오</h3>
<blockquote>
<p>액션(Action)은 더 이상 분해할 수 없는 단일 작업이고, 액티비티(Activity)는 몇 개의 액션으로 분리될 수 있는 작업이다.</p>
</blockquote>
<h3 id="uml-다이어그램-중-다음과-같은-특징을-갖는-다이어그램이-무엇인지-쓰시오">UML 다이어그램 중 다음과 같은 특징을 갖는 다이어그램이 무엇인지 쓰시오</h3>
<blockquote>
<ul>
<li>시스템이나 객체들이 메시지를 주고받으며 시간의 흐름에 따라 상호 작용 하는 과정을 액터, 객체, 링크, 메시지 등의 요소를 사용하여 그림으로 표현한 것이다</li>
</ul>
</blockquote>
<ul>
<li>동작에 참여하는 객체들이 주고받는 메시지를 표현하는데 메시지뿐만 아니라 <strong>객체들 간의 관계</strong>까지 표현한다</li>
<li>클래스 다이어그램에서 관계가 제대로 표현됐는지 점검하는 용도로도 사용된다.</li>
<li>초기에는 협업(Collaboration) 다이어그램이라고 불렸다<blockquote>
<blockquote>
<p><strong>커뮤니케이션(Communication) 다이어그램</strong></p>
</blockquote>
</blockquote>
</li>
</ul>
<h3 id="커뮤니케이션의-요소-중-객체들-간의-관계를-표현하는데-사용하는-요소가-무엇인지-쓰시오">커뮤니케이션의 요소 중 객체들 간의 관계를 표현하는데 사용하는 요소가 무엇인지 쓰시오</h3>
<h4 id="커뮤니케이션communication-다이어그램이-순차sequence-다이어그램과-구별되는-가장-큰-특징은-메시지뿐만-아니라-객체들-간의-관계까지-표현한다는-것이다">커뮤니케이션(Communication) 다이어그램이 순차(Sequence) 다이어그램과 구별되는 가장 큰 특징은 메시지뿐만 아니라 객체들 간의 관계까지 표현한다는 것이다.</h4>
<blockquote>
<p>링크(Link)</p>
</blockquote>
<h3 id="소프트웨어-재공학software-reengineering의-개념을-간략히-서술하시오">소프트웨어 재공학(Software Reengineering)의 개념을 간략히 서술하시오</h3>
<blockquote>
<p>소프트웨어 재공학은 기존 시스템을 이용하여 보다 나은 시스템을 구축하고, 새로운 기능을 추가하여 소프트웨어 성능을 향상시키는 것이다.</p>
</blockquote>
<h3 id="많은-전문가들의-의견을-종합하여-산정하는-기법은-무엇인가">많은 전문가들의 의견을 종합하여 산정하는 기법은 무엇인가</h3>
<h4 id="소프트웨어-비용-산정-기법-중-전문가-감정-기법의-주관적인-편견을-보완하기-위해서">소프트웨어 비용 산정 기법 중 전문가 감정 기법의 주관적인 편견을 보완하기 위해서</h4>
<blockquote>
<p>델파이 기법</p>
</blockquote>
<h3 id="소프트웨어-프로젝트-관리의-개념을-간략히-서술">소프트웨어 프로젝트 관리의 개념을 간략히 서술</h3>
<blockquote>
<p>소프트웨어 프로젝트 관리는 <u>주어진 기간 내에 최소의 비용으로 사용자를 만족시키는 시스템을 개발</u>하기 위한 전반적인 활동이다. </p>
</blockquote>
<h3 id="cmmi의-개념-서술">CMMI의 개념 서술</h3>
<h4 id="소프트웨어-개발-표준-중-cmmi능력-성숙도-통합-모델의-개념">소프트웨어 개발 표준 중 CMMI(능력 성숙도 통합 모델)의 개념</h4>
<blockquote>
<p>CMMI는 소프트웨어 개발 조직의 업무 능력 및 조직의 성숙도를 평가하는 모델</p>
</blockquote>
<h3 id="테일러링의-개념을-간략히-서술">테일러링의 개념을 간략히 서술</h3>
<h4 id="소프트웨어-개발-방법론-테일러링에-대해서">소프트웨어 개발 방법론 테일러링에 대해서</h4>
<blockquote>
<p>소프트웨어 개발 방법론 테일러링은 <strong>소프트웨어 개발 방법론의 절차, 사용기법 등을 수정 및 보완하는 작업</strong>이다.</p>
</blockquote>
<h3 id="스프링-프레임워크">스프링 프레임워크</h3>
<blockquote>
<p>소프트웨어 개발 프레임워크 중 EJB(Enterprise JAVA Beans) 기반의 복잡함과 무거움을 극복하고 개발 생산성 향상과 고품질의 시스템 개발을 위한 자바 플랫폼상의 경량화된 오픈 소스 웹 애플리케이션 프레임워크</p>
</blockquote>
<h3 id="char와-varchar">CHAR와 VARCHAR</h3>
<blockquote>
<p>CHAR은 항상 지정된 크기만큼 기억 장소가 확보되고 VARCHAR은 기억 장소의 크기가 지정되어도 필드에 저장된 데이터만큼만 기억 장소가 확보된다. </p>
</blockquote>
<h3 id="인덱스index">인덱스(Index)</h3>
<blockquote>
<p>인덱스는 검색 시간을 단축시키기 위해 만든 보조적인 데이터 구조이다. </p>
</blockquote>
<h3 id="클러스터드-인덱스clustered-index">클러스터드 인덱스(Clustered Index)</h3>
<blockquote>
<p>인덱스 키의 순서에 따라 데이터가 정렬되어 저장되는 방식이다. 실제 데이터가 순서대로 저장되어 있어 인덱스를 검색하지 않아도 원하는 데이터를 빠르게 찾을 수 있다. 하지만 데이터 삽입, 삭제 발생 시 순서를 유지하기 위해 데이터를 재정렬 해야한다. </p>
</blockquote>
<h3 id="트랜잭션transaction">트랜잭션(Transaction)</h3>
<blockquote>
<p>트랜잭션(Transaction)은 데이터베이스에서 여러 작업(명령어)들을 하나의 묶음으로 처리하는 단위이다. 쉽게 말해, 여러 개의 작업을 한 번에 처리하고 그 결과가 모두 성공해야만 실제로 데이터에 반영되도록 만드는 기능이다.</p>
</blockquote>
<p>ex. 예를 들어 은행에서 돈을 이체할 때,</p>
<ol>
<li>내 계좌에서 돈을 빼고</li>
<li>친구 계좌에 돈을 넣는
두 가지 작업이 동시에 이루어져야 한다. 만약 한 작업만 성공을 하고 나머지는 실패하면 문제가 발생한다. 이 두 작업을 묶어서 &#39;둘 다 성공해야만 실제로 처리한다&#39;는 약속이 바로 트랜잭션이다.</li>
</ol>
<p><strong>즉 트랜잭션은 COMMIT 되거나 ROLLBACK 되어야 한다</strong></p>
<h3 id="3-way-handshake">3-way-handshake</h3>
<blockquote>
<p>신뢰성 있는 연결을 위해 송신지(보내는 곳)와 수신지(받는 곳) 간의 통신에 앞서 3단계에 걸친 확인 작업을 수행한 후 통신을 수행한다.</p>
</blockquote>
<ul>
<li>1단계 : 송신지에서 수신지로 &#39;SYN&#39; 패킷을 전송</li>
<li>2단계 : 수신지에서 송신지로 &#39;SYN&#39; + &#39;ACK&#39; 패킷을 전송</li>
<li>3단계 : 송신지에서 수신지로 &#39;ACK&#39; 패킷을 전송<blockquote>
<p>SYN 패킷의 경우 연결 요청을 의미하는 패킷이다.</p>
</blockquote>
</li>
</ul>
<h2 id="문제">문제</h2>
<p>Q. 소프트웨어 개발 방법론 중 프로토타입 모형(Prototype Model)에 대해 간략히 서술</p>
<blockquote>
<p>A. 프로토타입은 개발될 소프트웨어에 대한 견본품을 만들어 최종 결과물을 예측</p>
</blockquote>
<p>Q. 요구공학(Requirement Engineering)의 개념을 간략히 서술하시오</p>
<blockquote>
<p>A. 요구공학은 요구사항을 정의하고, 분석 및 관리하는 프로세스를 연구하는 학문</p>
</blockquote>
<h2 id="코딩">코딩</h2>
<h4 id="약수-중-자신을-제외한-약수-모두-합을-하면-자신과-같아지는-완전-수">약수 중 자신을 제외한 약수 모두 합을 하면 자신과 같아지는 완전 수</h4>
<blockquote>
<p>ex. 6의 약수 1,2,3,6 중 자신을 제외한 1,2,3을 모두 더하면 6이 된다.</p>
</blockquote>
<pre><code>#include &lt;stdio.h&gt;

main() {
    int s, el = 0; 
    for (int i = 6; i&lt;=30; i++) {   // i는 6부터 30까지 
        s = 0; 
        for (int j=1; j &lt;=i/2; j++)
            if(i%j == 0)
                s = s + j;
        if(s==i)
            el++;
    }
    printf(&quot;%d&quot;, el);
}</code></pre><h4 id="싱글톤singleton-디자인-패턴">싱글톤(Singleton) 디자인 패턴</h4>
<blockquote>
<p>한 번만 생성되고, 계속 그 하나만 쓰는 객체</p>
</blockquote>
<pre><code>class Connection {
    private static Connection _inst = null;  // 전역에서 딱 1개만 존재하는 인스턴스
    private int count = 0;                   // 호출 횟수 저장하는 변수

    public static Connection get() {
        if (_inst == null) {                 // 아직 생성되지 않았다면
            _inst = new Connection();        // 새로 만들어서
        }
        return _inst;                        // 항상 같은 인스턴스를 반환
    }

    public void count() { count++; }         // count를 1 증가
    public int getCount() { return count; }  // count 값을 리턴
}

public class Test {
    public static void main(String[] args) {
        Connection conn1 = Connection.get(); // 새 객체 생성됨
        conn1.count();                       // count = 1

        Connection conn2 = Connection.get(); // 기존 객체 재사용
        conn2.count();                       // count = 2

        Connection conn3 = Connection.get(); // 기존 객체 재사용
        conn3.count();                       // count = 3

        conn1.count();                       // count = 4

        System.out.print(conn1.getCount());  // 4 출력
    }
}
</code></pre><h4 id="완전수">완전수</h4>
<blockquote>
<p>1부터 100까지의 &#39;완전수&#39;를 찾아서 더하는 프로그램
1부터 100사이의 완전수는 &#39;6&#39;과 &#39;28&#39;이 있다</p>
</blockquote>
<pre><code>#include &lt;stdio.h&gt;
int isPerfectNum(int num) {
    int sum = 0;
    for (int i =1; i&lt;num; i++) {
        if (num % i == 0) 
            sum += i;
    }
    if (num==sum) return 1
    else return 0
}

main() {
    int r = 0;
    for (int i = 1; i &lt;= 100; i++)
        if (isPerfectNum(i))
            r+= i;
    printf(&quot;%d&quot;, r);
}</code></pre><h4 id="코드-오류">코드 오류</h4>
<blockquote>
<p>public static String get() {
    return name;
    } 부분에서 오류 발생</p>
<p>정적 메서드에서 일반 변수(name)을 쓸 수 없다</p>
</blockquote>
<pre><code>class Person {
    private String name;
    public Person(String val) {
        name = val; 
    }
    public static String get() {
        return name; 
    }
    public void print() {
        System.out.println(name);
    }
}

public class Test {
    public static void main (String[] args) {
        Person obj = new Person(&quot;Kim&quot;);
        obj.print();
    }
}
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[자바를 Java!]]></title>
            <link>https://velog.io/@korea_no_1/%EC%9E%90%EB%B0%94%EB%A5%BC-Java</link>
            <guid>https://velog.io/@korea_no_1/%EC%9E%90%EB%B0%94%EB%A5%BC-Java</guid>
            <pubDate>Mon, 31 Mar 2025 11:57:18 GMT</pubDate>
            <description><![CDATA[<h2 id="들어가기에-앞서">들어가기에 앞서...</h2>
<h3 id="java-특징"><strong>Java 특징</strong></h3>
<ul>
<li><strong>객체 지향</strong> : Java는 주로 객체 지향 프로그래밍(OOP) 언어이다. 즉, 데이터와 기능을 나타내는 객체의 사용을 강조한다.</li>
<li><strong>플랫폼 독립성</strong> : Java 프로그램은 JVM에서 실행할 수 있는 바이트코드로 컴파일 된다. 이를 통해 Java 애플리케이션은 코드를 다시 컴파일할 필요 없이 호완되는 JVM이 있는 모든 플랫폼에서 실행할 수 있다</li>
<li><strong>자동 메모리 관리</strong> : Java는 사용되지 않는 메모리(garbage collection) 수집 메커니즘을 통해 자동 메모리 관리를 제공한다. 프로그램에서 더 이상 필요하지 않은 메모리를 자동으로 회수하여 개발자가 메모리를 더 쉽게 관리할 수 있도록 한다.</li>
<li><strong>표준 라이브러리</strong> : Java는 입/출력, 네트워킹, 스레딩 및 데이터 구조와 같은 일반적인 프로그래밍 작업을 위한 광범위한 클래스와 함수를 제공하는 포괄적인 표준 라이브러리와 함께 제공된다</li>
<li><strong>멀티스레딩</strong> : Java는 멀티스레딩을 지원하여 프로그램이 여러 스레드를 동시에 실행할 수 있도록 한다. 이것은 독립적으로 수행할 수 있는 작업에 유용하며 특정 유형의 응용 프로그램의 성능을 향상시킬 수 있다.</li>
</ul>
<h3 id="java-프로그램-실행-과정">Java 프로그램 실행 과정</h3>
<ul>
<li><p>Java 프로그램에서 모든 소스 코드는 텍스트 파일로 작성되고 .java 확장자를 가진다.</p>
</li>
<li><p>이 소스코드가 javac 컴파일러에 의해 컴파일 되어 .class 파일로 만들어진다.</p>
</li>
<li><p>이 .class 파일은 실행되는 컴퓨터의 네이티브 코드(native code)를 가지고 있지 않은 상태로 바이트코드(bytecode)를 가지고 있다</p>
</li>
<li><p>바이트코드는 JVM(Java Virtual Machine: 자바가상기계)에서 실행될 수 있는 기계어 코드이다.</p>
</li>
<li><p>JVM이 설치되어 있는 컴퓨터에서 java 명령어를 사용하여 .class 파일을 실행한다. 
<img src="https://velog.velcdn.com/images/korea_no_1/post/976e415b-bd1e-4b71-8977-80675920efa5/image.png" alt=""></p>
</li>
<li><p>.class 바이트 코드는 JVM이 설치된 어떤 이기종 컴퓨터에서도 실행이 가능하다.</p>
</li>
<li><p>또한, JVM은 Java 프로그램과 하드웨어 사이에 위치하여 Java 프로그램 개발을 위한 API를 제공하고 Java 바이트코드를 해석항 실행하는 역할을 한다. </p>
</li>
</ul>
<h2 id="cs-지식">cs 지식</h2>
<h3 id="spring">SPRING</h3>
<blockquote>
<h3 id="스프링의-진짜-핵심"><strong>스프링</strong>의 진짜 핵심</h3>
</blockquote>
<ul>
<li><p>스프링은 <strong>자바언어</strong> 기반의 프레임워크</p>
</li>
<li><p>자바 언어의 가장 큰 특징 - <strong>객체 지향 언어</strong></p>
</li>
<li><p>스프링은 객체 지향 언어가 가진 <strong>강력한 특징</strong>을 살려내는 프레임워크</p>
</li>
<li><p>스프링은 <strong>좋은 객체 지향</strong> 애플리케이션을 개발할 수 있게 도와주는 프레임워크
&lt;-&gt; 이전에 존재한 EJB은 객체 지향 특징을 잃어버리게 사용한다. </p>
<h4 id="그렇다면-좋은-객체-지향-이란-무엇이냐">그렇다면 <em>좋은 객체 지향</em> 이란 무엇이냐</h4>
<blockquote>
<h4 id="객체-지향-특징">객체 지향 특징</h4>
</blockquote>
</li>
<li><p><strong>추상화</strong> </p>
</li>
<li><p><strong>캡슐화</strong></p>
</li>
<li><p><strong>상속</strong></p>
</li>
<li><p><strong>다형성</strong></p>
</li>
</ul>
<h4 id="객체-지향-프로그래밍">객체 지향 프로그래밍</h4>
<ul>
<li><p>객체 지향 프로그래밍은  컴퓨터 프로그램을 명령어의 목록으로 보는 시각에서 벗어나 여러개의 독립된 단위, 즉 <strong>&#39;객체&#39;</strong>들의 <strong>모임</strong>으로 파악하고자 하는 것이다. 각각의 <strong>객체</strong>는  <strong>메시지</strong>를 주고받고, 데이터를 처리할 수 있다. <strong>(협력)</strong></p>
</li>
<li><p>객체 지향 프로그래밍은 프로그램을 <strong>유연</strong>하고 <strong>변경</strong>이 용이하게 만들기 때문에 대규모 소프트웨어 개발에 많이 사용된다. </p>
</li>
</ul>
<blockquote>
<p><strong>유연</strong>하고, <strong>변경이 용이</strong>하다? 이게 무엇이냐</p>
</blockquote>
<ul>
<li>레고 블럭 조립하듯이 </li>
<li>키보드, 마우스 갈아 끼우듯이</li>
<li>컴퓨터 부품 갈아 끼우듯이</li>
<li>컴포넌트를 쉽고 유연하게 변경하면서 개발할 수 있는 방법이다. <h3 id="--다형성">-&gt; <strong>다형성</strong></h3>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/0f53acd7-7e95-4a2a-b2a0-4c0253624cdd/image.png" alt=""></p>
<p>자동차의 역할은 앞으로 가는 것이다. </p>
<p>자동차가 바뀌어도 운전자에게 영향을 주지 않는다.
이를 통하여서 운전자는 <strong>자동차의 역할에 의존</strong>하고 있음을 알 수 있다. </p>
<p>운전자는 자동차의 내부구조를 몰라도 된다.
내부적으로 바뀌어도 자동차 역할만 그래도 맞춘다면 사용자에게 영향을 주지 않는다.</p>
<p>이를 통하여서 운전자에게 영향을 주지 않고 새로운 기능을 제공할 수 있다</p>
<p>이것이 가능한 이유는 <strong>역할과 구현으로 세상을 구분</strong>하였기 때문이다. </p>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/69de7063-ca1c-4468-ab62-974f24a82644/image.png" alt=""></p>
<ul>
<li>로미오 역할의 경우 줄리엣 역할에 대해서 몰라도 된다.</li>
<li>배우는 대체가 가능해야 한다.</li>
</ul>
<blockquote>
<p><strong>유연</strong>하고 <strong>변경이 용이</strong>하다. </p>
</blockquote>
<h3 id="역할과-구현을-분리">역할과 구현을 분리</h3>
<ul>
<li><strong>역할</strong>과 <strong>구현</strong>으로 구분하면 세상이 <strong>단순</strong>해지고, <strong>유연</strong>해지면 <strong>변경</strong>도 편리해진다. </li>
<li><strong>장점</strong><ul>
<li><strong>클라이언트</strong>는 대상의 역할(인터페이스)만 알면 된다</li>
<li><strong>클라이언트</strong>는 구현 대상의 <strong>내부 구조를 몰라도</strong> 된다.</li>
<li><strong>클라이언트</strong>는 구현 대상의 <strong>내부 구조가 변경</strong>되어도 영향을 받지 않는다.</li>
<li><strong>클라이언트</strong>는 구현 <strong>대상 자체를 변경</strong>해도 영향을 받지 않는다. </li>
</ul>
</li>
</ul>
<h4 id="자바-언어">자바 언어</h4>
<ul>
<li><p>자바 언어의 <strong>다형성</strong>을 활용</p>
<ul>
<li><p>역할 = 인터페이스</p>
</li>
<li><p>구현 = 인터페이스를 구현한 클래스, 구현 객체</p>
</li>
<li><p>객체를 설계할 때 <strong>역할</strong>과 <strong>구현</strong>을 명확히 분리</p>
</li>
<li><p>객체 설계시 역할(인터페이스)을 먼저 부여하고, 그 역할을 수행하는 구현 객체 만들기</p>
<blockquote>
<p><strong>역할 &gt; 구현</strong> ( <strong>역할이 구현보다 중요하다</strong> ) </p>
</blockquote>
</li>
<li><p>클라이언트 : <strong>요청</strong></p>
</li>
<li><p>서버 : <strong>응답</strong>
<img src="https://velog.velcdn.com/images/korea_no_1/post/cd875a16-9f0d-4cb1-b47c-79b70de37f56/image.png" alt=""></p>
</li>
</ul>
</li>
</ul>
<blockquote>
<p>서버가 클라이언트가 되어서 다른 서버에게 요청할 수 있다. 
해당 부분에서 응답이, 꼭 데이터를 넣어서 return 값이 없어도 된다. </p>
</blockquote>
<h4 id="오버로딩-vs-오버라이딩">오버로딩 vs 오버라이딩</h4>
<ul>
<li>오버로딩 : </li>
</ul>
<hr>
<h2 id="용어">용어</h2>
<ul>
<li><p><strong>IoC(Inversion of Control) 제어의 역전</strong></p>
<ul>
<li>IoC를 설명할 때 흔히들 <code>할리우드 원칙</code>을 들어서 설명하곤 한다. </li>
</ul>
</li>
<li><p><strong>DI</strong></p>
</li>
<li><p><strong>SOLID</strong></p>
</li>
</ul>
<h2 id="코드">코드</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[먹을 수 있는 해는? 파이썬!]]></title>
            <link>https://velog.io/@korea_no_1/%EB%A8%B9%EC%9D%84-%EC%88%98-%EC%9E%88%EB%8A%94-%ED%95%B4%EB%8A%94-%ED%8C%8C%EC%9D%B4%EC%8D%AC</link>
            <guid>https://velog.io/@korea_no_1/%EB%A8%B9%EC%9D%84-%EC%88%98-%EC%9E%88%EB%8A%94-%ED%95%B4%EB%8A%94-%ED%8C%8C%EC%9D%B4%EC%8D%AC</guid>
            <pubDate>Sat, 29 Mar 2025 08:46:31 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/korea_no_1/post/1b2cf6bd-ca62-4d39-a44d-7334fda8eb1b/image.png" alt=""></p>
<h3 id="가상환경-설정">가상환경 설정</h3>
<pre><code>1. python -m venv 가상환경이름    
2. 가상환경이름\Scripts\activate</code></pre><p><a href="https://quite-a-bit.tistory.com/14">가상환경 및 파이썬 버전 참고사이트</a></p>
<h3 id="셀레니움-동적-크롤링">셀레니움 동적 크롤링</h3>
<p><a href="https://wikidocs.net/149358">동적 크롤링 관련 자료</a>
<strong>.env 파일에 klas 로그인 정보 필요</strong></p>
<pre><code>from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import time
import os
import re
from dotenv import load_dotenv
from pymongo import MongoClient
from selenium.common.exceptions import UnexpectedAlertPresentException, NoAlertPresentException, ElementNotInteractableException
from pymongo.errors import CursorNotFound

# 환경 변수 로드
load_dotenv()

# MongoDB 연결 설정
client = MongoClient(os.getenv(&quot;MONGO_URI&quot;))
db = client.get_database()
collection = db[&quot;class&quot;]

# Selenium 웹드라이버 설정
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))

def handle_alert():
    try:
        alert = driver.switch_to.alert
        alert_text = alert.text
        if &quot;폐강된 강의입니다&quot; in alert_text:
            print(&quot;폐강된 강의입니다. 경고창을 닫고 넘어갑니다.&quot;)
            alert.accept()
            return True
    except NoAlertPresentException:
        return False

def search_and_update(course_name):
    try:
        search_field = driver.find_element(By.XPATH, &#39;/html/body/main/div/div/div/div[2]/div[2]/table[1]/tbody/tr[2]/td[1]/input&#39;)
        search_field.clear()
        time.sleep(1)
        search_field.send_keys(course_name)

        search_button = driver.find_element(By.XPATH, &#39;/html/body/main/div/div/div/div[2]/div[2]/div/button&#39;)
        search_button.click()
        time.sleep(3)

        results = driver.find_elements(By.XPATH, &#39;/html/body/main/div/div/div/div[2]/div[2]/table[2]/tbody/tr&#39;)

        for i in range(len(results)):
            try:
                results = driver.find_elements(By.XPATH, &#39;/html/body/main/div/div/div/div[2]/div[2]/table[2]/tbody/tr&#39;)
                results[i].click()
                time.sleep(5)

                if handle_alert():
                    continue

                class_idx_element = driver.find_element(By.XPATH, &#39;//*[@id=&quot;appModule&quot;]/div[2]/div[2]/table[1]/tbody/tr[2]/td[1]&#39;)
                class_idx = class_idx_element.text.strip()

                class_in_db = collection.find_one({&quot;class_idx&quot;: class_idx})
                if class_in_db:
                    classroom_element = driver.find_element(By.XPATH, &#39;//*[@id=&quot;appModule&quot;]/div[2]/div[2]/table[1]/tbody/tr[4]/td[1]&#39;)
                    classroom_text = classroom_element.text.strip()
                    matches = re.findall(r&#39;\((.*?)\)&#39;, classroom_text)
                    classroom_idx = &#39;, &#39;.join(set(matches)) if matches else &quot;&quot;

                    print(f&quot;강의명: {course_name}, 강의 ID: {class_idx}, 강의실: {classroom_idx}&quot;)

                    collection.update_one(
                        {&quot;class_idx&quot;: class_idx}, 
                        {&quot;$set&quot;: {&quot;classroom_idx&quot;: classroom_idx}}, 
                        upsert=True
                    )

                back_button = driver.find_element(By.XPATH, &#39;//*[@id=&quot;appModule&quot;]/div[2]/div[2]/div/button&#39;)
                back_button.click()
                time.sleep(3)
            except UnexpectedAlertPresentException:
                if handle_alert():
                    continue
            except Exception as e:
                print(f&quot;오류 발생: {e}&quot;)
                continue
    except ElementNotInteractableException:
        print(f&quot;입력 필드 비활성화 오류 발생: {course_name} 검색 시 문제 발생&quot;)
    except Exception as e:
        print(f&quot;검색 오류 발생: {e}&quot;)

def handle_cursor_timeout():
    while True:
        try:
            return list(collection.find({}, {&quot;class_name&quot;: 1, &quot;_id&quot;: 0}).batch_size(10))
        except CursorNotFound:
            print(&quot;커서가 만료되었습니다. 다시 시도합니다.&quot;)
            time.sleep(1)

try:
    driver.get(&quot;https://klas.kw.ac.kr/usr/cmn/login/LoginForm.do&quot;)
    time.sleep(2)

    id_field = driver.find_element(By.XPATH, &#39;//*[@id=&quot;loginId&quot;]&#39;)
    password_field = driver.find_element(By.XPATH, &#39;//*[@id=&quot;loginPwd&quot;]&#39;)
    id_field.send_keys(os.getenv(&quot;ID&quot;))
    password_field.send_keys(os.getenv(&quot;PASSWORD&quot;))

    login_button = driver.find_element(By.XPATH, &#39;/html/body/div[1]/div/div/div[2]/form/div[2]/button&#39;)
    login_button.click()
    time.sleep(5)

    driver.get(&quot;https://klas.kw.ac.kr/std/cps/atnlc/LectrePlanStdPage.do&quot;)
    time.sleep(3)

    page_size = 100
    total_courses = collection.count_documents({})

    for page in range(0, total_courses, page_size):
        courses = handle_cursor_timeout()[page:page+page_size]
        processed_courses = set()

        for course in courses:
            if course[&quot;class_name&quot;] in processed_courses:
                continue
            search_and_update(course[&quot;class_name&quot;])
            processed_courses.add(course[&quot;class_name&quot;])
finally:
    driver.quit()
</code></pre><p>vscode 확장자(다운했던것들)
<img src="https://velog.velcdn.com/images/korea_no_1/post/814a4ab6-7905-4dd3-8ac2-e602f6c4c608/image.png" alt="">
<img src="https://velog.velcdn.com/images/korea_no_1/post/9b163af7-0460-49e8-8cdf-b4d2099b5167/image.png" alt="">
<img src="https://velog.velcdn.com/images/korea_no_1/post/908171a5-1f39-4c05-a961-2121f3bd728e/image.png" alt="">
<img src="https://velog.velcdn.com/images/korea_no_1/post/3952d6ee-63ac-4ffb-96f1-ea7da7d1d536/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[API에 관한 모든 것]]></title>
            <link>https://velog.io/@korea_no_1/API%EC%97%90-%EA%B4%80%ED%95%9C-%EB%AA%A8%EB%93%A0-%EA%B2%83</link>
            <guid>https://velog.io/@korea_no_1/API%EC%97%90-%EA%B4%80%ED%95%9C-%EB%AA%A8%EB%93%A0-%EA%B2%83</guid>
            <pubDate>Sun, 10 Nov 2024 16:08:45 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/korea_no_1/post/bc3d6914-66d5-4ffa-b444-2242e7db4c37/image.png" alt=""></p>
<blockquote>
<p>해당 내용은 수업에서 설명한 부분이 아닌 수업 이외의 내용을 작성한 부분입니다. 
API에 대해서 자주 언급되지만 볼때마다 헷갈린 나를 위해 작성하는 페이지</p>
</blockquote>
<h3 id="api란">API란?</h3>
<p>: 스마트폰으로 카카오톡에 로그인하려는 상황을 떠올려보자
스마트폰이 보낸 로그인 요청은 카카오 본사의 서버 컴퓨터 중 하나가 받은 다음, 알맞은 응답을 다시 스마트폰에 돌려주게 된다. (로그인 처리시키기 or &#39;로그인 성공&#39; 메시지 띄우기)</p>
<p>이것이 <strong>클라이언트 - 서버</strong> 구조 이다.
클라이언트는 로그인뿐만 아니라, 여러 요청들을 서버에 보내게 되는데, 각 요청들을 일일이 대응하는 것은 비효율적일 것이다. </p>
<p>그렇기에 각각의 요청들을 담당하는 서버에게 요청이 잘 전달될 수 있도록 교통정리를 해주는 체계가 <strong>&#39;API&#39;</strong>이다.</p>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/a5584874-529d-44c9-b251-74c193151be8/image.png" alt=""></p>
<p><strong>어떠한 방식으로 정보를 요청해야 하는지, 그리고 그러한 요청을 보냈을 때 어떠한 형식으로 무슨 데이터를 전달받을 수 있는지</strong>에 대해서 정리한 일종의 규격이라고 볼 수 있다.</p>
<p>API의 풀네임은 Application Programming Interface로서 애플리케이션이 인터페이싱(요청과 응답을 주고받는) 체계라고 이해하면 된다. </p>
<h3 id="api-구현-및-형식">API 구현 및 형식</h3>
<h4 id="api-구현-방법">API 구현 방법</h4>
<p>: API를 작성하는 다양한 방법이 있으나, 가장 많이 사용하는 방법은 REST API이며, 아래에 더 자세하게 다루어보도록 하겠다</p>
<h4 id="api-결과데이터-제공-형식">API 결과(데이터) 제공 형식</h4>
<p>: 주고 받는 데이터 형식은 주로 &#39;JSON&#39;, &#39;XML&#39;이다. 요청의 결과로 받는 데이터의 구조에도 통일감을 줄 수 있도록 공통의 포맷을 정한 것으로, 최근에는 <strong>JSON 형태</strong>를 많이 사용하고 있다. </p>
<ul>
<li><p><strong>JSON(JavaScript Object Notation) 이란?</strong>
: JSON은 사람이 읽을 수 있고 시스템에서 구문 분석할 수 있는 방식으로 데이터를 저장하고 교환하기 위한 텍스트 기반 형식이다. 결과적으로 JSON은 비교적 쉽게 학습하고 문제를 해결할 수 있다. </p>
<p><strong>JSON과 HTML, XML 비교</strong></p>
<ul>
<li><strong>JSON</strong>: 일반적으로 데이터 저장 및 전송에 사용된다. JSON은 간단하고 사용하기 쉬운 데이터 형식의 이점을 누릴 수 있는 애플리케이션을 위해 널리 사용되는 선택이다.</li>
<li><strong>XML</strong>(Extensible Markup Language) : 보다 복잡한 데이터 구조를 허용하는 JSON과 유사한 범용 마크업 언어이다. </li>
<li><strong>HTML</strong> : 웹 페이지의 구조 및 콘텐츠를 생성하는데 사용된다. CSS와 JavaScript와 같은 다른 언어와 함께 웹 사이트의 스타일을 통합하고 페이지에 상호 작용을 추가하는데 사용되는 경우가 많다.</li>
</ul>
</li>
</ul>
<h4 id="api-활용-방법">API 활용 방법</h4>
<p>: API 문서란, 각 기업이 만든 API의 사용법이 담긴 일종의 API 매뉴얼로, 어던 기능을 불러 올 수 있는지, 각 기능에 필요한 정보를 받아오기 위해서는 어떠한 방식으로 요청해야 하는지 등이 상세히 기술되어 있다. </p>
<ul>
<li><p><strong>Rest API</strong> 
: REST(Representational State Transfer)의 약자로 자원을 이름으로 구분하여 해당 자원의 상태를 주고받는 모든 것을 의미한다. </p>
<p>Represent가 &#39;표현하다&#39;는 뜻인 점을 염두에 두면, &#39;요청 자체만 보고 내가 무엇을 원하는지 알게 하자(=요청 자체로 나를 &#39;표현&#39;하자&#39;)는 사상으로 등장하였다.</p>
<p>클라이언트와 서버는 고유한 url(링크)을 통해 요청과 응답을 주고받게 되는데 이 url만 보면 어떤 요청인지 바로 추론할 수 있다.</p>
</li>
</ul>
<h4 id="즉-rest란"><strong>즉 REST란</strong></h4>
<ol>
<li>HTTP URI(Uniform Resource Identifier)를 통해 자원(Resource)을 명시하고, </li>
<li>HTTP Method(Post, Get, Put, Delete, Patch 등)를 통해</li>
<li>해당 자원(URI)에 대한 CRUD Operation을 적용하는 것을 의미한다.</li>
</ol>
<blockquote>
<p><strong>CRUD Operation 이란</strong>
CRUD는 대부분의 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능인 Create(생성), Read(읽기), Update(갱신), Delete(삭제)를 묶어서     일컫는 말로 REST에서의 CRUD Operation 동작 예시는 다음과 같다</p>
</blockquote>
<ul>
<li><p><strong>REST 구성 요소</strong></p>
<ul>
<li>자원(Resource) : HTTP URI</li>
<li>자원에 대한 행위(Verb) : HTTP Method<ul>
<li>자원에 대한 행위의 내용(Representations) : HTTP Method Pay Load</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>REST의 특징</strong></p>
<ul>
<li>Server-Client(서버-클라이언트 구조)<ul>
<li>Stateless(무상태)</li>
<li>Cacheable(캐시 처리 가능)</li>
<li>Layered System(계층화)</li>
<li>Uniform Interface(인터페이스 일관성)</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>REST의 장단점</strong></p>
<ul>
<li><p><em><strong>장점</strong></em></p>
<ul>
<li>HTTP 프로토콜의 인프라를 그래도 사용하므로 REST API 사용을 위한 별도의 인프라를 구축할 필요가 없다. </li>
<li>HTTP 프로토콜의 표준을 최대한 활용하여 여러 추가적인 장점을 함께 가져갈 수 있게 해준다.</li>
<li>HTTP 표준 프로토콜에 따르는 모든 플랫폼에서 사용이 가능하다</li>
<li>Hypermedeia API의 기본을 충실히 지키면서 범용성을 보장한다</li>
<li>REST API 메시지가 의도하는 바를 명확하게 나타내므로 의도하는 바를 쉽게 파악할 수 있다</li>
<li>여러 가지 서비스 디자인에서 생길 수 있는 문제를 최소화한다</li>
<li>서버와 클라이언트의 역할을 명확하게 분리한다</li>
</ul>
</li>
<li><p><em><strong>단점</strong></em></p>
</li>
<li><p>표준 자체가 존재하지 않아 정의가 필요하다</p>
</li>
<li><p>HTTP Method 형태가 제한적이다</p>
</li>
<li><p>브라우저를 통해 테스트할 일이 많은 서비스라면 쉽게 고칠 수 있는 URL보다 Header 정보의 값을 처리해야 하므로 전문성이 요구된다</p>
</li>
<li><p>구형 브라우저에서 호환이 되지 않아 지원해주지 못하는 동작이 많다(익스플로어)</p>
</li>
</ul>
</li>
</ul>
<h4 id="api-필요성">API 필요성</h4>
<ul>
<li><p><strong>개발 및 관리의 효율성</strong>
: API를 사용하면, 실제로 서비스가 어떻게 구현되었는지는 몰라도 그 서비스를 그대로 가져다 사용할 수 있다.
즉, 매번 새로운 개발을 할 필요 없이 이미 만들어 놓은 기능을 그대로 &#39;블록&#39;처럼 가져다 쓸 수 있다
덕분에 <strong>개발 시간이 줄어들고 개발에 필요한 비용도 아낄 수 있다</strong> 또한, API 문서만 보면 누구나 쉽게 이해할 수 있어, 협업에 용이하고 유지보수도 수월하다</p>
</li>
<li><p><strong>유연성, 확장성</strong>
: 서비스의 신규 개발과 웹/앱 등 채널 확장이 쉽다. 특히 타사 서비스와의 연계에 있어 가장 큰 장점을 자랑한다. </p>
</li>
</ul>
<h4 id="open-api란">Open API란?</h4>
<p>: Open API는 말 그대로 <strong>&#39;누구나 쓸 수 있도록 공개된(open) API&#39;</strong>를 의미한다
Open API가 유행하는 이유는, 아무래도 플랫폼의 영향력이 곧 돈이 되기 때문이다. 자사의 서비스가 타사의 다양한 서비스에서도 활용된다면, 사용자 수가 증가하는 등 서비스 자체의 가치도 높아질 것이며, 또한 API를 통해 새로운 수익원을 창출하는 것도 기업들이 Open API를 도입하는 주요 동인 중 하나이다. 
API의 호출 수에 제한을 두고, 무료 제공량 이상은 돈을 받는다거나(단계적 유료화), 자사가 구축한 결제 시스템을 API 형태로 타사 서비스에 연계할 수 있도록 하여 수수료 수익을 창출하는 등이 있다</p>
<hr>
<h3 id="용어">용어</h3>
<ul>
<li>PAYLOAD : 페이로드(payload)는 전송되는 데이터를 의미한다.<ul>
<li>데이터를 전송할 때, 헤더와 메타 데이터, 여러 체크 비트 등과 같은 다양한 요소들을 함께 보내어, 데이터 전송의 효율과 안정성을 높이데 된다</li>
<li>이때, 보내고자 하는 데이터 자체를 의미하는 것이 바로 페이로드이다.
<img src="https://velog.velcdn.com/images/korea_no_1/post/ec4b09dd-6104-4b0b-9dfd-c84d12e423b1/image.png" alt=""></li>
</ul>
</li>
</ul>
<hr>
<h3 id="reference">Reference</h3>
<p><a href="https://enjoyinjoanne.tistory.com/56">API 이해하기(KAKAO API)</a>
<a href="https://khj93.tistory.com/entry/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-REST-API%EB%9E%80-REST-RESTful%EC%9D%B4%EB%9E%80">REST API</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[웹서비스설계및실습(Cookie Session JWT)]]></title>
            <link>https://velog.io/@korea_no_1/%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4%EC%84%A4%EA%B3%84%EB%B0%8F%EC%8B%A4%EC%8A%B5Cookie-Session-JWT</link>
            <guid>https://velog.io/@korea_no_1/%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4%EC%84%A4%EA%B3%84%EB%B0%8F%EC%8B%A4%EC%8A%B5Cookie-Session-JWT</guid>
            <pubDate>Fri, 18 Oct 2024 02:26:56 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/korea_no_1/post/701f2497-0582-4881-98d5-c3d100ee7fee/image.png" alt=""></p>
<blockquote>
<p>수업 내용 정리</p>
</blockquote>
<h3 id="cs-용어">CS 용어</h3>
<h4 id="jwtjson-web-token">JWT(JSON Web Token)</h4>
<ul>
<li>JSON 형식의 데이터를 저장하는 토큰</li>
<li>API 요청을 인증하는 수단으로 사용</li>
<li>쿠키, 세션의 단점을 보완<ul>
<li>쿠키 : 암호와 안됨, 사이즈 제한(4KB), 브라우저마다 형태 다름</li>
<li>세션 : 서버 자원을 사용</li>
<li>JWT : 토큰 변조가 불가능하고, 내용에 포함해서(암호화 상태로) 전송하므로 서버에서 DB조회를 하지 않을 수 있음(DB조회를 하지 않고 검증 가능)</li>
</ul>
</li>
</ul>
<ul>
<li><p>JWT를 활용한 로그인 사례
(Token : 데이터 베이스의 호출이 없다, 토큰을 가지고 유효한지 유효하지 않은지 알 수 있다)
<img src="https://velog.velcdn.com/images/korea_no_1/post/43671e71-177a-4e8e-bded-e2156ab1baa4/image.png" alt=""></p>
<ol start="3">
<li><p>Access Token(JWT) 발급 : node가 Access Token(접근 토큰)을 만든다
노드(node)는 서버에 존재한다. </p>
</li>
<li><p>Token과 함께 사용자에게 응답을 보낸다</p>
</li>
<li><p>사용자는 Token을 넣어서 함께 요청한다</p>
</li>
<li><p>회원 DB의 호출없이 스스로 검증이 가능하다</p>
</li>
</ol>
</li>
<li><p>JWT의 구성(Token의 구성 모습) </p>
<ul>
<li>header : 토큰 종류와 해시 알고리즘 정보가 들어있다</li>
<li>payload : 토큰의 내용물이 인코딩된 부분
(실제 데이터를 담고 있다, JSON 형태)</li>
<li>signature : 일련의 문자열로, 이를 통해 토큰이 변조되었는지 여부 확인<strong>(암호화 보다 인증에 가깝다)</strong><ul>
<li>JWT 비밀키로 만들어지고, <strong>비밀키(signature에서 관리)가 노출되면 토큰 위조 가능</strong></li>
<li>비밀키는 별도 개발환경 안에서 관리해야함 (공개된 곳에 올라가지 않도록 주의 한다)</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Token 자체에 중요한 정보를 넣으면 안된다</strong>
(token log를 통해서 data 내용을 알 수 있기 때문에)</p>
</li>
<li><p><strong>토큰 검증</strong></p>
<ul>
<li><p>프론트에서는 header에 넣어서 호출</p>
</li>
<li><p>header 와 비밀키를 넣어서 검증</p>
<ul>
<li>비밀키는 dotenv 를 통해 관리</li>
<li>process.env</li>
</ul>
</li>
<li><p>middleware 생성</p>
<ul>
<li>오류 발생시, 그에 대한 설명을 return</li>
<li>오류 없으면, 실제 사용자의 호출이 맞다고 가정(변조 없음)</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="refresh-token">Refresh Token</h4>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/ec0621a3-2d2f-4866-aeba-0c9a8c67ea0d/image.png" alt=""></p>
<ol start="2">
<li>Access Token과 Refresh Token (서로 다른 2개의 Token 제작)</li>
<li>Refresh Token을 DB에 저장</li>
<li>Access Token의 유효기간 만료</li>
<li>만료가 되었음을 확인</li>
<li>사용자에게 만료 signal 보내기</li>
<li>Access Token을 요청하면서, Refresh Token도 같이 보낸다</li>
<li>Refresh Token을 DB에서 확인하고, 새로운 Access Token만 발행해서 넘겨준다</li>
<li>로그인이 끊기지 않고 계속해서 사용</li>
</ol>
<hr>
<h3 id="cs-지식">CS 지식</h3>
<h4 id="쿠키의-이해">쿠키의 이해</h4>
<ul>
<li><p><strong>쿠키 옵션, Set-Cookie 시 다양한 옵션이 있음</strong></p>
<ul>
<li><p><strong>쿠키명 = 쿠키값</strong> : 기본적인 쿠키의 값이다. mycookie=test 와 같이 <strong>pair로 설정</strong>한다</p>
</li>
<li><p><strong>Expires = 날짜</strong> : 만료 기한이다. 이 기한이 지나면 쿠키가 제거된다. 기본값은 클라이언트가 종료될 때까지이다.</p>
</li>
<li><p><strong>Max-age = 초</strong> : Expires와 비슷하지만 날짜 대신 초를 입력할 수 있다. 해당 초가 지나면 쿠키가 제거되며 Expires보다 우선시한다.</p>
</li>
<li><p><strong>Domain = 도메인명</strong> : 쿠키가 전송될 도메인을 특정할 수 있다. 기본값은 현재 도메인이다</p>
</li>
<li><p><strong>Path = URL</strong> : 쿠키가 전송될 URL을 특정할 수 있다. 기본값은 &#39;/&#39; 이며 이 경우 모든 URL에서 쿠키를 전송할 수 있다</p>
</li>
<li><p><strong>Secure</strong> : HTTPS일 경우에만 쿠키가 전송된다</p>
</li>
<li><p><strong>HttpOnly</strong> : 설정시 자바스크립트에서 쿠키에 접근할 수 없다. 쿠키 조작을 방지하기 위해 설정하는 것이 좋다</p>
</li>
</ul>
</li>
</ul>
<h4 id="세션의-이해">세션의 이해</h4>
<ul>
<li><p><strong>쿠키의 정보는 노출되고 수정되는 위험이 있음</strong></p>
<ul>
<li>중요한 정보는 서버에서 관리하고 클라이언트에는 세션 키만 제공</li>
<li>서버에 세션 객체(session) 생성 후, uniqueInt(키)를 만들어 속성명으로 사용</li>
<li>속성 값에 정보 저장하고 uniqueInt를 클라이언트에 보냄</li>
</ul>
<ul>
<li><p><strong>세션의 동작 방식</strong></p>
<ul>
<li>클라이언트가 서버에 접속 시 <strong>세션 ID를 발급</strong> 받음</li>
<li>클라이언트는 <strong>세션 ID에 대해</strong> 쿠키를 사용해서 저장하고 가지고 있음</li>
<li>클라이언트는 서버에 요청할 때, 이 <strong>쿠키의 세션 ID를 같이 서버에 전달</strong>해서 요청</li>
<li>서버는 세션 ID를 전달 받아서 별다른 작업없이 <strong>세션 ID로 세션에 있는 클라이언트 정보를 가져와서 사용</strong></li>
<li>클라이언트 정보를 가지고 서버 요청을 처리하여 클라이언트에게 응답</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="쿠키와-세션의-비교">쿠키와 세션의 비교</h4>
<ul>
<li><p>쿠키는 서버의 자원을 전혀 사용하지 않으며, 세션은 서버의 자원을 사용</p>
</li>
<li><p>보안 면에서 세션이 더 우수</p>
<ul>
<li><p>쿠키도 만료시간이 있지만 <strong>파일로 저장</strong>되기 때문에 브라우저를 종료해도 게속해서 정보가 남아 있을 수 있지만, 세션은 브라우저가 종료되면 만료시간에 상관없이 삭제됨</p>
</li>
<li><p>쿠키는 클라이언트 로컬에 저장되기 때문에 변질되거나 request에서 스니핑 당할 우려가 있어서 보안에 취약하지만 세션은 쿠키를 이용해서 sessionId만 저장하고 그것으로 구분해서 서버에서 처리</p>
</li>
</ul>
</li>
<li><p>요청 속도는 쿠키가 세션보다 더 빠름</p>
<ul>
<li>세션은 서버의 처리가 필요하기 때문에</li>
</ul>
</li>
</ul>
<h4 id="암호화">암호화</h4>
<ul>
<li><p>단방향 암호화</p>
<ul>
<li><p>암호화는 가능하지만 복호화는 불가능</p>
<ul>
<li>암호화 : 평문을 암호로 만듦</li>
<li>복호화 : 암호를 평문으로 만듦</li>
</ul>
</li>
<li><p>복호화할 필요가 없는, 복호화해서 안되는 정보에 활용 : 사용자 비밀번호</p>
</li>
<li><p>주로 Hash 기법을 활용</p>
</li>
</ul>
</li>
<li><p>Hash 사용하기(sha512)</p>
<ul>
<li>createHash(알고리즘) : 사용할 해시 알고리즘을 넣어준다<ul>
<li>현재는 sha512 정도로 충분하지만, 이후에 sha512도 취약해지면 더 강화된 알고리즘으로 변경<ul>
<li>update(문자열) : 변환할 문자열을 넣어준다</li>
<li>digest(인코딩) : 인코딩할 알고리즘을 넣어준다</li>
<li>base64, hex, latin1 이 주로 사용되는데, 그 중 base64가 결과 문자열이 가장 짧아서 자주 활용된다</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code>const crypto = require(&quot;crypto&quot;)

console.log(
    &quot;bash64: &quot;,
    crypto.createHash(&quot;sha512&quot;).update(&quot;password1234&quot;).digest(&quot;base64&quot;)</code></pre><hr>
<h3 id="코드">코드</h3>
<ul>
<li>cookie2.js<pre><code>const http = require(&#39;http&#39;);
const fs = require(&#39;fs&#39;).promises;
const path = require(&#39;path&#39;);
</code></pre></li>
</ul>
<p>const parseCookies = (cookie = &#39;&#39;) =&gt;
  cookie
    .split(&#39;;&#39;)
    .map(v =&gt; v.split(&#39;=&#39;))
    .reduce((acc, [k, v]) =&gt; {
      acc[k.trim()] = decodeURIComponent(v);
      return acc;
    }, {});</p>
<p>http.createServer(async (req, res) =&gt; {
  const cookies = parseCookies(req.headers.cookie); // { mycookie: &#39;test&#39; }
  // 주소가 /login으로 시작하는 경우
  if (req.url.startsWith(&#39;/login&#39;)) {  // 로그인으로 들어왔다
    const url = new URL(req.url, &#39;<a href="http://localhost:8084&#39;">http://localhost:8084&#39;</a>);  // 8084 받아옴
    const name = url.searchParams.get(&#39;name&#39;);
    const expires = new Date();
    // 쿠키 유효 시간을 현재시간 + 5분으로 설정
    expires.setMinutes(expires.getMinutes() + 5);   // 해당 쿠키의 유효시간을 5분, expires에 가져왔다
    res.writeHead(302, {
      Location: &#39;/&#39;,
      &#39;Set-Cookie&#39;: <code>name=${encodeURIComponent(name)}; Expires=${expires.toGMTString()}; HttpOnly; Path=/</code>,   // Set-Cookie에 내가 넣고 싶은 정보를 모두 넣을 수 있다
    });
    res.end();
  // name이라는 쿠키가 있는 경우
  } else if (cookies.name) {
    res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
    res.end(<code>${cookies.name}님 안녕하세요</code>);
  } else {
    try {
      const data = await fs.readFile(path.join(__dirname, &#39;cookie2.html&#39;));
      res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/html; charset=utf-8&#39; });
      res.end(data);
    } catch (err) {
      res.writeHead(500, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
      res.end(err.message);
    }
  }
})
  .listen(8084, () =&gt; {
    console.log(&#39;8084번 포트에서 서버 대기 중입니다!&#39;);
  });</p>
<pre><code>
- session.js
</code></pre><p>const http = require(&#39;http&#39;);
const fs = require(&#39;fs&#39;).promises;
const path = require(&#39;path&#39;);</p>
<p>const parseCookies = (cookie = &#39;&#39;) =&gt;
  cookie
    .split(&#39;;&#39;)
    .map(v =&gt; v.split(&#39;=&#39;))
    .reduce((acc, [k, v]) =&gt; {
      acc[k.trim()] = decodeURIComponent(v);
      return acc;
    }, {});</p>
<p>const session = {};</p>
<p>http.createServer(async (req, res) =&gt; {
  const cookies = parseCookies(req.headers.cookie);
  if (req.url.startsWith(&#39;/login&#39;)) {
    const url = new URL(req.url, &#39;<a href="http://localhost:8085&#39;">http://localhost:8085&#39;</a>);
    const name = url.searchParams.get(&#39;name&#39;);
    const expires = new Date();
    expires.setMinutes(expires.getMinutes() + 5);
    const uniqueInt = Date.now();  // 현재 시간
    session[uniqueInt] = {  // 현재 시간을 key로 가지고 이 key 안에는 name과 expires가 있다
      name,
      expires,
    };
    res.writeHead(302, {
      Location: &#39;/&#39;,
      &#39;Set-Cookie&#39;: <code>session=${uniqueInt}; Expires=${expires.toGMTString()}; HttpOnly; Path=/</code>,   // key를 보내서 client가 cookie에 저장할 수 있게 해준다
    });
    res.end();
  // 세션쿠키가 존재하고, 만료 기간이 지나지 않았다면
  } else if (cookies.session &amp;&amp; session[cookies.session].expires &gt; new Date()) {
    res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
    res.end(<code>${session[cookies.session].name}님 안녕하세요</code>);
  } else {
    try {
      const data = await fs.readFile(path.join(__dirname, &#39;cookie2.html&#39;));
      res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/html; charset=utf-8&#39; });
      res.end(data);
    } catch (err) {
      res.writeHead(500, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
      res.end(err.message);
    }
  }
})
  .listen(8085, () =&gt; {
    console.log(&#39;8085번 포트에서 서버 대기 중입니다!&#39;);
  });</p>
<pre><code>
#### JWT 설치

- JWT관련 모듈 설치</code></pre><p>npm install jsonwebtoken dotenv</p>
<pre><code>
- 토큰 발급
   - .sign( {넣을 정보}, 비밀키, {만료시간} ) 
</code></pre><p>const jwt = require(&quot;jsonwebtoken&quot;);
const token = jwt.sign({id : &quot;kdkd&quot;}, &quot;shhhh&quot;, {  // id : kdkd, 비밀키(탈취되면 안됨) : shhhh
    expiresIn : &quot;1m&quot;  // 1분만 유효
    issuer : &quot;yubin&quot;,
});
console.log(token);
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[서버 용어 및 개념 정리]]></title>
            <link>https://velog.io/@korea_no_1/%EC%84%9C%EB%B2%84-%EC%9A%A9%EC%96%B4-%EB%B0%8F-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@korea_no_1/%EC%84%9C%EB%B2%84-%EC%9A%A9%EC%96%B4-%EB%B0%8F-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Thu, 17 Oct 2024 01:55:38 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/korea_no_1/post/dd2f32a5-060e-44d2-bfb8-22bd80ffb7a3/image.png" alt=""></p>
<p><a href="https://ilovestorage.tistory.com/3">https://ilovestorage.tistory.com/3</a></p>
<h3 id="서버-가상화virture-machine">서버 가상화(Virture Machine)</h3>
<p>: 가상화시스템이 도입되기 전에는 <strong>1개의 하드웨어 서버에 1개의 운영체제를 설치한다</strong> 일반적으로 베어 메탈 서버들은 운영 중에 리소스의 15%만 사용한다고 한다. <strong>베어메탈 서버에서 서비스가 돌아가면, 가상화시스템에 비해 대부분의 리소스를 낭비하게 된다</strong></p>
<p>이에 대한 해결책으로 서버 가상화가 존재한다
<strong>가상화 소프트웨어를 사용하면 여러 대의 물리적 하드웨어 서버를 여러대의 가상 서버로 생성할 수 있다</strong>
하드웨어 서버를 추가적으로 구매할 필요 없이, 1대의 하드웨어에서 리소스를 최대한 활용할 수 있다. 
<img src="https://velog.velcdn.com/images/korea_no_1/post/0b75998f-41bd-49e4-96f1-accde8c530d9/image.png" alt=""></p>
<ul>
<li>베어 메탈 서버 : 가상화 기술을 사용하지 않고 물리적으로 분리된 CPU, 메모리 등의 컴퓨팅 자원을 단독으로 할당받아 사용할 수 있는 고성능 클라우드 컴퓨팅 서빗 이다(다른 클라우드 사용자의 영향을 받지 않아 성능에 민감한 서비스를 안정적으로 운영할 수 있다)</li>
</ul>
<h4 id="서버-가상화-작동방식">서버 가상화 작동방식</h4>
<p>: 가상화 시스템을 도입하려면, 먼저 가상화 소프트웨어를 정해야 한다. 가상화 시스템을 위해 도입되는, __가상화 소프트웨어를 일명 하이퍼바이저(hypervisor)라고 한다. </p>
<h3 id="cs-용어">CS 용어</h3>
<h4 id="인프라">인프라</h4>
<p>: 인프라를 왜 개발자도 알아야 하나?
과거는 서버 구축하고, 서버라는 곳에 소프트웨어가 있었다 서버기능을 하는 : 배포 작업</p>
<h4 id="iaasinfra-as-a-service">IaaS(Infra as a Service)</h4>
<p>: 인프라를 서비스처럼 제공해준다</p>
<h4 id="paasplatform-as-a-service">PaaS(Platform as a Service)</h4>
<h4 id="saassoftware-as-a-service">SaaS(Software as a Service)</h4>
<p>: 소프트웨어를 서비스처럼 제공해준다
굳이 데스크탑이나 서버에 설치하지 않고 쓸 수 있다
ex. office365</p>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/a3cae140-4f10-4ca3-b6a7-dd6b947c0005/image.png" alt="">
<img src="https://velog.velcdn.com/images/korea_no_1/post/3c5b201f-9f3a-4d53-8410-a0fc57c6c02c/image.png" alt=""></p>
<h4 id="faasfunction-as-a-service">FaaS(Function as a Service)</h4>
<p>-&gt; serverless 라고 하지만, 실제로는 서버가 있다
서버까지 관리를 하지 않아도 되는것이 맞다
개발은 하며, 해당 소스코드들이 기능을 한다.
그래서, 서버를 신경쓰지 않고 한다</p>
<p>사용한만큼 돈을 낸다</p>
<h4 id="클라우드">클라우드</h4>
<p>: 3가지 종류) 온-프레미스, 프라이빗 클라우드, 퍼블릭 클라우드
모두 이용하는 것) 하이브리드 클라우드</p>
<h4 id="idc">IDC</h4>
<hr>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/1b4768e0-cff4-4065-99c1-e70390d429ce/image.png" alt=""></p>
<p>플랫폼 : 프로그램이 실행되는 기계들 
기술분야 : 맡은 역할에 따라서 나누어졌다(특정 기능을 담당)
도메인 : 내가 속해있는 분야인 산업 분야가 중요해지고 있다</p>
<h4 id="dadomain-adaptation">DA(Domain Adaptation)</h4>
<p>출처 : <a href="https://lhw0772.medium.com/study-da-domain-adaptation-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0-%EA%B8%B0%EB%B3%B8%ED%8E%B8-4af4ab63f871">DA 알아보기</a>
<a href="https://velog.io/@ingsol/Domain-Adaptation-%EC%9E%90%EB%A3%8C">DA 자료</a></p>
<ul>
<li><p>한 줄 요약 : Domain 차이(Train dataset과 Test dataset의 분포 차이) 완화 하기</p>
</li>
<li><p>문제 정의 : 
Machine Learning, Deep Learning에서 항상 문제가 되는 것은 무엇일까. 단순하게 말하면 학습 데이터에서는 잘 동작하는데 테스트 데이터에서는 잘 동작하지 않는 문제가 가장 많을 것이다. 해당 원인은 학습 데이터가 다양하기 때문이기도 하고 model의 <strong>over-fitting(과적합)</strong> 때문일 수도 있기 때문이다. 또 하나 다른 이유는 학습 데이터와 테스트 데이터의 <strong>Domain-shift</strong>가 일어났기 때문이다</p>
</li>
</ul>
<blockquote>
<h4 id="domain-shift란">Domain Shift란?</h4>
</blockquote>
<p><strong>학습 데이터(Source)와 테스트 데이터(Target)의 Distribution(분포)의 차이</strong>를 의미한다. 예를 들면 같은 컵을 카메라로 찍었을 때와 캐리커쳐처럼 손으로 그렸을 때의 차이이다. 물론 Shift가 작은 경우엔 고화질의 DSLR과 Webcam의 이미지도 Domain shift로 볼 수 있다. 해당 Domain shift가 심할수록 test data의 정확도는 떨어지게 된다. <img src="https://velog.velcdn.com/images/korea_no_1/post/6289c8a8-cee4-4167-a516-038578a7e1d6/image.png" alt=""></p>
<p>다른 Domain Adaptaion의 예로는 Synthetic data를 이용해서 Real data를 대비하여 학습하는 경우이다.</p>
<blockquote>
<h4 id="synthetic-data란">Synthetic data란?</h4>
</blockquote>
<p>  Synthetic data(재현/합성 데이터)는 원본 데이터에서 생성되는 <strong>인공 데이터</strong>이자 원본 데이터의 특성과 구조를 재현하도록 학습된 모델이다. 즉 동일한 통계 분석을 수행할 때 합성 데이터와 원본 데이터는 매우 유사한 결과를 제공해야 한다.</p>
<p>요즘에는 그래픽이 좋아지면서 Synthetic data를 학습함으로써 실제 영상에 적용했을 때도 성능 향상이 이루어지는 경우가 많다. 하지만 이 경우에도 같은 양의 Real data를 사용했을 때의 성능보다는 떨어질 수 있다. 
<img src="https://velog.velcdn.com/images/korea_no_1/post/9ab1d9c9-fab1-4da3-8de5-e8296f934810/image.png" alt=""></p>
<blockquote>
<p>Traditional Domain Adaptation 방식</p>
</blockquote>
<ul>
<li>Metric Learning</li>
<li>Subspace Representation</li>
<li>Matching Distribution</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[웹서비스설계및실습 (과제)]]></title>
            <link>https://velog.io/@korea_no_1/%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4%EC%84%A4%EA%B3%84%EB%B0%8F%EC%8B%A4%EC%8A%B5-%EA%B3%BC%EC%A0%9C</link>
            <guid>https://velog.io/@korea_no_1/%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4%EC%84%A4%EA%B3%84%EB%B0%8F%EC%8B%A4%EC%8A%B5-%EA%B3%BC%EC%A0%9C</guid>
            <pubDate>Sun, 13 Oct 2024 17:11:05 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/korea_no_1/post/e943a208-1785-442c-ad2c-13bec414a837/image.png" alt=""></p>
<h2 id="1차-과제">1차 과제</h2>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/545b0369-7801-4764-b341-3580a4c03513/image.png" alt=""></p>
<p>다음과 같은 조건을 만족하여야 한다.</p>
<ul>
<li><strong>login.html</strong></li>
</ul>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;ko&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;title&gt;로그인&lt;/title&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;/styles.css&quot;&gt; 
&lt;/head&gt;
&lt;body&gt;
    &lt;div class=&quot;login-container&quot;&gt;
        &lt;h1&gt;로그인&lt;/h1&gt;
        &lt;form action=&quot;/login&quot; method=&quot;POST&quot;&gt;
            &lt;div class=&quot;form-group&quot;&gt;
                &lt;label for=&quot;loginId&quot;&gt;ID:&lt;/label&gt;
                &lt;input type=&quot;text&quot; id=&quot;loginId&quot; name=&quot;id&quot; oninput=&quot;enableLoginButton()&quot; required&gt;
            &lt;/div&gt;
            &lt;div class=&quot;form-group&quot;&gt;
                &lt;label for=&quot;loginPassword&quot;&gt;비밀번호:&lt;/label&gt;
                &lt;input type=&quot;password&quot; id=&quot;loginPassword&quot; name=&quot;password&quot; oninput=&quot;enableLoginButton()&quot; required&gt;
            &lt;/div&gt;
            &lt;div class=&quot;form-group&quot;&gt;
                &lt;button type=&quot;submit&quot; id=&quot;loginBtn&quot; class=&quot;inactive&quot; disabled&gt;로그인&lt;/button&gt;
            &lt;/div&gt;
            &lt;div class=&quot;form-group&quot;&gt;
                &lt;a href=&quot;/register&quot;&gt;회원가입&lt;/a&gt;
            &lt;/div&gt;
        &lt;/form&gt;
    &lt;/div&gt;
    &lt;script src=&quot;/scripts.js&quot;&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre><ul>
<li><p><strong>로그인 폼</strong>
<code>&lt;form action=&quot;/login&quot; method=&quot;POST&quot;&gt;</code>
: 로그인 폼을 정의하며, 사용자가 입력한 ID와 비밀번호가 /login 경로로 POST 방식으로 전송된다</p>
</li>
<li><p><strong>ID 입력 필드</strong>
<code>&lt;input type=&quot;text&quot; id=&quot;loginId&quot; name=&quot;id&quot; oninput=&quot;enableLoginButton()&quot; required&gt;</code>
: ID를 입력받는 텍스트 필드이다</p>
<ul>
<li><code>oninput=&quot;enableLoginButton()&quot;</code> 
: 사용자가 입력할 때마다 enableLoginButton() 함수를 호출한다. 이는 ID가 입력될 때 로그인 버튼을 활성활하는 기능을 수행</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li><strong>register.html</strong></li>
</ul>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;ko&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;title&gt;회원가입&lt;/title&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;/styles.css&quot;&gt;
    &lt;script&gt;
        let isDuplicateChecked = false;  // 중복 체크 여부 추적

        // 페이지 로드 시 기본적으로 회원가입 버튼 비활성화
        document.addEventListener(&#39;DOMContentLoaded&#39;, function() {
            document.getElementById(&#39;submitBtn&#39;).disabled = true;  // 기본적으로 비활성화
        });

        // ID 입력 시 중복 체크 버튼 활성화
        function handleIDInput() {
            const idInput = document.getElementById(&#39;id&#39;).value;
            const duplicateCheckBtn = document.getElementById(&#39;duplicateCheckBtn&#39;);
            duplicateCheckBtn.disabled = idInput.length &lt; 1; // 한 글자 이상일 때만 활성화

            // ID가 변경되면 중복 체크가 필요하므로 플래그 초기화
            isDuplicateChecked = false;
            enableSubmitButton();  // 버튼 활성화 여부 확인
        }

        // ID 중복 체크
        function checkDuplicateID() {
            const id = document.getElementById(&#39;id&#39;).value;
            const checkResult = document.getElementById(&#39;checkResult&#39;);
            const submitBtn = document.getElementById(&#39;submitBtn&#39;);

            if (!id) {
                checkResult.innerHTML = &#39;ID를 입력해주세요&#39;;
                return;
            }

            // 서버로 중복 체크 요청
            fetch(`/check-id?id=${id}`)
                .then(response =&gt; response.json())
                .then(data =&gt; {
                    if (data.exists) {
                        checkResult.innerHTML = &#39;이미 사용 중인 ID입니다.&#39;;
                        isDuplicateChecked = false; // 중복된 경우
                        submitBtn.disabled = true;  // ID가 중복되면 회원가입 버튼 비활성화
                    } else {
                        checkResult.innerHTML = &#39;사용 가능한 ID입니다.&#39;;
                        isDuplicateChecked = true;  // 사용 가능한 경우
                    }
                    enableSubmitButton();  // 중복 체크 후 회원가입 버튼 활성화 여부 확인
                });
        }

        // 비밀번호 일치 여부 확인
        function checkPasswordMatch() {
            const pw1 = document.getElementById(&#39;password1&#39;).value;
            const pw2 = document.getElementById(&#39;password2&#39;).value;
            const pwMatchResult = document.getElementById(&#39;pwMatchResult&#39;);

            if (pw1 &amp;&amp; pw2) {
                if (pw1 === pw2) {
                    pwMatchResult.innerHTML = &#39;비밀번호가 일치합니다.&#39;;
                } else {
                    pwMatchResult.innerHTML = &#39;비밀번호가 일치하지 않습니다.&#39;;
                }
            } else {
                pwMatchResult.innerHTML = &#39;&#39;; // 둘 다 입력하지 않은 경우 메시지 지움
            }

            enableSubmitButton();  // 비밀번호 확인 후 회원가입 버튼 활성화 여부 확인
        }

        // 회원가입 버튼 활성화
        function enableSubmitButton() {
            const pw1 = document.getElementById(&#39;password1&#39;).value;
            const pw2 = document.getElementById(&#39;password2&#39;).value;
            const submitBtn = document.getElementById(&#39;submitBtn&#39;);

            // ID 중복 체크가 완료되고, 비밀번호가 일치하며, 비밀번호가 입력되었을 때만 회원가입 버튼 활성화
            if (isDuplicateChecked &amp;&amp; pw1 === pw2 &amp;&amp; pw1.length &gt; 0 &amp;&amp; pw2.length &gt; 0) {
                submitBtn.disabled = false;  // 활성화
            } else {
                submitBtn.disabled = true;  // 비활성화
            }
        }

        // onblur로 실시간 비밀번호 확인
        function handlePasswordBlur() {
            checkPasswordMatch();
        }
    &lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div class=&quot;register-container&quot;&gt;
        &lt;h1&gt;회원가입&lt;/h1&gt;
        &lt;form action=&quot;/register&quot; method=&quot;POST&quot;&gt;
            &lt;div class=&quot;form-group&quot;&gt;
                &lt;label for=&quot;id&quot;&gt;ID:&lt;/label&gt;
                &lt;input type=&quot;text&quot; id=&quot;id&quot; name=&quot;id&quot; oninput=&quot;handleIDInput()&quot;&gt;
                &lt;button type=&quot;button&quot; id=&quot;duplicateCheckBtn&quot; disabled onclick=&quot;checkDuplicateID()&quot;&gt;중복 ID 체크&lt;/button&gt;
                &lt;span id=&quot;checkResult&quot; style=&quot;color: red;&quot;&gt;&lt;/span&gt;
            &lt;/div&gt;
            &lt;div class=&quot;form-group&quot;&gt;
                &lt;label for=&quot;password1&quot;&gt;비밀번호:&lt;/label&gt;
                &lt;input type=&quot;password&quot; id=&quot;password1&quot; name=&quot;password1&quot; oninput=&quot;checkPasswordMatch()&quot; onblur=&quot;handlePasswordBlur()&quot;&gt;
            &lt;/div&gt;
            &lt;div class=&quot;form-group&quot;&gt;
                &lt;label for=&quot;password2&quot;&gt;비밀번호 확인:&lt;/label&gt;
                &lt;input type=&quot;password&quot; id=&quot;password2&quot; name=&quot;password2&quot; oninput=&quot;checkPasswordMatch()&quot; onblur=&quot;handlePasswordBlur()&quot;&gt;
                &lt;span id=&quot;pwMatchResult&quot; style=&quot;color: red;&quot;&gt;&lt;/span&gt;
            &lt;/div&gt;
            &lt;div class=&quot;form-group&quot;&gt;
                &lt;button type=&quot;submit&quot; id=&quot;submitBtn&quot; disabled&gt;회원가입&lt;/button&gt;
            &lt;/div&gt;
        &lt;/form&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre><hr>
<ul>
<li><strong>scripts.js</strong></li>
</ul>
<pre><code>let isDuplicateChecked = false;  // 중복 체크 여부 추적(기본값 : false)

// 페이지 로드 시 기본적으로 회원가입 버튼 비활성화
document.addEventListener(&#39;DOMContentLoaded&#39;, function() {
    document.getElementById(&#39;submitBtn&#39;).disabled = true;  // 기본적으로 비활성화
});

// ID 입력 시 중복 체크 버튼 활성화
function handleIdInput() {
    const idInput = document.getElementById(&#39;id&#39;).value;
    const checkDuplicateBtn = document.getElementById(&#39;checkDuplicateBtn&#39;);

    // ID 입력이 한 글자라도 있으면 중복 체크 버튼 활성화
    checkDuplicateBtn.disabled = idInput.length === 0;

    // ID가 변경되면 중복 체크가 필요하므로 플래그 초기화
    isDuplicateChecked = false;  
    enableSubmitButton();  // 회원가입 버튼 활성화 여부 확인
}

// ID 중복 체크
function checkDuplicateID() {
    const id = document.getElementById(&#39;id&#39;).value;
    const checkResult = document.getElementById(&#39;checkResult&#39;);

    if (!id) {
        checkResult.innerHTML = &#39;ID를 입력해주세요&#39;;
        isDuplicateChecked = false;  // 입력이 없으면 중복 체크를 하지 않는다
        enableSubmitButton();  // 버튼 활성화 여부 확인하기
        return;
    }

    // 서버로 중복 체크 요청
    fetch(`/check-id?id=${id}`)
        .then(response =&gt; response.json())
        .then(data =&gt; {
            if (data.exists) {
                checkResult.innerHTML = &#39;이미 사용 중인 ID입니다.&#39;;
                isDuplicateChecked = false;  // 중복된 경우
            } else {
                checkResult.innerHTML = &#39;사용 가능한 ID입니다.&#39;;
                isDuplicateChecked = true;  // 사용 가능한 경우
            }
            enableSubmitButton();  // 중복 체크 후 회원가입 버튼 활성화 여부 확인
        });
}

// 비밀번호 일치 여부 확인
function checkPasswordMatch() {
    const pw1 = document.getElementById(&#39;password1&#39;).value;
    const pw2 = document.getElementById(&#39;password2&#39;).value;
    const pwMatchResult = document.getElementById(&#39;pwMatchResult&#39;);

    if (pw1 &amp;&amp; pw2) {
        if (pw1 === pw2) {
            pwMatchResult.innerHTML = &#39;비밀번호가 일치합니다.&#39;;
        } else {
            pwMatchResult.innerHTML = &#39;비밀번호가 일치하지 않습니다.&#39;;
        }
    } else {
        pwMatchResult.innerHTML = &#39;&#39;;  // 비밀번호가 입력되지 않았을 경우 초기화
    }

    enableSubmitButton();  // 비밀번호 확인 후 회원가입 버튼 활성화 여부 확인
}

// 회원가입 버튼 활성화
function enableSubmitButton() {
    const pw1 = document.getElementById(&#39;password1&#39;).value;
    const pw2 = document.getElementById(&#39;password2&#39;).value;
    const submitBtn = document.getElementById(&#39;submitBtn&#39;);

    // ID 중복 체크가 완료되고, 비밀번호가 일치하며, 비밀번호가 입력되었을 때만 회원가입 버튼 활성화
    if (isDuplicateChecked &amp;&amp; pw1 === pw2 &amp;&amp; pw1.length &gt; 0 &amp;&amp; pw2.length &gt; 0) {
        submitBtn.disabled = false;  // 활성화
        submitBtn.classList.add(&#39;active&#39;);  // &#39;active&#39; 클래스 추가
    } else {
        submitBtn.disabled = true;  // 비활성화
        submitBtn.classList.remove(&#39;active&#39;);  // &#39;active&#39; 클래스 제거
    }
}

// 로그인 버튼 활성화
function enableLoginButton() {
    const idInput = document.getElementById(&#39;loginId&#39;).value;
    const passwordInput = document.getElementById(&#39;loginPassword&#39;).value;
    const loginBtn = document.getElementById(&#39;loginBtn&#39;);

    // ID와 비밀번호가 모두 입력되었을 때만 로그인 버튼 활성화(한 개라도 입력되면 활성화)
    if (idInput.length &gt; 0 &amp;&amp; passwordInput.length &gt; 0) {
        loginBtn.disabled = false;
        loginBtn.classList.remove(&#39;inactive&#39;);
        loginBtn.classList.add(&#39;active&#39;);
    } else {
        loginBtn.disabled = true;
        loginBtn.classList.remove(&#39;active&#39;);
        loginBtn.classList.add(&#39;inactive&#39;);
    }
}
</code></pre><hr>
<ul>
<li><strong>style.css</strong><pre><code>/* 전체 화면 설정 */
body {
  font-family: Arial, sans-serif;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  margin: 0;
  background-color: #f5f5f5;
}

</code></pre></li>
</ul>
<p>/* 로그인 컨테이너 스타일 */
.login-container {
    background-color: white;
    padding: 2rem;
    border-radius: 10px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    text-align: center;
    width: 300px;
}</p>
<p>/* 회원가입 컨테이너 스타일 */
.register-container {
    background-color: #ffffff;
    padding: 40px;
    border-radius: 10px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    width: 400px;
    text-align: center;
}</p>
<p>h1 {
    margin-bottom: 30px;
    font-size: 24px;
    color: #333;
}</p>
<p>.form-group {
    margin-bottom: 20px;
    text-align: left;
}</p>
<p>label {
    display: block;
    margin-bottom: 5px;
    font-weight: bold;
    color: #333;
}</p>
<p>input[type=&quot;text&quot;], input[type=&quot;password&quot;] {
    width: 100%;
    padding: 10px;
    margin-bottom: 10px;
    border: 1px solid #ccc;
    border-radius: 5px;
}</p>
<p>input[type=&quot;text&quot;]:focus,
input[type=&quot;password&quot;]:focus {
    outline: none;
    border-color: #007bff;
}</p>
<p>button {
    width: 100%;
    padding: 10px;
    background-color: #007bff;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-size: 16px;
}</p>
<p>/* 비활성화된 상태 */
button.inactive {
    background-color: #ccc;
    cursor: not-allowed;
}</p>
<p>/* 활성화된 상태 */
button.active {
    background-color: #007bff;
    cursor: pointer;
}</p>
<p>/* 활성화된 상태에서 마우스를 올렸을 때 */
button.active:hover {
    background-color: #0056b3;
}</p>
<p>button:not(.inactive):hover {
    background-color: #0056b3;
}</p>
<p>button:disabled {
    background-color: #ccc;
    cursor: not-allowed;
}</p>
<p>/* 활성화된 버튼에 마우스를 올릴 때 */
button:hover:enabled {
    background-color: #0056b3;
}</p>
<p>a {
    display: block;
    margin-top: 1rem;
    color: #007bff;
    text-decoration: none;
}</p>
<p>a:hover {
    text-decoration: underline;
}</p>
<pre><code>
---
- __server.js__
</code></pre><p>const express = require(&#39;express&#39;);
const session = require(&#39;express-session&#39;);
const bodyParser = require(&#39;body-parser&#39;);
const path = require(&#39;path&#39;);  // 경로 설정을 위해 path 모듈</p>
<p>const app = express();
app.use(bodyParser.urlencoded({ extended: true }));</p>
<p>// 정적 파일 경로 설정
app.use(express.static(path.join(__dirname, &#39;views&#39;)));</p>
<p>app.use(session({
    secret: &#39;your_secret_key&#39;,
    resave: false,
    saveUninitialized: true
}));</p>
<p>let users = [];</p>
<p>// 기본 경로로 접속 시 /login으로 리다이렉트
app.get(&#39;/&#39;, (req, res) =&gt; {
    res.redirect(&#39;/login&#39;);
});</p>
<p>// 로그인 페이지
app.get(&#39;/login&#39;, (req, res) =&gt; {
    res.sendFile(path.join(__dirname, &#39;views&#39;, &#39;login.html&#39;));<br>});</p>
<p>// 회원가입 페이지
app.get(&#39;/register&#39;, (req, res) =&gt; {
    res.sendFile(path.join(__dirname, &#39;views&#39;, &#39;register.html&#39;));<br>});</p>
<p>app.post(&#39;/login&#39;, (req, res) =&gt; {
    const { id, password } = req.body;
    const user = users.find(u =&gt; u.id === id &amp;&amp; u.password === password);</p>
<pre><code>if (user) {
    req.session.user = user;
    res.redirect(&#39;/home&#39;);
} else {
    res.send(&#39;&lt;script&gt;alert(&quot;ID 또는 PW가 잘못되었습니다.&quot;); window.location=&quot;/login&quot;;&lt;/script&gt;&#39;);
}</code></pre><p>});</p>
<p>app.post(&#39;/register&#39;, (req, res) =&gt; {
    const { id, password1, password2 } = req.body;</p>
<pre><code>if (users.some(u =&gt; u.id === id)) {
    return res.send(&#39;&lt;script&gt;alert(&quot;중복된 ID입니다.&quot;); window.location=&quot;/register&quot;;&lt;/script&gt;&#39;);
}

if (password1 !== password2) {
    return res.send(&#39;&lt;script&gt;alert(&quot;비밀번호가 일치하지 않습니다.&quot;); window.location=&quot;/register&quot;;&lt;/script&gt;&#39;);
}

users.push({ id, password: password1, name: &#39;박규동 교수&#39; });
res.redirect(&#39;/login&#39;);</code></pre><p>});</p>
<p>// 홈 페이지
app.get(&#39;/home&#39;, (req, res) =&gt; {
    if (req.session.user) {
        res.send(<code>&lt;h1&gt;환영합니다, ${req.session.user.name}님! 오실줄 알 고 있었습니다&lt;/h1&gt;
            &lt;p&gt;저는 정보융합학부 20학번 정유빈 입니다&lt;/p&gt;</code>);
    } else {
        res.redirect(&#39;/login&#39;);
    }
});</p>
<p>// ID 중복 체크
app.get(&#39;/check-id&#39;, (req, res) =&gt; {
    const id = req.query.id;
    const exists = users.some(u =&gt; u.id === id);
    res.json({ exists });
});</p>
<p>app.listen(3000, () =&gt; {
    console.log(&#39;서버가 <a href="http://localhost:3000">http://localhost:3000</a> 에서 실행 중입니다.&#39;);
});</p>
<pre><code>### __최종본__

- __초기화면__

![](https://velog.velcdn.com/images/korea_no_1/post/6d218e64-43a2-4895-9343-78be7936deb9/image.png)


- __회원가입 화면__

![](https://velog.velcdn.com/images/korea_no_1/post/e526b48f-ffe6-4d0b-90ec-cfefb2529378/image.png)

__실시간으로 비밀번호 확인(onblur 사용)__
![](https://velog.velcdn.com/images/korea_no_1/post/c9d15540-f079-4d32-887d-08eb25d997a6/image.png)


 __중복ID 체크를 하지 않으면 회원가입이 되지 않음__
![](https://velog.velcdn.com/images/korea_no_1/post/c236b8cb-7b59-46bb-9e9b-2d1b4364b5b1/image.png)

__중복 ID 체크 이후 모습__
![](https://velog.velcdn.com/images/korea_no_1/post/d8ccfe32-1cbf-45eb-9be8-56c30211b7c4/image.png)

- __로그인 성공 후 home으로 이동(아이디와 비번에 한 글자만 입력해도 로그인 버튼 활성화)__

![](https://velog.velcdn.com/images/korea_no_1/post/600aa74a-384e-404e-9071-5ebae5506759/image.png)

- __로그인 실패시 다음과 같은 화면 출력후 다시 login 페이지로 리다이렉션__

![](https://velog.velcdn.com/images/korea_no_1/post/2e86e787-8269-4d11-8dff-aa84351cd2db/image.png)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[웹서비스설계및실습(Express)]]></title>
            <link>https://velog.io/@korea_no_1/%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4%EC%84%A4%EA%B3%84%EB%B0%8F%EC%8B%A4%EC%8A%B5</link>
            <guid>https://velog.io/@korea_no_1/%EC%9B%B9%EC%84%9C%EB%B9%84%EC%8A%A4%EC%84%A4%EA%B3%84%EB%B0%8F%EC%8B%A4%EC%8A%B5</guid>
            <pubDate>Wed, 09 Oct 2024 00:40:38 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>수업 내용에 대한 정리</strong></p>
</blockquote>
<h3 id="cs-용어">CS 용어</h3>
<ul>
<li><p><strong>Paradigm Shift(패러다임 변화)</strong>
: 사회.문화에 대한 인식들이 천천히 변해 가면서 바뀌는 것이다
( 하나의 기술이 나온다고 바로 바뀌는 것이 아니다 ) </p>
</li>
<li><p><strong>프로세스</strong> : 운영체제 로부터 자원을 할당 받은 작업의 단위
( 메모리에 할당이 된다 )</p>
</li>
<li><p><strong>스레드</strong> : 프로세스가 할당 받은 자원을 이용하는 실행 흐름의 단위</p>
</li>
</ul>
<p><strong>스레드를 만드는 이유 : __ 하나의 프로세스 안에서 __여러가지 흐름</strong>을 가질 수 있게 하기 위해서 </p>
<p>웹 서버는 <strong>thread</strong> 이다. </p>
<p>*<em>프로그램 -&gt; 프로세스 -&gt; 스레드 *</em></p>
<ul>
<li><strong>Deadlock</strong>
: 운영체제 또는 소프트웨어의 잘못된 자원 관리로 인하여 <strong>둘 이상의 프로세스</strong> 또는 <strong>스레드(thread)</strong>들이 아무것도 진행하지 않는 상태로 영원히 대기하는 상황이다. 한국어로는 <strong>교착 상태</strong>라고 한다.</li>
</ul>
<p>한정된 자원을 여러 프로세스에서 동시에 사용하는 환경에서 서로 상대방이 사용 중인 자원을 쓰기 위해 대기하는 상황. 즉, A가 B를 기다리고 B가 A를 기다릴 때  발생한다. </p>
<p>&lt;-&gt; 병목 현상은 여러 구성 요소가 동시에 실행될 때, 가장 느린 쪽의 속도에 맞추기 위해 전체 시스템이 느려지는 상황이고, 교착 상태는 한정된 자원을 둘 이상의 주체가 서로 동시에 사용하려고 기다리기 때문에 발생한다. </p>
<ul>
<li><p><strong>HTTP(Hyper Text Transfer Protocopl)</strong>
: Web3 에서 정보를 주고받을 수 있는 <strong>프로토콜</strong> 이다. 
Hyper Text : 하이퍼링크를 가진 문서
Protocol : 통신을 위해 미리 정의된 <strong>규약</strong>을 의미 </p>
</li>
<li><p><strong>HTTPS</strong> : HTTP 요청과 응답 과정을 암호화해 HTTP의 보안을 한 층 강화한 프로토콜 </p>
</li>
<li><p><strong>노드</strong> : 자바스크립트 런타임 이다
자바스크립트 런타임은 인터프리터 방식이다 인터프리터 방식은 한 줄씩 읽고 실행하며, C언어의 경우 컴파일 방식이다</p>
</li>
<li><p><strong>동기(Synchronous), 비동기(Asynchronous)</strong>
<img src="https://velog.velcdn.com/images/korea_no_1/post/5535d019-9788-42a6-bc6e-589ea320db44/image.png" alt=""></p>
</li>
</ul>
<p>Synchronous(동기) : 요청을 보낸 후 해당 요청의 응답을 받아야 다음 동작을 실행 즉, <strong>직렬적</strong>으로 작동하는 방식</p>
<p>Asynchronous(비동기) : 요청을 보낸 후 응답과 관계없이 다음 동작을 실행할 수 있는 방식 즉, <strong>병렬적</strong>으로 작동하는 방식</p>
<ul>
<li><strong>API(Application Programming Interface)</strong></li>
</ul>
<p>다른 애플리케이션에서 현재 프로그램의 기능을 사용할 수 있게 함
웹API : 다른 웹 서비스의 기능을 사용하거나 자원을 가져올 수 있게 함</p>
<p>CRUD(Create, Read, Update, Delete)</p>
<ul>
<li><strong>HTTP 요청 메서드</strong></li>
</ul>
<p>GET : 서버 자원을 <strong>가져오려고</strong> 할 때 사용
POST : 서버에 자원을 <strong>새로 등록하고자</strong> 할 때 사용(또는 뭘 써야할 지 애매할 때)
PUT : 서버의 자원을 요청에 들어있는 자원으로 <strong>치환하고자</strong> 할 때 사용
PATCH : 서버 자원의 <strong>일부만 수정하고자 할 때</strong> 사용
DELETE : 서버의 자원을 <strong>삭제하고자 할 때</strong> 사용</p>
<hr>
<h3 id="cs-지식">CS 지식</h3>
<h4 id="현재-시대는-web20-에서-web30-으로-넘어가는-시대이다">현재 시대는 Web2.0 에서 Web3.0 으로 넘어가는 시대이다</h4>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/074a16ad-85ef-4fb2-82ba-1cd8b233b449/image.jpg" alt=""></p>
<h4 id="힙-vs-스택-속도-비교">힙 vs 스택 속도 비교</h4>
<p>: 힙이 접근속도 더 느리다
( 이유 : 스택처럼 차곡차곡 쌓는게 아니라 랜덤한 주소에 쌓기 때문에 -&gt; 메모리 단편화(파편화) ) </p>
<h4 id="stack-overflow힙과-스택-사이가-over될-때">Stack Overflow(힙과 스택 사이가 over될 때)</h4>
<p>: 프로세스와 프로세스 사이에 독립성을 유지하기 위해서
ex. 서로가 데이터의 영역을 침범해서 서버가 뻗는것(죽는것)을 예방하기 위해서</p>
<h4 id="node의-특성">Node의 특성</h4>
<ul>
<li><p>이벤트 기반 : 이벤트가 발생할 때 미리 지정해둔 작업을 수행하는 방식</p>
<ul>
<li>콜백 함수 : 이벤트가 발생했을 때 실행될 함수</li>
</ul>
</li>
<li><p>Non-Blocking I/O</p>
<ul>
<li>논 블로킹 : 오래 걸리는 함수를 백그라운드로 보내서 다음 코드가 먼저 실행되게 하고, 나중에 오래 걸리는 함수를 실행<ul>
<li>논 블로킹 방식 하에서 일부 코드는 백그라운드에서 병렬로 실행</li>
<li>일부 코드 : I/O 작업(파일 시스템 접근, 네트워크 요청), 압축, 암호화 등</li>
<li>I/O 작업을 제외한 나머지 코드는 블로킹 방식으로 실행
(블로킹 방식 : 하나가 끝나야지 다음 것 실행) 
<img src="https://velog.velcdn.com/images/korea_no_1/post/986464d8-4276-4b81-a154-6257d53ca2af/image.png" alt=""></li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="비동기asynchronous란">비동기(Asynchronous)란?</h4>
<ul>
<li>병렬적으로 작업을 수행한다</li>
<li>요청을 보낸 후 응답의 수락 여부와는 상관없이 다음 태스크가 동작하는 방식이다<ul>
<li>A 업무가 실행되는 동안 B업무도 할 수 있으므로 자원을 효율적으로 사용할 수 있다. </li>
</ul>
</li>
<li>비동기 요청시 응답 후 처리할 <strong>&#39;콜백 함수&#39;</strong>를 함께 알려준다. 즉, 해당 태스크가 완료되었을 때, <strong>&#39;콜백 함수&#39;</strong>가 호출된다</li>
</ul>
<h4 id="프로미스의-필요성">프로미스의 필요성</h4>
<ul>
<li><strong>Callback Hell</strong><ul>
<li>콜백 함수를 익명 함수(무명 함수)로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 감당하기 힘들정도로 깊어지는 현상</li>
<li>이벤트 처리 및 서버 통신과 같은 비동기적인 작업을 수행 시 발생</li>
<li>코드 가독성 저하</li>
</ul>
</li>
</ul>
<h4 id="front-end-와-back-end-의-통신">Front-end 와 Back-end 의 통신</h4>
<ul>
<li><p>Front와 Back이 주고 받을 수 있어야 함</p>
<ul>
<li>Back(express) 에서는 CRUD method를 만들고 대기함</li>
</ul>
</li>
<li><p>Front는 Back 에서 설게한대로 요청을 넣음</p>
<ul>
<li>Front 에서는 비동기 통신 방법을 이해해야 한다</li>
</ul>
</li>
</ul>
<h4 id="front-end에서-구현하는-비동기-통신">Front-end에서 구현하는 비동기 통신</h4>
<ul>
<li><strong>AJAX : Asynchronous JavaScript and XML</strong>
이름 그대로, JS를 사용한 비동기 통신, 클라이언트와 서버간에 데이터를 주고받는 기술이다.<ul>
<li>Ajax는 웹 페이지 전체를 다시 로딩(새로고침) 하지 않고도, 웹 페이지의 일부분만을 갱신 가능</li>
<li>Ajax를 이용하면 백그라운드 영역에서 서버와 통신하여, 그 결과를 웹 페이지의 일부분에만 표시 가능</li>
</ul>
</li>
</ul>
<blockquote>
<p>Ajax를 통해 서버와 비동기적으로 통신함으로 인해 우리는 전체 웹페이지를 다시 불러오는 동기 방식과는 다르게 점진적으로 해당 부분의 사용자 인터페이스를 갱신할 수 있다.</p>
</blockquote>
<blockquote>
<p>예를 들면, 페이스북에서 좋아요 버튼을 누를 때마다 페이지가 갱신이되면 많이 불편하다 그렇기에 비동기식으로 데이터를 주고 받으며 해결하는 것이다.</p>
</blockquote>
<ul>
<li><p>*<em>Axios *</em></p>
<ul>
<li><p>Axios는 브라우저, Node.js를 위한 Promise API를 활용하는 HTTP 비동기 통신 라이브러리이다. </p>
</li>
<li><p>Ajax와 더불어 사용한다</p>
</li>
<li><p>JS에는 fetch API가 있지만, 프레임워크에서는 AJAX를 구현할때 Axios를 사용한다.</p>
</li>
<li><p>특징</p>
<ul>
<li>요청과 응답 데이터의 변형</li>
<li>HTTP 요청 취소</li>
<li>HTTP 요청과 응답을 JSON 형태로 자동 변경</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><strong>예시</strong></p>
<pre><code>GET : axios.get(url[, config])
POST : axios.post(url, data[, config])
PUT : axios.put(url, data[, config])
DELETE : axios.delete(url[, config])</code></pre><ul>
<li><strong>XMLHttpRequest</strong><ul>
<li>라이브러리 없이는 브라우저가 지원하는 XMLHttpRequest 객체 이용</li>
<li>AJAX 요청 시 Axios 라이브러리 활용</li>
<li>HTML에 아래 스크립트를 추가하면 사용할 수 있음</li>
</ul>
</li>
</ul>
<pre><code>&lt;script src=&quot;https://unpkg.com/axios/dist/axios.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;
// 예제 코드 작성
&lt;/script&gt;</code></pre><h4 id="callback-함수">CallBack 함수</h4>
<p>: 함수에 파라미터로 들어가는 함수이며, 용도는 순차적으로 하고 싶을때 사용한다.</p>
<p>JS에서 함수는 Object라고 한다. 그래서 함수는 다른 함수의 인사로 쓰일 수도 있고 어떤 함수에 의해 리턴될 수도 있다. 이렇게 인자로 넘겨지는 함수를 callback 함수라고 한다.</p>
<p><strong>예시</strong> </p>
<pre><code>&lt;script&gt;
    function first(parameter){
        console.log(1)
        parameter()  // parameter에 second 함수가 실행
    }

    function second(){
        console.log(2)
    }

    first(second)  // first 함수 안의 코드를 실햄시켜 주세요 근데 parameter에 second를 넣어서요

    // first(function(){console.log(2)}) --&gt; first()후에 console.log(2) 바로 실행 하기
&lt;/script&gt;</code></pre><blockquote>
<p>결과 : 
1 
2 </p>
</blockquote>
<p>주석으로 처리된 부분을 콜백 함수로 표현한 것</p>
<pre><code>// function func1(){
//     document.write(&quot;1.함수 실행&quot;);
// }
// function func2(){
//     document.write(&quot;2.함수 실행&quot;);
// }
// func1();   // JS는 위에서부터 읽기 때문에
// func2();

function func(){
    document.write(&quot;2.함수 실행&quot;);
}
function callback(str){
    document.write(&quot;1.함수 실행&quot;);
    str();
}
callback(func);</code></pre><blockquote>
<p>결과 : 1. 함수 실행 2. 함수 실행</p>
</blockquote>
<hr>
<h3 id="code">Code</h3>
<h4 id="packagejson">package.json</h4>
<ul>
<li>현재 프로젝트에 대한 정보와 사용 중인 패키지에 대한 정보를 담은 파일<ul>
<li>같은 패키지라도 버전별로 기능이 다를 수 있으므로 버전을 기록</li>
<li>노드 프로젝트 시작 전 package.json 부터 만들고 시작함(npm init)<pre><code>npm init</code></pre></li>
<li>npm init 이 완료되면 폴더에 node_modules 설치됨</li>
<li>npm run [스크립트명]으로 스크립트 실행
 ex. npm run </li>
</ul>
</li>
</ul>
<h4 id="express-설치하기">express 설치하기</h4>
<pre><code>npm install express</code></pre><p>package.json에 기록이 된다</p>
<h4 id="node_modules">node_modules</h4>
<ul>
<li><p>npm install 시 node_modules 폴더 생성 </p>
</li>
<li><blockquote>
<p>git에 안 올리는게 정석 / package.json으로 확인하기</p>
</blockquote>
<ul>
<li>내부에 설치한 패키지들이 들어있음</li>
<li>express 외에도 express와 의존 관계가 있는 패키지들이 모두 설치</li>
</ul>
</li>
<li><p>package-lock.json도 생성되어 패키지 간 의존 관계를 명확하게 표시함</p>
</li>
</ul>
<h4 id="nodemon-설치">nodemon 설치</h4>
<pre><code>npm install --save-dev nodemon</code></pre><h4 id="요청과-응답">요청과 응답</h4>
<pre><code>const http = require(&#39;http&#39;); 

http.createServer((req, res) =&gt; {    
    res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/html; charset=urf-8&#39;});
    res.write(&#39;&lt;h1&gt;Hello Node!&lt;/h1&gt;&#39;);
    res.end(&#39;&lt;p&gt;Hello Server!!&lt;/p&gt;&#39;);
}).listen(8080, () =&gt; {
    console.log(&#39;8080포트에서 서버 대기 중&#39;);
});
</code></pre><p>res 메서드로 응답 보냄</p>
<ul>
<li>write로 응답 내용을 적고</li>
<li>end로 응답 마무리(내용을 넣어도 됨)</li>
</ul>
<p>listen(포트) 메서드로 특정 포트에 연결</p>
<h4 id="실행-방법">실행 방법</h4>
<p>node [.js파일 이름] : 수정 내용 즉시 반영 x 
nodemon [.js파일 이름] : 수정 내용 즉시 반영</p>
<pre><code>const http = require(&#39;http&#39;); 

const server = http.createServer((req, res) =&gt; {    
    res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/html; charset=urf-8&#39;});
    res.write(&#39;&lt;h1&gt;Hello Node!&lt;/h1&gt;&#39;);
    res.end(&#39;&lt;p&gt;Hello Server!!&lt;/p&gt;&#39;);
});
server.listen(8080);

server.on(&#39;listening&#39;, () =&gt; {
    console.log(&#39;8080포트에서 서버 대기 중입니다.&#39;);
});
server.on(&#39;error&#39;, (error) =&gt; {
    console.log(error);
});</code></pre><h4 id="여러-개의-서버-실행">여러 개의 서버 실행</h4>
<p>createServer를 여러 번 호출하여 한번에 여러 개의 서버 실행 가능
 <strong>단, 포트를 다르게 해아함</strong></p>
<pre><code>const http = require(&#39;http&#39;);

http.createServer((req, res) =&gt; {
    res.writeHead(200, {&#39;Content-Type&#39;: &#39;text/html; charset=utf-8&#39;});
    res.write(&#39;&lt;h1&gt;Hello 8080&lt;/h1&gt;&#39;);
    res.end(&#39;&lt;p&gt;Hello Server~ &lt;/p&gt;&#39;);
})
.listen(8080, () =&gt; {    // 서버 연결
    console.log(&#39;8080번 포트에서 서버 대기중 입니다.&#39;);
});

http.createServer((req, res) =&gt; {
    res.writeHead(200, {&#39;Content-Type&#39;:&#39;text/html; charset=utf-8&#39;})
    res.write(&#39;&lt;h1&gt;Hello 8081&lt;/h1&gt;&#39;);
    res.end(&#39;&lt;p&gt;Hello Server~ &lt;/p&gt;&#39;);
})
.listen(8081, () =&gt; {
    console.log(&#39;8081번 포트에서 서버 대기 중&#39;);
});</code></pre><p>=&gt; 실행 결과 )
실행후, console창에 
8080번 포트에서 서버 대기중 입니다
8081번 포트에서 서버 대기 중</p>
<p>이 뜨며, </p>
<p>localhost:8080 과 localhost:8081 두 개의 페이지가 각각 열리며 작성한 내용들을 볼 수 있다. </p>
<h4 id="비동기-처리요청과-응답">비동기 처리(요청과 응답)</h4>
<ul>
<li>server.html<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
  &lt;meta charset=&quot;UTF-8&quot;&gt;
  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
  &lt;title&gt;Node.js 웹 서버&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;Node.js 웹 서버&lt;/h1&gt;
  &lt;p&gt; 만들어 보자잇&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre></li>
</ul>
<pre><code>
- http.js</code></pre><p>const http = require(&#39;http&#39;);
const fs = require(&#39;fs&#39;).promises;</p>
<p>http.createServer(async (req, res) =&gt; {
    try {
        const data = await fs.readFile(&#39;./server.html&#39;);
        res.writeHead(200, {&#39;Content-Type&#39;:&#39;text/html; charset=utf-8&#39;});
        res.end(data);
    } catch(err) {
        console.error(err);
        res.writeHead(500, {&#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39;});
        res.end(err.message);
    }<br>}).listen(8080, () =&gt; {
    console.log(&#39;8080번 포트에서 서버 대기 중&#39;);
});</p>
<pre><code>**http.js에 대해 코드 분석
**
- const http = require(&#39;http&#39;) 의 경우, Node.js에서 http 서버를 만들기 위해 필요한 http 모듈을 가져온다.

- const fs = require(&#39;fs&#39;).promises; 
fs는 파일 시스템에 접근하는 모듈이다. 해당 모듈을 사용하여 파일을 읽고, 쓰고, 삭제하는 등의 작업을 할 수 있다. 
.promises 를 사용함으로써, fs 모듈의 파일 작업을 promise 기반으로 사용할 수 있다. 또한, 기존의 callback 방식과 다르게 async / await 을 사용하여 비동기 방식으로 처리를 하였다

- http.createServer(async, (req, res) =&gt; { }) 

http.createServer()는 새로운 http 서버 객체를 생선한다. 이 메서드는 요청(req)과 응답(res) 객체를 매개변수로 받는 콜백 함수를 설정 할 수 있다

async 함수로 만들어졌기에 내부에서 await을 사용할 수 있으며, 비동기 코드를 동기적인 코드처럼 사용할 수 있다.
- const data = await fs.readFile(./server.html&#39;)

fs.promises.readFile 메서드를 사용하여 server.html 파일을 읽는다
await 키워드를 사용하면 프로미스가 처리될 때까지 기다릴 수 있으며, 비동기 처리 결과를 마치 동기 처리한 것처럼 다룰 수 있다.
await은 실행 될때까지 대기한다.(파일은 읽는데 오래 걸리기 때문에)

await 뒤에 있는 fs.readFile() 함수는 프로미스를 반환합니다. 프로미스가 성공적으로 처리되면 파일 내용을 data 변수에 할당하게 됩니다.

await는 비동기 작업을 처리하는 동안 함수 실행을 잠시 중단시키고, 그 작업이 완료되면 결과를 반환합니다. 이 방식은 코드의 가독성을 높이고, callback 지옥을 피할 수 있게 도와줍니다.

- res.writeHead(200, {&#39;Content-Type&#39;:&#39;text/html; charset=utf-8&#39;});

클라이언트에 응답할 때, HTTP 헤더를 설정하는 부분dl다. 200은 성공적인 요청을 의미하는 상태 코드이다. 헤더에는 Content-Type이 포함되어 있으며, 서버에서 응답하는 콘텐츠가 text/html 형식이라는 것을 명시합니다. charset=utf-8은 응답의 인코딩 방식을 UTF-8로 설정해 클라이언트가 제대로 된 문자를 표시할 수 있도록 한다.

- res.end(data)

res.end() 메서드는 서버가 클라이언트에게 응답을 끝내는 함수이다. 인수로 data를 넘기면, 읽어온 HTML 파일의 내용을 클라이언트에게 보낸다. 이 때 data는 앞서 fs.readFile()을 통해 읽은 server.html 파일의 내용이다.

- catch(err)

파일을 읽는 과정에서 오류가 발생할 경우 try 블록에서 던져진 오류를 처리하는 부분이다. 만약 파일을 읽는 도중 문제가 생기면 이 블록이 실행되어 서버 오류 상태(500)를 클라이언트에게 응답한다. 또한 err.message로 오류 메시지를 전달한다.

#### REST 서버 만들기(GIT 소스코드 참조 restServer.js)

- restFront.css</code></pre><p>a { color: blue; text-decoration: none; }</p>
<pre><code>
- restFront.html</code></pre><!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="utf-8" />
  <title>RESTful SERVER</title>
  <link rel="stylesheet" href="./restFront.css" />
</head>
<body>
<nav>
  <a href="/">Home</a>
  <a href="/about">About</a>
</nav>
<div>
  <form id="form">
    <input type="text" id="username">
    <button type="submit">등록</button>
  </form>
</div>
<div id="list"></div>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="./restFront.js"></script>
</body>
</html>
```

<ul>
<li>restFront.js</li>
</ul>
<pre><code>async function getUser() { // 로딩 시 사용자 가져오는 함수
    try {
      const res = await axios.get(&#39;/users&#39;);
      const users = res.data;
      const list = document.getElementById(&#39;list&#39;);
      list.innerHTML = &#39;&#39;;
      // 사용자마다 반복적으로 화면 표시 및 이벤트 연결
      Object.keys(users).map(function (key) {
        const userDiv = document.createElement(&#39;div&#39;);
        const span = document.createElement(&#39;span&#39;);
        span.textContent = users[key];
        const edit = document.createElement(&#39;button&#39;);
        edit.textContent = &#39;수정&#39;;
        edit.addEventListener(&#39;click&#39;, async () =&gt; { // 수정 버튼 클릭
          const name = prompt(&#39;바꿀 이름을 입력하세요&#39;);
          if (!name) {
            return alert(&#39;이름을 반드시 입력하셔야 합니다&#39;);
          }
          try {
            await axios.put(&#39;/user/&#39; + key, { name });
            getUser();
          } catch (err) {
            console.error(err);
          }
        });
        const remove = document.createElement(&#39;button&#39;);
        remove.textContent = &#39;삭제&#39;;
        remove.addEventListener(&#39;click&#39;, async () =&gt; { // 삭제 버튼 클릭
          try {
            await axios.delete(&#39;/user/&#39; + key);
            getUser();
          } catch (err) {
            console.error(err);
          }
        });
        userDiv.appendChild(span);
        userDiv.appendChild(edit);
        userDiv.appendChild(remove);
        list.appendChild(userDiv);
        console.log(res.data);
      });
    } catch (err) {
      console.error(err);
    }
  }

  window.onload = getUser; // 화면 로딩 시 getUser 호출
  // 폼 제출(submit) 시 실행
  document.getElementById(&#39;form&#39;).addEventListener(&#39;submit&#39;, async (e) =&gt; {
    e.preventDefault();
    const name = e.target.username.value;
    if (!name) {
      return alert(&#39;이름을 입력하세요&#39;);
    }
    try {
      await axios.post(&#39;/user&#39;, { name });
      getUser();
    } catch (err) {
      console.error(err);
    }
    e.target.username.value = &#39;&#39;;
  });</code></pre><ul>
<li>restServer.js<pre><code>const http = require(&#39;http&#39;);
const fs = require(&#39;fs&#39;).promises;
const path = require(&#39;path&#39;);
</code></pre></li>
</ul>
<p>const users = {}; // 데이터 저장용</p>
<p>http.createServer(async (req, res) =&gt; {
  try {
    if (req.method === &#39;GET&#39;) {
      if (req.url === &#39;/&#39;) {
        const data = await fs.readFile(path.join(<strong>dirname, &#39;restFront.html&#39;));
        res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/html; charset=utf-8&#39; });
        return res.end(data);
      } else if (req.url === &#39;/about&#39;) {
        const data = await fs.readFile(path.join(</strong>dirname, &#39;about.html&#39;));
        res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/html; charset=utf-8&#39; });
        return res.end(data);
      } else if (req.url === &#39;/users&#39;) {
        res.writeHead(200, { &#39;Content-Type&#39;: &#39;application/json; charset=utf-8&#39; });
        return res.end(JSON.stringify(users));
      }
      // /도 /about도 /users도 아니면
      try {
        const data = await fs.readFile(path.join(__dirname, req.url));
        return res.end(data);
      } catch (err) {
        // 주소에 해당하는 라우트를 못 찾았다는 404 Not Found error 발생
      }
    } else if (req.method === &#39;POST&#39;) {
      if (req.url === &#39;/user&#39;) {
        let body = &#39;&#39;;
        // 요청의 body를 stream 형식으로 받음
        req.on(&#39;data&#39;, (data) =&gt; {
          body += data;
        });
        // 요청의 body를 다 받은 후 실행됨
        return req.on(&#39;end&#39;, () =&gt; {
          console.log(&#39;POST 본문(Body):&#39;, body);
          const { name } = JSON.parse(body);
          const id = Date.now();
          users[id] = name;
          res.writeHead(201, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
          res.end(&#39;등록 성공&#39;);
        });
      }
    } else if (req.method === &#39;PUT&#39;) {
      if (req.url.startsWith(&#39;/user/&#39;)) {
        const key = req.url.split(&#39;/&#39;)[2];
        let body = &#39;&#39;;
        req.on(&#39;data&#39;, (data) =&gt; {
          body += data;
        });
        return req.on(&#39;end&#39;, () =&gt; {
          console.log(&#39;PUT 본문(Body):&#39;, body);
          users[key] = JSON.parse(body).name;
          res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
          return res.end(JSON.stringify(users));
        });
      }
    } else if (req.method === &#39;DELETE&#39;) {
      if (req.url.startsWith(&#39;/user/&#39;)) {
        const key = req.url.split(&#39;/&#39;)[2];
        delete users[key];
        res.writeHead(200, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
        return res.end(JSON.stringify(users));
      }
    }
    res.writeHead(404);
    return res.end(&#39;NOT FOUND&#39;);
  } catch (err) {
    console.error(err);
    res.writeHead(500, { &#39;Content-Type&#39;: &#39;text/plain; charset=utf-8&#39; });
    res.end(err.message);
  }
})
  .listen(8082, () =&gt; {
    console.log(&#39;8082번 포트에서 서버 대기 중입니다&#39;);
  });</p>
<pre><code>
#### JavaScript(JS)에서 map 함수
: map( ) 함수는 **배열을 순회**해서 **각 요소를 콜백 함수로 적용해서 처리해 모은 새로운 배열을 반환**하기 위한 함수이다. 

- map( ) 함수에 전달되는 콜백 함수는 &#39;각 요소를 변환하여 새로운 배열로 매핑(mapping)하는 역할을 한다&#39; 라고 말한다

- 간단 예제 : 숫자 배열을 받아 각 숫자를 두 배로 만들어 새로운 배열을 생성하는 map( ) 함수의 예시

JS</code></pre><p>const numbers = [1, 2, 3, 4, 5];</p>
<p>const doubledNumbers = numbers.map(function(number)) {
    return number * 2;
});</p>
<p>console.log(doubledNumbers);</p>
<p>// 출력 : [2, 4, 6, 8, 10]</p>
<p>```</p>
<hr>
<h3 id="tutorials">Tutorials</h3>
<p><a href="https://www.w3schools.com">Learn To Code</a></p>
<p><a href="https://developer.mozilla.org/ko/docs/Learn">Web 개발 학습</a></p>
<p><a href="https://www.codecademy.com/catalog/language/html-css">html-css</a></p>
<p><a href="https://poiemaweb.com">웹프로그래밍 튜토리얼(한글)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[백준 1263]]></title>
            <link>https://velog.io/@korea_no_1/%EB%B0%B1%EC%A4%80-1263</link>
            <guid>https://velog.io/@korea_no_1/%EB%B0%B1%EC%A4%80-1263</guid>
            <pubDate>Mon, 30 Sep 2024 21:39:07 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/korea_no_1/post/32f661ae-f881-4543-9e80-ab81866f6281/image.png" alt="">
w[0] for w in work는 <strong>리스트 컴프리헨션(list comprehension)</strong>의 한 부분으로, 이 구문은 work 리스트 안의 각 리스트에서 첫 번째 값을 추출하는 간결한 방법입니다. </p>
<blockquote>
<p>해당 방법에 대해서 오래 기억하기 위해서 작성한 페이지</p>
</blockquote>
<pre><code>N = int(input())
work = []   # 모든 입력을 저장할 리스트

for i in range(N):
    temp = list(map(int, input().split()))   # 입력받은 값을 임시 리스트에 저장
    work.append(temp)   # 각 입력을 work 리스트에 추가

first_hap = sum(w[0] for w in work)   # w[0]는 for문의 w 이다

# 입력 값)
4
3 5
8 14
5 20
1 16</code></pre><h3 id="1-work-리스트">1. work 리스트</h3>
<p>먼저, work 리스트는 여러 개의 리스트를 포함한 2차원 리스트입니다. 예를 들어, 다음과 같은 입력이 있다고 가정합니다:</p>
<pre><code>work = [
    [3, 5],
    [8, 14],
    [5, 20],
    [1, 16]
]</code></pre><p>여기서 work는 4개의 리스트를 포함하는 리스트입니다. 각 리스트는 두 개의 정수 값을 가지고 있습니다.</p>
<h3 id="2-리스트-컴프리헨션의-구조">2. 리스트 컴프리헨션의 구조</h3>
<p>w[0] for w in work는 리스트 컴프리헨션의 일부로, 그 구조는 다음과 같습니다:</p>
<blockquote>
<p>표현식 for 변수 in 반복가능한 객체</p>
</blockquote>
<p>이를 해석해 보면:</p>
<p>for 변수 in 반복가능한 객체: work라는 리스트 안에서 각 요소(각각의 리스트)를 하나씩 꺼내 w에 할당합니다.
표현식: w[0]은 각 리스트 w의 첫 번째 요소를 의미합니다.
따라서, 리스트 컴프리헨션은 work 리스트의 각 리스트에서 첫 번째 요소를 추출하는 동작을 합니다.</p>
<h3 id="3-for-w-in-work">3. for w in work</h3>
<p>이 부분은 work 리스트를 반복하는 구문입니다. work 안에 있는 각 리스트를 하나씩 가져와서 변수 w에 할당합니다. 예를 들어:</p>
<ul>
<li>첫 번째 반복: w는 [3, 5]</li>
<li>두 번째 반복: w는 [8, 14]</li>
<li>세 번째 반복: w는 [5, 20]</li>
<li>네 번째 반복: w는 [1, 16]</li>
</ul>
<p>즉, for w in work는 work 리스트의 각 요소(리스트)를 순서대로 가져오는 역할을 합니다.</p>
<h3 id="4-w0">4. w[0]</h3>
<p>이 부분은 w라는 리스트의 첫 번째 요소를 의미합니다. w는 work 리스트의 각 요소(리스트) 중 하나이기 때문에, w[0]은 그 리스트의 첫 번째 요소를 나타냅니다. 예를 들어:</p>
<ul>
<li>첫 번째 반복: w가 [3, 5]일 때, w[0]은 3</li>
<li>두 번째 반복: w가 [8, 14]일 때, w[0]은 8</li>
<li>세 번째 반복: w가 [5, 20]일 때, w[0]은 5</li>
<li>네 번째 반복: w가 [1, 16]일 때, w[0]은 1</li>
</ul>
<p>즉, w[0]은 각 리스트의 첫 번째 요소를 의미합니다.</p>
<h3 id="5-전체-리스트-컴프리헨션-구문">5. 전체 리스트 컴프리헨션 구문</h3>
<p>이제 w[0] for w in work 구문을 전체로 보면:</p>
<blockquote>
<p>[w[0] for w in work]</p>
</blockquote>
<p>이것은 work 리스트 안의 각 리스트에서 첫 번째 요소를 추출하여 새로운 리스트를 만듭니다. 예를 들어:</p>
<pre><code>work = [
    [3, 5],
    [8, 14],
    [5, 20],
    [1, 16]
]


first_elements = [w[0] for w in work]</code></pre><p>위 코드에서 first_elements는 [3, 8, 5, 1]이 됩니다. 각 리스트의 첫 번째 요소들만 모아서 새로운 리스트를 만들었기 때문입니다.</p>
<h3 id="6-sum-함수와의-결합">6. sum() 함수와의 결합</h3>
<p>만약 이 첫 번째 값들의 합을 구하고 싶다면, 이 리스트 컴프리헨션을 sum() 함수와 결합할 수 있습니다:</p>
<pre><code>total_sum = sum(w[0] for w in work)</code></pre><p>여기서 sum() 함수는 리스트 컴프리헨션이 만들어낸 값들을 모두 더해줍니다. 예를 들어, w[0] for w in work는 [3, 8, 5, 1] 리스트를 생성하므로, sum()은 3 + 8 + 5 + 1 = 17을 계산합니다.</p>
<p>요약</p>
<p>for w in work: work 리스트의 각 리스트를 w에 할당하면서 반복합니다.
w[0]: 각 리스트의 첫 번째 요소를 의미합니다.
sum(w[0] for w in work): 각 리스트의 첫 번째 요소들을 더한 값을 계산합니다.
이렇게 하면 각 리스트의 첫 번째 요소만을 추출하여 그 합을 구하는 동작을 효율적으로 수행할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ESP32 와 SEN0609(C4001)-12m 연결하기]]></title>
            <link>https://velog.io/@korea_no_1/ESP32-%EC%99%80-SEN0609C4001-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@korea_no_1/ESP32-%EC%99%80-SEN0609C4001-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 02 Sep 2024 18:19:32 GMT</pubDate>
            <description><![CDATA[<h3 id="esp32의-pin-map">ESP32의 PIN MAP</h3>
<p><a href="https://docs.espressif.com/projects/esp-idf/en/stable/esp32/hw-reference/esp32/get-started-devkitc.html">ESP32_DEVKIT_V4</a> - ESP32_WROOM_32D Pin Map</p>
<p>ESP32의 D2, D3는 사용하지 말라고 명시되어 있다. </p>
<p>그렇기에, 이전에 사용하였던 번호인 16, 17번을 그대로 사용하려고 한다.
ESP32의 RX는 16으로 하며, TX는 17로 지정한다</p>
<p>연결 코드는 아래와 같다</p>
<pre><code>#include &quot;DFRobot_C4001.h&quot;

//#define I2C_COMMUNICATION  //use I2C for communication, but use the serial port for communication if the line of codes were masked

#ifdef  I2C_COMMUNICATION
  /*
   * DEVICE_ADDR_0 = 0x2A     default iic_address
   * DEVICE_ADDR_1 = 0x2B
   */
  DFRobot_C4001_I2C radar(&amp;Wire ,DEVICE_ADDR_0);
#else
/* ---------------------------------------------------------------------------------------------------------------------
 *    board   |             MCU                | Leonardo/Mega2560/M0 |    UNO    | ESP8266 | ESP32 |  microbit  |   m0  |
 *     VCC    |            3.3V/5V             |        VCC           |    VCC    |   VCC   |  VCC  |     X      |  vcc  |
 *     GND    |              GND               |        GND           |    GND    |   GND   |  GND  |     X      |  gnd  |
 *     RX     |              TX                |     Serial1 TX1      |     5     |   5/D6  |  D2   |     X      |  tx1  |
 *     TX     |              RX                |     Serial1 RX1      |     4     |   4/D7  |  D3   |     X      |  rx1  |
 * ----------------------------------------------------------------------------------------------------------------------*/
/* Baud rate cannot be changed */
  #if defined(ARDUINO_AVR_UNO) || defined(ESP8266)
    SoftwareSerial mySerial(4, 5);
    DFRobot_C4001_UART radar(&amp;mySerial ,9600);
  #elif defined(ESP32)
    DFRobot_C4001_UART radar(&amp;Serial1 ,9600 ,/*rx*/17 ,/*tx*/16);  // GPIO 10:RX, GPIO 9:TX  / D2=9 , D3=10
  #else
    DFRobot_C4001_UART radar(&amp;Serial1 ,9600);
  #endif
#endif

void setup()
{
  Serial.begin(115200);
  while(!Serial);
  while(!radar.begin()){
    Serial.println(&quot;NO Devices !&quot;);
    delay(1000);
  }
  Serial.println(&quot;Device connected!&quot;);

  // exist Mode
  radar.setSensorMode(eExitMode);

  sSensorStatus_t data;
  data = radar.getStatus();
  //  0 stop  1 start
  Serial.print(&quot;work status  = &quot;);
  Serial.println(data.workStatus);

  //  0 is exist   1 speed
  Serial.print(&quot;work mode  = &quot;);
  Serial.println(data.workMode);

  //  0 no init    1 init success
  Serial.print(&quot;init status = &quot;);
  Serial.println(data.initStatus);
  Serial.println();

  /*
   * min Detection range Minimum distance, unit cm, range 0.3~25m (30~2500), not exceeding max, otherwise the function is abnormal.
   * max Detection range Maximum distance, unit cm, range 2.4~25m (240~2500)
   * trig Detection range Maximum distance, unit cm, default trig = max
   */
  if(radar.setDetectionRange(/*min*/30, /*max*/1000, /*trig*/1000)){
    Serial.println(&quot;set detection range successfully!&quot;);
  }
  // set trigger sensitivity 0 - 9
  if(radar.setTrigSensitivity(1)){
    Serial.println(&quot;set trig sensitivity successfully!&quot;);
  }

  // set keep sensitivity 0 - 9
  if(radar.setKeepSensitivity(2)){
    Serial.println(&quot;set keep sensitivity successfully!&quot;);
  }
  /*
   * trig Trigger delay, unit 0.01s, range 0~2s (0~200)
   * keep Maintain the detection timeout, unit 0.5s, range 2~1500 seconds (4~3000)
   */
  if(radar.setDelay(/*trig*/100, /*keep*/4)){
    Serial.println(&quot;set delay successfully!&quot;);
  }


  // get confige params
  Serial.print(&quot;trig sensitivity = &quot;);
  Serial.println(radar.getTrigSensitivity());
  Serial.print(&quot;keep sensitivity = &quot;);
  Serial.println(radar.getKeepSensitivity());

  Serial.print(&quot;min range = &quot;);
  Serial.println(radar.getMinRange());
  Serial.print(&quot;max range = &quot;);
  Serial.println(radar.getMaxRange());
  Serial.print(&quot;trig range = &quot;);
  Serial.println(radar.getTrigRange());

  Serial.print(&quot;keep time = &quot;);
  Serial.println(radar.getKeepTimerout());

  Serial.print(&quot;trig delay = &quot;);
  Serial.println(radar.getTrigDelay());

}

void loop()
{
  // Determine whether the object is moving
  if(radar.motionDetection()){
    Serial.println(&quot;exist motion&quot;);
    Serial.println();
  }
  delay(100);
}
</code></pre><p>위의 코드를 실행시키고 변형 시켜서 내가 출력하고자 하는 것들을 출력하면 된다. </p>
<h4 id="2번째-energy-target_number">2번째 energy, target_number</h4>
<pre><code>#include &quot;DFRobot_C4001.h&quot;

//#define I2C_COMMUNICATION  //use I2C for communication, but use the serial port for communication if the line of codes were masked

#ifdef  I2C_COMMUNICATION
  /*
   * DEVICE_ADDR_0 = 0x2A     default iic_address
   * DEVICE_ADDR_1 = 0x2B
   */
  DFRobot_C4001_I2C radar(&amp;Wire ,DEVICE_ADDR_0);
#else
/* ---------------------------------------------------------------------------------------------------------------------
 *    board   |             MCU                | Leonardo/Mega2560/M0 |    UNO    | ESP8266 | ESP32 |  microbit  |   m0  |
 *     VCC    |            3.3V/5V             |        VCC           |    VCC    |   VCC   |  VCC  |     X      |  vcc  |
 *     GND    |              GND               |        GND           |    GND    |   GND   |  GND  |     X      |  gnd  |
 *     RX     |              TX                |     Serial1 TX1      |     5     |   5/D6  |  D2   |     X      |  tx1  |
 *     TX     |              RX                |     Serial1 RX1      |     4     |   4/D7  |  D3   |     X      |  rx1  |
 * ----------------------------------------------------------------------------------------------------------------------*/
/* Baud rate cannot be changed */
  #if defined(ARDUINO_AVR_UNO) || defined(ESP8266)
    SoftwareSerial mySerial(4, 5);
    DFRobot_C4001_UART radar(&amp;mySerial ,9600);
  #elif defined(ESP32)
    DFRobot_C4001_UART radar(&amp;Serial1 ,9600 ,/*rx*/16 ,/*tx*/17);  // GPIO 10:RX, GPIO 9:TX  / D2=9 , D3=10
  #else
    DFRobot_C4001_UART radar(&amp;Serial1 ,9600);
  #endif
#endif

void setup()
{
  Serial.begin(115200);
  while(!Serial);
  while(!radar.begin()){
    Serial.println(&quot;NO Devices !&quot;);
    delay(1000);
  }
  Serial.println(&quot;Device connected!&quot;);

  // speed Mode
  radar.setSensorMode(eSpeedMode);

  sSensorStatus_t data;
  data = radar.getStatus();
  //  0 stop  1 start
  Serial.print(&quot;work status  = &quot;);
  Serial.println(data.workStatus);

  //  0 is exist   1 speed
  Serial.print(&quot;work mode  = &quot;);
  Serial.println(data.workMode);

  //  0 no init    1 init success
  Serial.print(&quot;init status = &quot;);
  Serial.println(data.initStatus);
  Serial.println();

  /*
   * min Detection range Minimum distance, unit cm, range 0.3~20m (30~2500), not exceeding max, otherwise the function is abnormal.
   * max Detection range Maximum distance, unit cm, range 2.4~20m (240~2500)
   * thres Target detection threshold, dimensionless unit 0.1, range 0~6553.5 (0~65535)
   */
  if (radar.setDetectThres(/*min*/ 11, /*max*/ 1200, /*thres*/ 10)) {
    Serial.println(&quot;set detect threshold successfully&quot;);
  }

  // set Fretting Detection
  radar.setFrettingDetection(eON);

  // get confige params
  Serial.print(&quot;min range = &quot;);
  Serial.println(radar.getTMinRange());
  Serial.print(&quot;max range = &quot;);
  Serial.println(radar.getTMaxRange());
  Serial.print(&quot;threshold range = &quot;);
  Serial.println(radar.getThresRange());
  Serial.print(&quot;fretting detection = &quot;);
  Serial.println(radar.getFrettingDetection());
}

void loop() {
  Serial.print(&quot;target number = &quot;);
  Serial.println(radar.getTargetNumber());  // must exist
  Serial.print(&quot;target Speed  = &quot;);
  Serial.print(radar.getTargetSpeed());
  Serial.println(&quot; m/s&quot;);

  Serial.print(&quot;target range  = &quot;);
  Serial.print(radar.getTargetRange());
  Serial.println(&quot; m&quot;);

  Serial.print(&quot;target energy  = &quot;);
  Serial.println(radar.getTargetEnergy());
  Serial.println();
  delay(100);
}

</code></pre><hr>
<h3 id="센서-설명">센서 설명</h3>
<ul>
<li><p>C4001 mmWave(millimeter-wave)는 정지 물체와 움직이는 물체를 모두 감지할 수 있다는 장점이 있다 </p>
</li>
<li><p>상대적으로 강력한 간섭 방지 기능이 있어 온도 변화, 주변광 변화 및 환경 소음과 같은 요인에 덜 민감하다</p>
</li>
<li><p>사람이 앉아 있든, 잠을 자든, 움직이고 있든 센서는 빠르고 민감하게 사람의 존재를 감지할 수 있다</p>
</li>
</ul>
<h3 id="mmwave-와-infrared-sensor적외선-센서의-차이">MMWave 와 Infrared Sensor(적외선 센서)의 차이</h3>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/1443ab6b-758f-42e6-bf1f-c9d6a4c185a3/image.png" alt=""></p>
<h3 id="distance-and-velocity-detection">Distance and velocity detection</h3>
<ul>
<li>최대 감지 범위는 12m 이고 속도 측정 범위는 초당 0.1 ~ 10m 이다.</li>
</ul>
<h3 id="characteristics">Characteristics</h3>
<ul>
<li><p>I2C 와 UART 두 가지 통신 방법을 지원한다</p>
</li>
<li><p>Human Detection : 최대 8m 거리에서 인간의 존재를 탐지하고, 최대 12m 거리에서 인간의 움직임을 감지할 수 있다</p>
</li>
<li><p>Distance Detection : 1.2m 에서 12m까지의 거리를 측정할 수 있다 </p>
</li>
<li><p>Speed Detection : 0.1m/s 에서 10m/s 까지의 속도를 감지할 수 있다</p>
</li>
<li><p>Strong anti-interference capability : 눈, 안개, 온도, 습도, 먼지, 빛, 소음 등의 요인에 영향을 받지 않는다</p>
</li>
</ul>
<h3 id="installation-method">Installation Method</h3>
<p>: mmWave Sensor는 설치 방법에 민감하며, 부적절한 설치는 센서의 성능과 기능에 영향을 미칠 수 있다. 이 모듈에 일반적으로 사용되는 설치 방법에는 상단 설치, 하단 설치, 수평 설치 및 하향 기울기 설치가 있다 </p>
<h4 id="top-installation상단-설치">Top Installation(상단 설치)</h4>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/de2ff53d-e602-4437-92ef-83b6e4ff6b23/image.png" alt=""></p>
<h4 id="bottom-installation하단-설치">Bottom Installation(하단 설치)</h4>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/dc7175f0-fd6b-4496-8cdb-58a520e63be0/image.png" alt=""></p>
<h4 id="horizontal-installation수평-설치">Horizontal Installation(수평 설치)</h4>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/12be2e46-7dcb-43a0-8aec-cf276fef2a0b/image.png" alt=""></p>
<h3 id="참고문헌">참고문헌</h3>
<p><a href="https://wiki.dfrobot.com/SKU_SEN0610_Gravity_C4001_mmWave_Presence_Sensor_12m_I2C_UART#target_7">C4001_12m</a> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ESP32 와 SEN0557(LD2410) 연결]]></title>
            <link>https://velog.io/@korea_no_1/ESP32-%EC%99%80-SEN0557LD2410-%EC%97%B0%EA%B2%B0</link>
            <guid>https://velog.io/@korea_no_1/ESP32-%EC%99%80-SEN0557LD2410-%EC%97%B0%EA%B2%B0</guid>
            <pubDate>Tue, 27 Aug 2024 03:57:26 GMT</pubDate>
            <description><![CDATA[<p>저는 LD2410을 연결하기 위해서 이번 여름 방학동안 안해본 짓이 없습니다
연결을 완료했더니 방학이 끝나버렸네요</p>
<p>포트 드라이버 깔아서 연결 해줬잖아, 라이브러리 설치해서 해줬잖아,
SoftwareSerial로도 해줬잖아, HardwareSerial위치도 바꿔줬잖아
HomeAssistant 해줬잖아, Virtual Box도 해줬잖아
그냥 다 해줬잖아
<del>메이플 정상화 진행중..</del></p>
<p>근데 그렇게 날 매정하게 버리더니.. 내 간절한 신호는 응답도 안하더니</p>
<p>이런 젠장 
내가 모아온 정보와 코드들을 좀 쌈뽕하게 섞어주고 오류난 부분은 고쳐달라고 요청해서 챗 지피티가 한 번 만져주니 바로 작동을 해버리다니</p>
<p>내가 그렇게 지금까지 너에게 전력을 공급해주고 연결해주던 그 오랜 시간들은 잊어버린거냐구!</p>
<p>그래 챗지피티..너가 이겼다 그래서!!
넌 내가 무료로 쓰기 미안해서 유료 결제 해주려고 한다
<img src="https://velog.velcdn.com/images/korea_no_1/post/7f323f6d-0768-47e9-ab14-ee4d56fe9b66/image.png" alt=""></p>
<h4 id="언제든지-찾아가서-너의-머릿속에있는-정보들을-하나하나-탐해줄거야🥵🥵">언제든지 찾아가서 너의 머릿속에있는 정보들을 하나하나 탐해줄거야🥵🥵</h4>
<h4 id="사실-내가-앞에-저렇게-노가다를-뛰어서-한-번에-너가-성공한건-아닐까-싶어-반박시-챗지피티-냉각수로-넣어버림">사실 내가 앞에 저렇게 노가다를 뛰어서 한 번에 너가 성공한건 아닐까 싶어 반박시 챗지피티 냉각수로 넣어버림</h4>
<blockquote>
<p>이런 나의 노력과 챗지피티의 비상한 머리의 작품은 아래 코드로 제가 이쁘게 드리겠습니다
저처럼 착한 사람있어서 딸깍으로 가져갈 수 있겠네요</p>
</blockquote>
<h4 id="기억해주세요-이-곳에-내가-잠시-살았다는걸">기억해주세요 이 곳에 내가 잠시 살았다는걸</h4>
<h4 id="이-글을-작성하고-있는-in-kwangwoon-univ-제-3열람실-26번">이 글을 작성하고 있는 in KwangWoon Univ 제 3열람실 26번</h4>
<h4 id="major-in-information-convergence">major in Information Convergence</h4>
<h4 id="his-name-is-yu-bin-jeong">His name is Yu Bin Jeong...</h4>
<h4 id="미래에-왕이-될-남자">미래에 왕이 될 남자</h4>
<pre><code>#include &lt;HardwareSerial.h&gt;

HardwareSerial mySerial(2);

size_t readN(uint8_t *buf, size_t len);

bool recdData(uint8_t *buf);

uint8_t Cache[23] = {0};    //Cache

void setup()
{
  Serial.begin(115200); // Use default UART0 for debugging
  mySerial.begin(57600, SERIAL_8N1, 17, 16); // UART2, RX on GPIO17, TX on GPIO16
}

void loop()
{
  recdData(Cache);
}

size_t readN(uint8_t *buf, size_t len)
{
  size_t offset = 0, left = len;
  int16_t Tineout = 1500;
  uint8_t  *buffer = buf;
  long curr = millis();
  while (left) {
    if (mySerial.available()) {
      buffer[offset] = mySerial.read();
      offset++;
      left--;
    }
    if (millis() - curr &gt; Tineout) {
      break;
    }
  }
  return offset;
}

bool recdData(uint8_t *buf)
{
  int16_t Tineout = 50000;
  long curr = millis();
  uint8_t ch;
  bool ret = false;
  while (!ret) {
    if (millis() - curr &gt; Tineout) {
      break;
    }
    if (readN(&amp;ch, 1) == 1) {
      if (ch == 0xF4) {
        buf[0] = ch;
        if (readN(&amp;ch, 1) == 1) {
          if (ch == 0xF3) {
            buf[1] = ch;
            if (readN(&amp;ch, 1) == 1) {
              if (ch == 0xF2) {
                buf[2] = ch;
                if (readN(&amp;ch, 1) == 1) {
                  if (ch == 0xF1) {
                    buf[3] = ch;
                      if (readN(&amp;buf[4], 19) == 19) {
//                        printdf(buf, 23); //Print raw data
                        uint16_t Adistance = buf[10] &lt;&lt; 8 | buf[9];
                        uint16_t Sdistance = buf[13] &lt;&lt; 8 | buf[12];
                        uint16_t Distance = buf[16] &lt;&lt; 8 | buf[15];
                        switch (buf[8]) {
                          case 0x00 : Serial.println(&quot;Detected status: nobody&quot;); break;
                          case 0x01 : Serial.println(&quot;Detected status: moving&quot;); break;
                          case 0x02 : Serial.println(&quot;Detected status: stationary&quot;); break;
                          case 0x03 : Serial.println(&quot;Detected status: moving &amp; stationary object&quot;); break;
                        }
//                        Serial.print(&quot;Energy value of moving object:&quot;);
//                        Serial.println(buf[11]);
//                        Serial.print(&quot;Energy value of stationary object:&quot;);
//                        Serial.println(buf[14]);
//                        Serial.print(&quot;Distance to the moving object in CM:&quot;);
//                        Serial.println(Adistance);
//                        Serial.print(&quot;Distance to the stationary object in CM:&quot;);
//                        Serial.println(Sdistance);
                        Serial.print(&quot;Detection distance CM:&quot;);
                        Serial.println(Distance);
                        break;
                      }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  return ret;
}

void printdf(uint8_t *buf, int len)
{
  for (int i = 0; i &lt; len; i++) {
    if (buf[i] &lt; 0x10) {
      Serial.print(&quot;0&quot;);
    }

    Serial.print(buf[i], HEX);
    Serial.print(&quot; &quot;);
  }
  Serial.println();
}
</code></pre><p>그래서 다들 물어보죠
이 코드를 실행하면 무엇이 나오냐고
그러면 나는 대답하죠</p>
<h4 id="너가-원하는-그-무엇이든-이-안에-담겨져-있다">너가 원하는 그 무엇이든 이 안에 담겨져 있다</h4>
<h3 id="실행-결과">실행 결과</h3>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/2980ed34-4b26-4f8f-97ee-d4bac1a7b0a2/image.png" alt=""></p>
<p>이것만 보아서는 감이 잘 오지 않을거야
왜냐구? 너는 노가다를 안했기 때문이야
진흙밭을 굴러야지 그게 진흙인줄 안다
똥밭을 굴러야지 내가 있는곳이 똥밭인줄 안다</p>
<h4 id="그래-맞아-이것은-바로-거리-탐지기다-두둥">그래 맞아 이것은 바로 거리 탐지기다!! (두둥)</h4>
<p>그래프로 쌈뽕하게 보여주지</p>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/ebb09c53-d387-46e9-bf4f-762ebc5d9b83/image.png" alt=""></p>
<p>센서를 통해서 앞에 사람이 얼마만큼 떨어져있는지 인식하는 이 IoT 의 능력</p>
<p>음하하</p>
<p>내가 앞뒤로 움직였는데 저렇게 나타나있음을 그래프로 보여주지</p>
<p>그리고 아래는 해당 센서에 대한 기술을 작성한 표이니 한 번씩 보고가도록</p>
<p>그럼 20000</p>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/a37d141a-be09-45d0-a96c-df7ba9680fca/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/6169a08c-a433-48bd-8925-b635e07e9434/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/2f05b8d3-09f2-4e76-baa0-a41267dac586/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/ca9e0fbb-b93b-4a3c-8e73-fce3db80a386/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ESP32 와 mmWave(MR60BHA1) 연결하기]]></title>
            <link>https://velog.io/@korea_no_1/ESP32-%EC%99%80-mmWaveMR60BHA1-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@korea_no_1/ESP32-%EC%99%80-mmWaveMR60BHA1-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 27 Aug 2024 00:53:47 GMT</pubDate>
            <description><![CDATA[<p>분명 저번글에서는 ESP32가 아닌 ESP8266과 연결이었다</p>
<p>왜 갑자기 ESP가 변경되었을까?</p>
<h4 id="그건-바로-교수님께서-esp32로-연결하라고-하셨기-때문이다">그건 바로 교수님께서 ESP32로 연결하라고 하셨기 때문이다</h4>
<p>사실 걱정이 많았다 지금까지 ESP32를 사용하여서 Arduino.ide와 연결을 한 적이 없었기에.. 그래서 homeassistant를 통해서 하려고 했지만, 연결은 되어도 sensor 연결이 되지 않았었다....</p>
<p>결국 늘 그렇듯 우리는 답을 찾아낼 것이다
그리고 긴 시간이 지나고 나 역시 그  답을 찾아냈다</p>
<p>Board : ESP32 Dev Module
Upload Speed : 115200 
ESP32 Board 연결(16:TX , 17:RX)</p>
<blockquote>
<p>이 글을 보고있는 어린양을 위해서 내가 친히 사진까지 첨부해드리겠소
감사하시오. TX RX 적혀있는거에 속지마시오 그거는 함정이오</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/da64ee12-8349-403d-8eb9-1f93b4c10400/image.jpg" alt=""></p>
<h3 id="demo1raw-data-export">Demo1.Raw Data export</h3>
<pre><code>#include &quot;Arduino.h&quot;
#include &lt;60ghzbreathheart.h&gt;

// can also try hardware serial with
BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;Serial1);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial1.begin(115200, SERIAL_8N1, 17, 16);  // Serial1.begin(115200);

  //  mySerial.begin(115200);

  while(!Serial);   //When the serial port is opened, the program starts to execute.

  Serial.println(&quot;Readly&quot;);
}

void loop()
{
  // put your main code here, to run repeatedly:
  radar.recvRadarBytes();           //Receive radar data and start processing
  radar.showData();                 //Serial port prints a set of received data frames
  delay(200);                       //Add time delay to avoid program jam
}</code></pre><h3 id="demo2-use-of-human-presence-detection-function">Demo2. Use of human presence detection function</h3>
<pre><code>#include &quot;Arduino.h&quot;
#include &lt;60ghzbreathheart.h&gt;

// can also try hardware serial with
BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;Serial1);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial1.begin(115200, SERIAL_8N1, 17, 16);

  //  mySerial.begin(115200);

  while(!Serial);   //When the serial port is opened, the program starts to execute.

  Serial.println(&quot;Readly&quot;);
}

void loop()
{
  // put your main code here, to run repeatedly:
  radar.HumanExis_Func();           //Human existence information output
  if(radar.sensor_report != 0x00){
    switch(radar.sensor_report){
      case NOONE:
        Serial.println(&quot;Nobody here.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SOMEONE:
        Serial.println(&quot;Someone is here.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case NONEPSE:
        Serial.println(&quot;No human activity messages.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case STATION:
        Serial.println(&quot;Someone stop&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case MOVE:
        Serial.println(&quot;Someone moving&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case BODYVAL:
        Serial.print(&quot;The parameters of human body signs are: &quot;);
        Serial.println(radar.bodysign_val, DEC);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case DISVAL:
        Serial.print(&quot;The sensor judges the distance to the human body to be: &quot;);
        Serial.print(radar.distance, DEC);
        Serial.println(&quot; m&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case DIREVAL:
        Serial.print(&quot;The sensor judges the orientation data with the human body as -- x: &quot;);
        Serial.print(radar.Dir_x);
        Serial.print(&quot; m, y: &quot;);
        Serial.print(radar.Dir_y);
        Serial.print(&quot; m, z: &quot;);
        Serial.print(radar.Dir_z);
        Serial.println(&quot; m&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
    }
  }
  delay(200);                       //Add time delay to avoid program jam
}</code></pre><h3 id="demo3-the-use-of-respiratory-and-heartbeat-functions-in-the-resting-people">Demo3. The use of respiratory and heartbeat functions in the resting people</h3>
<pre><code>#include &quot;Arduino.h&quot;
#include &lt;60ghzbreathheart.h&gt;

// can also try hardware serial with
BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;Serial1);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial1.begin(115200, SERIAL_8N1, 17, 16);  // Serial1.begin(115200);

  while(!Serial);   //When the serial port is opened, the program starts to execute.

  Serial.println(&quot;Readly&quot;);
}


void loop()
{
  // put your main code here, to run repeatedly:
  radar.Breath_Heart();           //Breath and heartbeat information output
  if(radar.sensor_report != 0x00){
    switch(radar.sensor_report){
      case HEARTRATEVAL:
        Serial.print(&quot;Sensor monitored the current heart rate value is: &quot;);
        Serial.println(radar.heart_rate, DEC);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case HEARTRATEWAVE:  //Valid only when real-time data transfer mode is on
        Serial.print(&quot;The heart rate waveform(Sine wave) -- point 1: &quot;);
        Serial.print(radar.heart_point_1);
        Serial.print(&quot;, point 2 : &quot;);
        Serial.print(radar.heart_point_2);
        Serial.print(&quot;, point 3 : &quot;);
        Serial.print(radar.heart_point_3);
        Serial.print(&quot;, point 4 : &quot;);
        Serial.print(radar.heart_point_4);
        Serial.print(&quot;, point 5 : &quot;);
        Serial.println(radar.heart_point_5);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case BREATHNOR:
        Serial.println(&quot;Sensor detects current breath rate is normal.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case BREATHRAPID:
        Serial.println(&quot;Sensor detects current breath rate is too fast.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case BREATHSLOW:
        Serial.println(&quot;Sensor detects current breath rate is too slow.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case BREATHNONE:
        Serial.println(&quot;There is no breathing information yet, please wait...&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case BREATHVAL:
        Serial.print(&quot;Sensor monitored the current breath rate value is: &quot;);
        Serial.println(radar.breath_rate, DEC);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case BREATHWAVE:  //Valid only when real-time data transfer mode is on
        Serial.print(&quot;The breath rate waveform(Sine wave) -- point 1: &quot;);
        Serial.print(radar.breath_point_1);
        Serial.print(&quot;, point 2 : &quot;);
        Serial.print(radar.breath_point_2);
        Serial.print(&quot;, point 3 : &quot;);
        Serial.print(radar.breath_point_3);
        Serial.print(&quot;, point 4 : &quot;);
        Serial.print(radar.breath_point_4);
        Serial.print(&quot;, point 5 : &quot;);
        Serial.println(radar.breath_point_5);
        Serial.println(&quot;----------------------------&quot;);
        break;
    }
  }
  delay(200);                       //Add time delay to avoid program jam
}</code></pre><h4 id="3초-대기후-heart_rate_value-출력">3초 대기후 heart_rate_value 출력</h4>
<pre><code>#include &quot;Arduino.h&quot;
#include &lt;60ghzbreathheart.h&gt;

// can also try hardware serial with
BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;Serial1);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial1.begin(115200, SERIAL_8N1, 17, 16);  // Serial1.begin(115200);

  while(!Serial);   //When the serial port is opened, the program starts to execute.

  Serial.println(&quot;Readly&quot;);
}


void loop()
{
  // put your main code here, to run repeatedly:
  radar.Breath_Heart();           //Breath and heartbeat information output
  if(radar.sensor_report != 0x00)
  {
    switch(radar.sensor_report){
      case HEARTRATEVAL:
        Serial.print(&quot;Sensor monitored the current heart rate value is: &quot;);
        Serial.println(radar.heart_rate, DEC);
        Serial.println(&quot;----------------------------&quot;);
        break;
    }
  }
  delay(3000);                       //Add time delay to avoid program jam
}</code></pre><h3 id="demo4-use-of-the-sleep-function">Demo4. Use of the sleep function</h3>
<pre><code>#include &quot;Arduino.h&quot;
#include &lt;60ghzbreathheart.h&gt;

// can also try hardware serial with
BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;Serial1);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial1.begin(115200, SERIAL_8N1, 17, 16);

  //  mySerial.begin(115200);

  while(!Serial);   //When the serial port is opened, the program starts to execute.

  Serial.println(&quot;Readly&quot;);
}

void loop()
{
  // put your main code here, to run repeatedly:
  radar.SleepInf_Decode();           //Sleep-related information output. Data output begins when the monitoring figure is in bed for five minutes.
  if(radar.sensor_report != 0x00){
    switch(radar.sensor_report){
      case OUTBED:
        Serial.println(&quot;Sensor detects someone currently leaving the bed.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case INBED:
        Serial.println(&quot;Sensor detects that someone is currently in bed.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case NOINOUT:
        Serial.println(&quot;No subject is detected leaving or going to bed.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPAWAKE:
        Serial.println(&quot;Sensor detects that the monitoring people is awake.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPLIGHT:
        Serial.println(&quot;Sensor detects that the monitoring people is in light sleeping.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPDEEP:
        Serial.println(&quot;Sensor detects that the monitoring people is in deep sleeping.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPNONE:
        Serial.println(&quot;Sleep state of the object is not detected.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case AWAKETIME:
        Serial.print(&quot;Sensor monitored the awake sleep time is: &quot;);
        Serial.print(radar.awake_time);
        Serial.println(&quot; min&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case LIGHTTIME:
        Serial.print(&quot;Sensor monitored the light sleep time is: &quot;);
        Serial.print(radar.light_time);
        Serial.println(&quot; min&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case DEEPTIME:
        Serial.print(&quot;Sensor monitored the deep sleep time is: &quot;);
        Serial.print(radar.deep_time);
        Serial.println(&quot; min&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPSCORE:
        Serial.print(&quot;Sensor judgment sleep score is: &quot;);
        Serial.println(radar.sleep_score);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPSTATUE:
        Serial.println(&quot;Sleep integrated state information -- &quot;);
        Serial.print(&quot;Human existence: &quot;);
        if(radar.existence)Serial.println(&quot;human exis&quot;);
        else Serial.println(&quot;human non-existent&quot;);
        Serial.print(&quot;Sleep state: &quot;);
        if(radar.sleep_status == SLEEPDEEP)Serial.println(&quot;sleeping soundly&quot;);
        else if(radar.sleep_status == SLEEPLIGHT)Serial.println(&quot;light sleep&quot;);
        else if(radar.sleep_status == SLEEPAWAKE)Serial.println(&quot;awake&quot;);
        else if(radar.sleep_status == SLEEPNONE)Serial.println(&quot;off the bed&quot;);
        Serial.print(&quot;Average breathing: &quot;);
        Serial.println(radar.breath_rate);
        Serial.print(&quot;Average heart rate: &quot;);
        Serial.println(radar.heart_rate);
        Serial.print(&quot;Number of turning over during sleep: &quot;);
        Serial.println(radar.turn_num);
        Serial.print(&quot;Percentage of substantial exercise during sleep: &quot;);
        Serial.println(radar.substantial_move_ratio);
        Serial.print(&quot;Percentage of small-amplitude movements during sleep: &quot;);
        Serial.println(radar.samll_move_ratio);
        Serial.print(&quot;Number of apnea: &quot;);
        Serial.println(radar.apnea_num);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPQUALITY:
        Serial.println(&quot;Quality of sleep information -- &quot;);
        Serial.print(&quot;Sleep score: &quot;);
        Serial.println(radar.sleep_score);
        Serial.print(&quot;Total time of sleep: &quot;);
        Serial.print(radar.sleep_time);
        Serial.println(&quot; min&quot;);
        Serial.print(&quot;Percentage of waking time: &quot;);
        Serial.println(radar.awake_time_radio);
        Serial.print(&quot;Percentage of light sleep time: &quot;);
        Serial.println(radar.light_time_radio);
        Serial.print(&quot;Percentage of deep sleep time: &quot;);
        Serial.println(radar.deep_time_radio);
        Serial.print(&quot;Total time away from bed: &quot;);
        Serial.print(radar.outbed_time);
        Serial.println(&quot; min&quot;);
        Serial.print(&quot;Total number of times out of bed: &quot;);
        Serial.println(radar.outbed_num);
        Serial.print(&quot;The number of turning over during sleep: &quot;);
        Serial.println(radar.turn_num);
        Serial.print(&quot;Average breathing: &quot;);
        Serial.println(radar.breath_rate);
        Serial.print(&quot;Average heart rate: &quot;);
        Serial.println(radar.heart_rate);
        Serial.print(&quot;Number of apnea: &quot;);
        Serial.println(radar.apnea_num);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPLESS4H:
        Serial.print(&quot;The monitored subjects slept for less than 4 hours.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPOVER12H:
        Serial.print(&quot;The length of sleep of the monitored subjects exceeded 12 hours.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case LONGTIMENOONE:
        Serial.print(&quot;Abnormally unoccupied for long periods of time.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case ERRORNONE:
        Serial.print(&quot;No abnormal information.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
    }
  }
  delay(200);                       //Add time delay to avoid program jam
}</code></pre><h3 id="demo5-send-data-tp-sensor">Demo5. Send data tp Sensor</h3>
<pre><code>#include &quot;Arduino.h&quot;
#include &lt;60ghzbreathheart.h&gt;

// can also try hardware serial with
BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;Serial1);

const unsigned char DevID_buff[10] = {0x53, 0x59, 0x02, 0xA1, 0x00, 0x01, 0x0F, 0x5F, 0x54, 0x43};

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial1.begin(115200, SERIAL_8N1, 17, 16);

  //  mySerial.begin(115200);

  while(!Serial);   //When the serial port is opened, the program starts to execute.

  Serial.println(&quot;Readly&quot;);
}

void loop()
{
  // put your main code here, to run repeatedly:
  radar.send_func(DevID_buff, 10, false);
  delay(50);                       //Do not set the delay time too long, as this may affect the reception of the data frames returned by the radar.
}</code></pre><h3 id="demo6-reset-sensor">Demo6. Reset Sensor</h3>
<pre><code>#include &quot;Arduino.h&quot;
#include &lt;60ghzbreathheart.h&gt;

//#include &lt;SoftwareSerial.h&gt;
// Choose any two pins that can be used with SoftwareSerial to RX &amp; TX
//#define RX_Pin A2
//#define TX_Pin A3

//SoftwareSerial mySerial = SoftwareSerial(RX_Pin, TX_Pin);

// we&#39;ll be using software serial
//BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;mySerial);

// can also try hardware serial with
BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;Serial1);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial1.begin(115200, SERIAL_8N1, 17, 16);

  //  mySerial.begin(115200);

  while(!Serial);   //When the serial port is opened, the program starts to execute.

  Serial.println(&quot;Readly&quot;);

  radar.reset_func();
}

void loop()
{
  // put your main code here, to run repeatedly:
}</code></pre><h3 id="arduino에서-측정한-데이터-옮기는-법">Arduino에서 측정한 데이터 옮기는 법</h3>
<p>코드 업로드 이후 잘 측정이 되고 있음을 확인하고 잘 되고 있으면, serial monitor를 끄고 cmd 창에서 다음과 같이 입력한다.</p>
<pre><code>type COM5 &gt; output.txt</code></pre><p>COM5 의 경우는 현재 내가 쓰고 있는 PORT NUMBER이며, output.txt 는 내가 저장하고 싶은 파일의 이름이다. 즉, 내가 현재 사용하는 port는 COM5이고 저장하고 싶은 파일의 이름은 output.txt 이다. 
이렇게 하면 실행 시킨 이후부터 자동으로 output.txt 에 측정되고 있는 값들이 저장하게 된다. 끄는 방법은 cmd창에서 ctrl + c 키를 누르면 된다. </p>
<p>혹시나 &#39;엑세스가 거부되었습니다&#39; 라는 창이 뜨면 arduino.ide 에서 serial monitor 가 켜져있는지 확인하자
serial monitor가 꺼져있어야지 정상적으로 작동이 가능하다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ESP8266 & mmWave(MR60BHA1) 
정리본]]></title>
            <link>https://velog.io/@korea_no_1/ESP8266-mmWaveMR60BHA1-%EC%A0%95%EB%A6%AC%EB%B3%B8</link>
            <guid>https://velog.io/@korea_no_1/ESP8266-mmWaveMR60BHA1-%EC%A0%95%EB%A6%AC%EB%B3%B8</guid>
            <pubDate>Tue, 13 Aug 2024 05:05:04 GMT</pubDate>
            <description><![CDATA[<p>Board 및 각 설정은 앞에 내용 참고</p>
<blockquote>
<p>ESP32C3 에서는 작동하지 않는다고 명시되어 있다.
Serial1을 직접적으로 사용할 경우, usb 포트가 작동하지 않을 수 있기 때문에.</p>
</blockquote>
<blockquote>
<p>해당 센서는 단일 생명체에서만 탐지가 가능하며, 두 명 이상의 사람에게서 감지가 어렵다 </p>
</blockquote>
<h2 id="frame-structure-definition">Frame Structure Definition</h2>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/4d6fc76e-e7e1-4c98-9115-61463f4f4273/image.png" alt=""></p>
<h2 id="address-allocation-and-data-information-description">Address allocation and data information description</h2>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/7a2c645f-0175-491d-8e5c-ae49f5e36c3d/image.png" alt=""></p>
<hr>
<h2 id="데이터-값에-대해서-심층-탐구">데이터 값에 대해서 심층 탐구</h2>
<blockquote>
<p>탐구할 코드 : 60ghzbreathheart.cpp 코드로
 raw데이터 들이 어떠한 변환을 거쳐서 출력되는지 나와있다. 
 아래는 해당 코드들에 대해 전체 내용이 담겨져 있으며, 코드에 대한 주석과 해석부분을 추가로 작성해두었다. </p>
</blockquote>
<pre><code>#include &quot;Arduino.h&quot;
#include &quot;60ghzbreathheart.h&quot;


// BreathHeart_60Hz 클래스의 생성자 : Stream 객체를 받아들여 초기화
BreathHeart_60GHz::BreathHeart_60GHz(Stream *s)
    : stream(s){
  this-&gt;newData = false;  // 데이터 수신 상태 초기화, &#39;newData&#39;는 새로운 데이터가 수신되었는지 여부를 나타내는 플래그
}

/* 데이터를 스트림에서 읽으며, &#39;MESSAGE_HEAD1&#39;과 &#39;MESSAGE_HEAD2&#39; 바이트를 확인하여 유효한 데이터 프레임인지 확인한다
또한, 유효한 데이터 프레임이 수신되면, 이를 MSG 배열에 저장하고, &#39;newData&#39; 플래그를 true로 설정하여 새로운 데이터가
수신 되었음을 알린다. */

// 데이터를 수신하고 처리하는 메서드
void BreathHeart_60GHz::recvRadarBytes(){
  while (stream-&gt;available()) { // 데이터를 수신할 준비가 되었는지 확인
    if(stream-&gt;read() == MESSAGE_HEAD1){           //Receive header frame 1(첫 번째 헤더 바이트 확인)
      if(stream-&gt;read() == MESSAGE_HEAD2){         //Receive header frame 2
        dataLen = stream-&gt;readBytesUntil(MESSAGE_END2, Msg, 20);  // 데이터 끝까지 읽음
        if (dataLen &gt; 0 &amp;&amp; dataLen &lt; 20){
          Msg[dataLen] = MESSAGE_END2;  // 종료 바이트 추가
          this-&gt;newData = true;  // 새로운 데이터가 수신되었음을 표시
        }
      }
    }
  }
}

/* 아래 함수는 수신된 데이터를 직렬 포트로 출력하며, 
데이터 출력을 완료한 후 &#39;newData&#39; 플래그를 &#39;false&#39;로 설정하고, 배열을 초기화*/

//데이터 출력 함수(&#39;showData&#39;) Radar transmits data frames for display via serial port
void BreathHeart_60GHz::showData(){
  if(this-&gt;newData){
    Serial.print(MESSAGE_HEAD1, HEX);  // 첫 번째 헤더 출력
    Serial.print(&#39; &#39;);
    Serial.print(MESSAGE_HEAD2, HEX);  // 두 번째 헤더 출력
    Serial.print(&#39; &#39;);
    char charVal[4];
    for (byte n = 0; n &lt; dataLen+1; n++) {
      sprintf(charVal, &quot;%02X&quot;, Msg[n]);  // 데이터를 16진수로 변환하여 저장
      Serial.print(charVal);
      Serial.print(&#39; &#39;);
    }
    Serial.println();
    this-&gt;newData = false;  // 데이터 출력을 완료했으므로 플래그를 초기화
    Msg[dataLen] = {0};  // 메시지 배열 초기화
  }
}


/* 아래 함수는 레이더 데이터를 통해 사람이 존재하는지, 그리고 움직임이 있는지를 판단한다
recvRandarBytes()를 호출하여 데이터를 수신하고, reset_val()로 이전 데이터를 초기화한다.
사람의 존재, 움직임, 신체 신호, 거리, 방향 등의 정보를 판별하고 결과를 sensor_report에 저장한다. */

// 사람의 존재와 움직임 판단 함수(&#39;HumanExis_Func&#39;) Judgment of occupied and unoccupied, approach and distance
void BreathHeart_60GHz::HumanExis_Func(){
  recvRadarBytes();   // 데이터를 수신
  reset_val();  // 이전 데이터를 초기화 
  if(this-&gt;newData){   // 새로운 데이터가 수신되었는지 확인
    switch(Msg[0]){   // 첫 번째 메시지 바이트에 따라 분기
      case HUMAN_PSE_RADAR:  
        switch(Msg[1]){   // 두 번째 메시지 바이트에 따라 분기
          case PRESENCE_INF:
            switch(Msg[4]){  // 네 번째 메시지 바이트에 따라 사람의 존재 여부 판단
              case NOONE_HERE:
                showData();
                sensor_report = NOONE;  // 사람이 없음을 나타냄
                break;
              case SOMEONE_HERE:
                showData();
                sensor_report = SOMEONE;  // 사람이 있음을 나타냄
                break;
            }
            break;
          case MOVE_INF:
            switch(Msg[4]){   // 네 번째 메시지 바이트에 따라 움직임 정보 판단
              case PSE_NONE:
                showData();
                sensor_report = NONEPSE;  // 움직임이 없음을 나타냄
                break;
              case STATIONARY:
                showData();
                sensor_report = STATION;  // 정지 상태임을 나타냄
                break;
              case MOVEMENT:
                showData();
                sensor_report = MOVE;  // 움직임이 있음을 나타냄
                break;
            }
            break;
          case BODY_SIG:
            showData();
            sensor_report = BODYVAL;  // 신체 신호가 있음을 나타냄
            bodysign_val = Msg[4];  // 신체 신호 값을 저장
            break;
          case DISTANCE:
            showData();
            sensor_report = DISVAL;   // 거리 값을 나타냄 
            distance = (Msg[4] &lt;&lt; 8 | Msg[5]) / 100.0; // 거리를 계산(미터 단위)
            break;
          case DIRECTIONS:
            showData();
            sensor_report = DIREVAL;   // 방향 정보를 나타냄
            Dir_x = Byte2Int(Msg[4], Msg[5]);  // x축 방향 계산
            Dir_y = Byte2Int(Msg[6], Msg[7]);  // y축 방향 계산
            Dir_z = Byte2Int(Msg[8], Msg[9]);  // z축 방향 계산
            break;
        }
        break;
    }
  }
}

// 아래 함수는 레이더 데이터를 통해 호흡과 심박수를 측정한다.
//호흡과 심박수를 측정하는 함수(&#39;Breath_heart&#39;)Respiratory and heart rate data analysis
void BreathHeart_60GHz::Breath_Heart(){
  recvRadarBytes();  // 데이터를 수신
  reset_val();  // 이전 데이터를 초기화
  if(this-&gt;newData){
    switch(Msg[0]){
      case HEART_INF:
        switch(Msg[1]){
          case HEART_RATE:
            showData();
            sensor_report = HEARTRATEVAL;  // 심박수를 나타냄
            heart_rate = Msg[4];  // 심박수 값을 저장(raw value)
            break;
          case HEART_RATE_WAVE:
            showData();
            sensor_report = HEARTRATEWAVE;  // 심박수 파형을 나타냄
            heart_point_1 = Msg[4];  // 심박 파형의 첫 번째 포인트 저장
            heart_point_2 = Msg[5];  // 심박 파형의 두 번째 포인트 저장
            heart_point_3 = Msg[6];  // 심박 파형의 세 번째 포인트 저장
            heart_point_4 = Msg[7];  // 심박 파형의 네 번째 포인트 저장
            heart_point_5 = Msg[8];  // 심박 파형의 다섯 번째 포인트 저장
            break;
        }
        break;
      case BREATH_RATE_RADAR:
        switch(Msg[1]){   // 두 번째 메시지 바이트에 따라 분기
          case BREATH_INF:
            switch(Msg[4]){  // 네 번째 메시지 바이트에 따라 호흡 상태 판단
              case BREATH_NORMAL:
                showData();
                sensor_report = BREATHNOR;  // 정상 호흡
                break;
              case BREATH_RAPID:
                showData();
                sensor_report = BREATHRAPID;  // 빠른 호흡
                break;
              case BREATH_SLOW:
                showData();
                sensor_report = BREATHSLOW;  // 느린 호흡
                break;
              case BREATH_NONE:
                showData();
                sensor_report = BREATHNONE;  // 호흡 없음
                break;
            }
            break;
          case BREATH_VAL:
            showData();
            sensor_report = BREATHVAL;  // 호흡 속도를 나타냄
            breath_rate = Msg[4];  // 호흡 속도 값을 저장
            break;
          case BREATH_WAVE:
            showData();
            sensor_report = BREATHWAVE;  // 호흡 파형을 나타냄
            breath_point_1 = Msg[4];  // 호흡 파형의 첫 번째 포인트 저장
            breath_point_2 = Msg[5];  // 호흡 파형의 두 번째 포인트 저장
            breath_point_3 = Msg[6];  // 호흡 파형의 세 번째 포인트 저장
            breath_point_4 = Msg[7];  // 호흡 파형의 네 번째 포인트 저장
            breath_point_5 = Msg[8];  // 호흡 파형의 다섯 번째 포인트 저장
            break;
        }
        break;
    }
  }
}

/*아래 함수 다시 해석 */

void BreathHeart_60GHz::SleepInf_Decode(){
  recvRadarBytes();   // 데이터를 수신
  reset_val();  // 이전 데이터를 초기화
  if(this-&gt;newData){  // 새로운 데이터가 수신되었는지 확인
    switch(Msg[0]){  // 첫 번째 메시지 바이트에 따라 분기
      case SLEEP_INF:
        switch(Msg[1]){  // 두 번째 메시지 바이트에 따라 분기
          case INOUT_BED:
            switch(Msg[4]){
              case OUT_BED:
                showData();
                sensor_report = OUTBED;
                break;
              case IN_BED:
                showData();
                sensor_report = INBED;
                break;
              case INOUT_NONE:
                showData();
                sensor_report = NOINOUT;
                break;
            }
            break;
          case SLEEP_STATE:
            switch(Msg[4]){
              case AWAKE:
                showData();
                sensor_report = SLEEPAWAKE;
                break;
              case LIGHT_SLEEP:
                showData();
                sensor_report = SLEEPLIGHT;
                break;
              case DEEP_SLEEP:
                showData();
                sensor_report = SLEEPDEEP;
                break;
              case SLEEP_NONE:
                showData();
                sensor_report = SLEEPNONE;
                break;
            }
            break;
          case AWAKE_TIME:
            showData();
            sensor_report = AWAKETIME;
            awake_time = Msg[4] &lt;&lt; 8 | Msg[5];   // Time: minutes
            break;
          case LIGHTSLEEP_TIME:
            showData();
            sensor_report = LIGHTTIME;
            light_time = Msg[4] &lt;&lt; 8 | Msg[5];   // Time: minutes
            break;
          case DEEPSLEEP_TIME:
            showData();
            sensor_report = DEEPTIME;
            deep_time = Msg[4] &lt;&lt; 8 | Msg[5];   // Time: minutes
            break;
          case SLEEP_SCORE:
            showData();
            sensor_report = SLEEPSCORE;
            sleep_score = Msg[4];
            break;
          case SLEEP_STATUE:
            showData();
            sensor_report = SLEEPSTATUE;  // 수면 상태를 나타냄
            switch(Msg[4]){
              case SOMEONE_HERE:
                existence = true;
                break;
              case NOONE_HERE:
                existence = false;
                break;
            }
            switch(Msg[5]){
              case DEEP_SLEEP:
                sleep_status = SLEEPDEEP;
                break;
              case LIGHT_SLEEP:
                sleep_status = SLEEPLIGHT;
                break;
              case AWAKE:
                sleep_status = SLEEPAWAKE;
                break;
              case SLEEP_NONE:
                sleep_status = SLEEPNONE;
                break;
            }
            breath_rate = Msg[6];
            heart_rate = Msg[7];
            turn_num = Msg[8];
            substantial_move_ratio = Msg[9];
            samll_move_ratio = Msg[10];
            apnea_num = Msg[11];
            break;
          case SLEEP_QUALITY:
            showData();
            sensor_report = SLEEPQUALITY;
            sleep_score = Msg[4];
            sleep_time = Msg[5] &lt;&lt; 8 | Msg[6];
            awake_time_radio = Msg[7];
            light_time_radio = Msg[8];
            deep_time_radio = Msg[9];
            outbed_time = Msg[10];
            outbed_num = Msg[11];
            turn_num = Msg[12];
            breath_rate = Msg[13];
            heart_rate = Msg[14];
            apnea_num = Msg[15];
            break;
          case SLEEP_ERROR:
            switch(Msg[4]){
              case SLEEP_LESS4H:
                showData();
                sensor_report = SLEEPLESS4H;
                break;
              case SLEEP_OVER12H:
                showData();
                sensor_report = SLEEPOVER12H;
                break;
              case SLEEP_LONGTIMENOONE:
                showData();
                sensor_report = LONGTIMENOONE;
                break;
              case SLEEP_ERRORNONE:
                showData();
                sensor_report = ERRORNONE;
                break;
            }
            break;
        }
        break;
    }
  }
}

/* 아래 함수는 센서로 데이터를 전송하고, 그에 대한 응답을 처리한다.
cyclic 플래그가 설정되었거나 전송 횟수가 기준치(&#39;checkdata_len&#39;)보다 적을때 데이터를 전송한다 
데이터를 전송한 후, recvRadarBytes()를 호출하여 응답을 수신하고 수신된 데이터를 출력한다. */

//Send data frame
void BreathHeart_60GHz::send_func(const unsigned char* buff, int len, bool cyclic /*=false*/){
  if(cyclic || count &lt; checkdata_len){   // 주기적으로 데이터를 전송할지 여부 확인
    if(cyclic || count &lt; 1){
      stream-&gt;write(buff, len);  // 데이터를 전송 
      stream-&gt;flush();  // 버퍼를 비움
    }
    do{
      recvRadarBytes();  // 데이터를 수신
      delay(20);  // 약간의 대기 시간
    }while(!(this-&gt;newData));  // 새로운 데이터가 수신될 때까지 반복
    if(cyclic || count &lt; 1){
      Serial.print(&quot;  Sent  ---&gt; &quot;);  
      data_printf(buff, len);  // 전송한 데이터를 출력
    }
    if(count%2 == 1){
      Serial.print(&quot;Receive &lt;--- &quot;);
      showData();   // 수신한(받은) 데이터를 출력
    } 
    this-&gt;newData = false;  // 새로운 데이터 플래그 초기화
  }
  count++;  // 전송 횟수 증가
}


/* 센서의 전송 모드를 설정한다.
사용자가 입력한 &#39;mode&#39; 값에 따라 센서를 실시간 데이터 전송 모드 또는 수면 상태 전송 모드로 설정 
잘못된 모드가 입력되면 오류 메시지를 출력한다. */


//모드 선택 함수(Transfer mode selection)
void BreathHeart_60GHz::ModeSelect_fuc(int mode){
  if (mode == 1){   // 모드 1 : 실시간 데이터 전송 모드 
    stream-&gt;write(realtime_mode_frame, mode_frame_len);  // 실시간 모드 활성화
    stream-&gt;flush();  // 버퍼를 비움
    Serial.println(&quot;Real-time data transfer mode ON!&quot;);
  }
  else if (mode == 2){   // 모드 2 : 수면 상태 전송 모드 
    stream-&gt;write(sleepstatus_mode_frame, mode_frame_len);  // 수면 상태 모드 활성화
    stream-&gt;flush();  // 버퍼를 비움
    Serial.println(&quot;Sleep state transfer mode ON!&quot;);
  }
  else Serial.println(&quot;Input error, please reselect the mode - 1: indicates real-time transmission mode, 2: indicates sleep state mode.&quot;);
}

//센서 리셋 함수(Reset radar)
void BreathHeart_60GHz::reset_func(){
  stream-&gt;write(breath_reset_frame, reset_frame_len);
  stream-&gt;flush();
  Serial.println(&quot;Radar reset!&quot;);
}

/* 두 개의 바이트를 (2byte = 16bit) 16비트 정수로 결합하고, 이를 부호있는 정수로 변환
부호 비트를 확인하여 음수인지 양수인지를 판단한다.*/

//Two Byte to signed integer
float BreathHeart_60GHz::Byte2Int(unsigned int x, unsigned int y){
  float z = ((x &lt;&lt; 8 | y) &amp; 0x7FFF) / 100.00;
  if (((x &lt;&lt; 8 | y) &amp; 0x8000) == 0x8000)z = -z;
  return z;
}

//print redirect
void BreathHeart_60GHz::data_printf(const unsigned char* buff, int len){
  char charVal[4];
  for(int i=0; i&lt;len; i++){
    sprintf(charVal, &quot;%02X&quot;, buff[i]);
    Serial.print(charVal);
    Serial.print(&#39; &#39;);
  }
  Serial.println();
}

//reset the radar values
void BreathHeart_60GHz::reset_val(){
  sensor_report = 0x00;

  bodysign_val = 0x00;
  distance = 0x00;
  Dir_x = 0x00;
  Dir_y = 0x00;
  Dir_z = 0x00;

  heart_rate = 0x00;
  heart_point_1 = 0x00;
  heart_point_2 = 0x00;
  heart_point_3 = 0x00;
  heart_point_4 = 0x00;
  heart_point_5 = 0x00;
  breath_rate = 0x00;
  breath_point_1 = 0x00;
  breath_point_2 = 0x00;
  breath_point_3 = 0x00;
  breath_point_4 = 0x00;
  breath_point_5 = 0x00;

  awake_time = 0x00;
  light_time = 0x00;
  deep_time = 0x00;
  sleep_score = 0x00;
  sleep_status = 0x00;
  turn_num = 0x00;
  substantial_move_ratio = 0x00;
  samll_move_ratio = 0x00;
  apnea_num = 0x00;
  sleep_time = 0x00;
  awake_time_radio = 0x00;
  light_time_radio = 0x00;
  deep_time_radio = 0x00;
  outbed_time = 0x00;
  outbed_num = 0x00;
}

</code></pre><h4 id="raw-데이터를-읽어오고-어떻게-바뀌는지에-대한-내용">raw 데이터를 읽어오고 어떻게 바뀌는지에 대한 내용</h4>
<ul>
<li>Msg[] 배열은 최대 20 바이트를 읽기 위해 할당 되어있다. </li>
</ul>
<ul>
<li><p>void HumanExis_Func() </p>
<ul>
<li><p>반환 값</p>
<ul>
<li><p>unsigned int sensor_report : 인간의 움직임 정보는 변경이 발생할 때마다 보고 된다. </p>
</li>
<li><p>distance : ( Msg[4] &lt;&lt; 8 | Msg[5] ) / 100.0
&lt;&lt; 비트 시프트 연산으로, Msg[4]의 값을 왼쪽으로 8비트 이동 시킨다. 즉, Msg[4]의 값을 256배 키우는 것과 같아서, Msg[4]의 값이 1이라면, 256 이다. </p>
<ul>
<li>비트 OR 연산(|) 
Msg[4] &lt;&lt; 8 | Msg[5] 는 두 값을 결합한다. 먼저 Msg[4]의 값을 8비트 왼쪽으로 이동시키고, 그 결과에 Msg[5]의 값을 OR 연산하여 두 값을 하나의 정수로 합친다. 이 연산을 통해 Msg[4]와 Msg[5]를 하나의 16비트 정수로 결합하게 된다</li>
<li>나누기(/ 100.0)
결합된 값을 100.0으로 나누어주는데, 이는 결과를 부동 소수점 수로 변환,
이 연산을 통해 거리(distance)를 미터 또는 다른 단위로 변환하는 것으로 보인다. </li>
</ul>
</li>
<li><p>int bodysign_val : 반환된 값은 Human Movement Parameter의 값을 나타내며, 이 값은 1초에 한 번씩 보고된다. </p>
</li>
<li><p>float distance : 센서는 인체와의 현재 거리를 측정하며, 값은 미터 단위이다. 이 값은 2초마다 한 번씩 보고된다.</p>
</li>
<li><p>float Dir_x, Dir_y, Dir_z : 센서가 감지한 신체 위치 정보를 나타내며 위치 정보는 미터 단위로 양수 및 음수 단위가 있다. 이 값은 2초마다 한 번씩 보고된다. </p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li><p>void Breath_Heart()</p>
<ul>
<li><p>반환 값</p>
<ul>
<li><p>unsigned int heart_rate : 심박수 값 3초마다 보고되며, 값 범위는 0~100 이다 </p>
</li>
<li><p>unsigned int heart_point1, heart_point2, heart_point3, heart_point4, heart_point5 : 심박수 파형 데이터. 5바이트는 실시간으로 1초 동안 5개의 값을 나타내며, 파형은 sin파 데이터 이고 중심축은 128이다.
즉, 심박수 강도가 0일때 128로 표시되며, 이 값은 1초에 한 번씩 보고 된다. </p>
</li>
<li><p>unsigned int breath_rate : 호흡 수치, 3초마다 보고되며, 값 범위는 0~20</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[mmWave Sensor 와 ESP8266 D1 연결하기]]></title>
            <link>https://velog.io/@korea_no_1/mmWave-Sensor-%EC%99%80-ESP8266-D1-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@korea_no_1/mmWave-Sensor-%EC%99%80-ESP8266-D1-%EC%97%B0%EA%B2%B0%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 12 Jul 2024 05:40:26 GMT</pubDate>
            <description><![CDATA[<h3 id="환경">환경</h3>
<p>Arduino IDE 2.3.2
Board : ESP8266 - LOLIN(Wemos)D1 R1
<em>Port : Com4(변동 가능)</em>
Upload Speed : 115200</p>
<p>cf. ESP8266 board manager
<a href="http://arduino.esp8266.com/stable/package_esp8266com_index.json">http://arduino.esp8266.com/stable/package_esp8266com_index.json</a></p>
<p>cf. Board - esp32
version : 3.0.2(2024.07.16 기준)</p>
<hr>
<h4 id="용어-정리">용어 정리</h4>
<ul>
<li>UART(Universal asynchronous receiver/treansmitter) : 범용 비동기화 송수신기. 병렬 데이터의 형태를 직렬 방식으로 전환하여 데이터를 전송하는 <strong>컴퓨터 하드웨어</strong>의 일종</li>
</ul>
<hr>
<h3 id="esp8266-d1-r1-pin-map">ESP8266 D1 R1 Pin Map</h3>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/2d2bf4e8-d2c6-4b13-a2b6-a65c0b0428fd/image.png" alt=""></p>
<h4 id="esp-연결-확인">esp 연결 확인</h4>
<p>*<em>File -&gt; Example -&gt; ESP8266 -&gt; Blink *</em>
: Blink를 실행하였을때, ESP8266이 깜빡이면 연결 성공     </p>
<h3 id="mr60bha160ghz-mmwave-sensor---human-static-sleep-breathing-monitoring">MR60BHA1(60GHz mmWave Sensor - Human Static Sleep Breathing Monitoring)</h3>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/63155f6b-5c7a-40b6-bc8a-60687ace59e8/image.png" alt=""></p>
<h4 id="mr60bha1-reference-link">MR60BHA1 Reference Link</h4>
<p><a href="https://wiki.seeedstudio.com/Radar_MR60BHA1/">https://wiki.seeedstudio.com/Radar_MR60BHA1/</a></p>
<h4 id="60ghzbreathhearth-zip-library-link">60ghzbreathheart.h zip library link</h4>
<p><a href="https://github.com/limengdu/Seeed-Studio-MR60BHA1-Sensor">https://github.com/limengdu/Seeed-Studio-MR60BHA1-Sensor</a></p>
<blockquote>
<p>How to bring Library in Github
: In Github page download Zip file -&gt; Arduino Sketch -&gt; Include Library -&gt; Add .Zip Library  </p>
</blockquote>
<h5 id="demo1">Demo1</h5>
<pre><code>#include &quot;Arduino.h&quot;
#include &lt;60ghzbreathheart.h&gt;

//#include &lt;SoftwareSerial.h&gt;
// Choose any two pins that can be used with SoftwareSerial to RX &amp; TX
//#define RX_Pin A2
//#define TX_Pin A3

//SoftwareSerial mySerial = SoftwareSerial(RX_Pin, TX_Pin);

// we&#39;ll be using software serial
//BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;mySerial);

// can also try hardware serial with
BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;Serial1);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial1.begin(115200);

  //  mySerial.begin(115200);

  while(!Serial);   //When the serial port is opened, the program starts to execute.

  Serial.println(&quot;Readly&quot;);
}

void loop()
{
  // put your main code here, to run repeatedly:
  radar.recvRadarBytes();           //Receive radar data and start processing
  radar.showData();                 //Serial port prints a set of received data frames
  delay(200);                       //Add time delay to avoid program jam
}</code></pre><blockquote>
<p>연결 Tip
먼저 ESP8266만 연결한 상태에서 코드 업로드 -&gt; 코드 업로드 이후, mmWave sensor와 연결하기</p>
</blockquote>
<h3 id="c400112m-exarduino-uno">C4001(12M) (ex.Arduino Uno)</h3>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/b57de94c-213c-4b0b-90dc-1fda9e74880b/image.png" alt=""></p>
<h4 id="c40010-interface-definitions">C40010 Interface Definitions</h4>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/0f5eda42-a95b-4543-b4c9-9f792e76da47/image.png" alt=""></p>
<blockquote>
<p>C4001 빨간색 : 5V , 검정색 : GROUND , 파란색 : RX , 초록색 : TX</p>
</blockquote>
<blockquote>
<p>C4001의 경우, Serial로 하지 않고 I2C 방식으로 연결 해야함
esp8266 과 c4001 을 I2C로 연결해서 진행하기</p>
</blockquote>
<pre><code> /*!
  * @file  motionDetection.ino
  * @brief  Example of radar detecting whether an object is moving
  * @copyright Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
  * @license The MIT License (MIT)
  * @author ZhixinLiu(zhixin.liu@dfrobot.com)
  * @version V1.0
  * @date 2024-02-02
  * @url https://github.com/dfrobot/DFRobot_C4001
  */

#include &quot;DFRobot_C4001.h&quot;

// #define I2C_COMMUNICATION  //use I2C for communication, but use the serial port for communication if the line of codes were masked

// #ifdef  I2C_COMMUNICATION
// DEVICE_ADDR_0 = 0x2A     default iic_address
// DEVICE_ADDR_1 = 0x2B

DFRobot_C4001_I2C radar(&amp;Wire ,DEVICE_ADDR_0);  
// #else
/* ---------------------------------------------------------------------------------------------------------------------
 *    board   |             MCU                | Leonardo/Mega2560/M0 |    UNO    | ESP8266 | ESP32 |  microbit  |   m0  |
 *     VCC    |            3.3V/5V             |        VCC           |    VCC    |   VCC   |  VCC  |     X      |  vcc  |
 *     GND    |              GND               |        GND           |    GND    |   GND   |  GND  |     X      |  gnd  |
 *     RX     |              TX                |     Serial1 TX1      |     5     |   5/D6  |  D2   |     X      |  tx1  |
 *     TX     |              RX                |     Serial1 RX1      |     4     |   4/D7  |  D3   |     X      |  rx1  |
 * ----------------------------------------------------------------------------------------------------------------------*/
// /* Baud rate cannot be changed */
//   #if defined(ARDUINO_AVR_UNO) || defined(ESP8266)
// SoftwareSerial mySerial(4, 5);
// DFRobot_C4001_UART radar(&amp;mySerial ,9600);
//   #elif defined(ESP32)
//     DFRobot_C4001_UART radar(&amp;Serial1 ,9600 ,/*rx*/D2 ,/*tx*/D3);
//   #else
//     DFRobot_C4001_UART radar(&amp;Serial1 ,9600);
//   #endif
// #endif

// DFRobot_C4001_UART radar(&amp;Serial ,9600);

void setup()
{

  Serial.begin(9600);
  while(!Serial);
  while(!radar.begin()){
    Serial.println(&quot;NO Deivces !&quot;);
    delay(1000);
  }
  Serial.println(&quot;Device connected!&quot;);

  // exist Mode
  radar.setSensorMode(eExitMode);

  sSensorStatus_t data;
  data = radar.getStatus();
  //  0 stop  1 start
  Serial.print(&quot;work status  = &quot;);
  Serial.println(data.workStatus);

  //  0 is exist   1 speed
  Serial.print(&quot;work mode  = &quot;);
  Serial.println(data.workMode);

  //  0 no init    1 init success
  Serial.print(&quot;init status = &quot;);
  Serial.println(data.initStatus);
  Serial.println();

  /*
   * min Detection range Minimum distance, unit cm, range 0.3~25m (30~2500), not exceeding max, otherwise the function is abnormal.
   * max Detection range Maximum distance, unit cm, range 2.4~25m (240~2500)
   * trig Detection range Maximum distance, unit cm, default trig = max
   */
  if(radar.setDetectionRange(/*min*/30, /*max*/1000, /*trig*/1000)){
    Serial.println(&quot;set detection range successfully!&quot;);
  }
  // set trigger sensitivity 0 - 9
  if(radar.setTrigSensitivity(1)){
    Serial.println(&quot;set trig sensitivity successfully!&quot;);
  }

  // set keep sensitivity 0 - 9
  if(radar.setKeepSensitivity(2)){
    Serial.println(&quot;set keep sensitivity successfully!&quot;);
  }
  /*
   * trig Trigger delay, unit 0.01s, range 0~2s (0~200)
   * keep Maintain the detection timeout, unit 0.5s, range 2~1500 seconds (4~3000)
   */
  if(radar.setDelay(/*trig*/100, /*keep*/4)){
    Serial.println(&quot;set delay successfully!&quot;);
  }


  // get confige params
  Serial.print(&quot;trig sensitivity = &quot;);
  Serial.println(radar.getTrigSensitivity());
  Serial.print(&quot;keep sensitivity = &quot;);
  Serial.println(radar.getKeepSensitivity());

  Serial.print(&quot;min range = &quot;);
  Serial.println(radar.getMinRange());
  Serial.print(&quot;max range = &quot;);
  Serial.println(radar.getMaxRange());
  Serial.print(&quot;trig range = &quot;);
  Serial.println(radar.getTrigRange());

  Serial.print(&quot;keep time = &quot;);
  Serial.println(radar.getKeepTimerout());

  Serial.print(&quot;trig delay = &quot;);
  Serial.println(radar.getTrigDelay());

}

void loop()
{
  // Determine whether the object is moving
  if(radar.motionDetection()){
    Serial.println(&quot;exist motion&quot;);
    Serial.println();
  }
  delay(100);
}</code></pre><blockquote>
<p><strong>해당 코드는 현재 ESP8266 이 연결 되지 않는다고 뜬다.</strong>
I2C 연결법을 빨리 찾아라...(24.07.23 기준..)</p>
</blockquote>
<blockquote>
<p><a href="https://alselectro.wordpress.com/2018/04/16/esp8266-wemos-d1-with-i2c-serial-lcd/">https://alselectro.wordpress.com/2018/04/16/esp8266-wemos-d1-with-i2c-serial-lcd/</a> 
위 사이트 참고해봐라 닝겐..</p>
</blockquote>
<h3 id="sen0557ld2410">SEN0557(LD2410)</h3>
<h4 id="sen0557-board-overview">SEN0557 Board Overview</h4>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/e3ee7244-3765-44bf-99ff-0fad06958446/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/d92415b5-c75b-4e06-9cce-0a4e58dd8247/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/868a74c6-999f-4545-8345-e8969120ef61/image.png" alt=""></p>
<p>*<em>위 사진은 ESP32 와 LD2410 연결에 대해서 
ESP32의 16:TX , 17:RX에 해당 *</em></p>
<pre><code> /* Example sketch for reporting on readings from the LD2410 using whatever settings are currently configured.
 * 
 * The sketch assumes an ESP32 board with the LD2410 connected as Serial1 to pins 8 &amp; 9, the serial configuration for other boards may vary
 * 
 */

#include &lt;ld2410.h&gt;

ld2410 radar;

uint32_t lastReading = 0;

void setup(void)
{
  Serial.begin(115200); //Feedback over Serial Monitor
  radar.debug(Serial);
   //Uncomment to show debug information from the library on the Serial Monitor. By default this does not show sensor reads as they are very frequent.
  Serial1.begin (256000, SERIAL_8N1, 16, 17); //UART for monitoring the radar
  delay(500);
  Serial.println(F(&quot;\nLD2410 radar sensor initialising: &quot;));
  if(radar.begin(Serial1))
  {
    Serial.println(F(&quot;OK&quot;));
  }
  else
  {
    Serial.println(F(&quot;not connected&quot;));
  }
}

void loop()
{
  radar.read();
  if(radar.isConnected() &amp;&amp; millis() - lastReading &gt; 1000)  //Report every 1000ms
  {
    lastReading = millis();
    if(radar.presenceDetected())
    {
      if(radar.stationaryTargetDistance())
      {
        Serial.print(F(&quot;Stationary target: &quot;));
        Serial.print(radar.stationaryTargetDistance());
        Serial.print(F(&quot;cm energy:&quot;));
        Serial.println(radar.stationaryTargetEnergy());
      }
      if(radar.movingTargetDistance())
      {
        Serial.print(F(&quot;Moving target: &quot;));
        Serial.print(radar.movingTargetDistance());
        Serial.print(F(&quot;cm energy:&quot;));
        Serial.println(radar.movingTargetEnergy());
      }
    }
    else
    {
      Serial.println(F(&quot;No target&quot;));
    }
  }
}</code></pre><p>관련 근거 사진은 아래와 같다</p>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/611ca630-462f-4d10-8f79-99ad4a9ccf38/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/1f6a0e6a-c041-4bcd-92d4-3b6c24798c90/image.png" alt=""></p>
<blockquote>
<p>현재는 모든 연결과 upload만 확인 하였으며 추후에 추가적으로 실험 방향에 대해서 작성하겠다.</p>
</blockquote>
<p>ㅡㅡ 2024.07.12 ㅡㅡ</p>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/2ad312fa-7379-408a-81e0-d85e05b37e51/image.png" alt=""></p>
<blockquote>
<p><a href="https://blog.naver.com/compass1111/221073101230">https://blog.naver.com/compass1111/221073101230</a>
ㄴ Serial Monitor esp8266에 띄우는 기본 예제 코드 참고하기</p>
</blockquote>
<p>간단 설명) print와 println의 차이는 줄 바꿈에 있다
printf의 경우, $d 와 \n 같이 서식 지정자를 통해 출력할 데이터의 서식을 지정할 수 있다.</p>
<pre><code>&gt; 예제코드 출력
/* 
  ESP8266 Blink by Simon Peter
  Blink the blue LED on the ESP-01 module
  This example code is in the public domain

  The blue LED on the ESP-01 module is connected to GPIO1
  (which is also the TXD pin; so we cannot use Serial.print() at the same time)

  Note that this sketch uses LED_BUILTIN to find the pin with the internal LED
*/

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);  // Initialize the LED_BUILTIN pin as an output
  Serial.begin(115200);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);  // Turn the LED on (Note that LOW is the voltage level
  Serial.print(1004);
  Serial.print(&quot;welcome&quot;);
  Serial.println(&quot;hello world&quot;);
  Serial.printf(&quot;Everybody! Esp-%d&quot;, 8266);
  Serial.write(1234);

  delay(1000);
  digitalWrite(LED_BUILTIN, LOW);
  delay(1000);
}
</code></pre><h4 id="serial-monitor에서-입력하는-코드">Serial Monitor에서 입력하는 코드</h4>
<pre><code>/*
  ESP8266 Blink by Simon Peter
  Blink the blue LED on the ESP-01 module
  This example code is in the public domain

  The blue LED on the ESP-01 module is connected to GPIO1
  (which is also the TXD pin; so we cannot use Serial.print() at the same time)

  Note that this sketch uses LED_BUILTIN to find the pin with the internal LED
*/

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);  // Initialize the LED_BUILTIN pin as an output
  Serial.begin(115200);
}

// the loop function runs over and over again forever
void loop() 
{
  if(Serial.available()&gt;0)
  {
    char i=Serial.read();
    Serial.printf(&quot;Read data is %c \r\n&quot;, i);
  }
}</code></pre><p>\r 과 \n의 차이</p>
<ul>
<li>정의 </li>
</ul>
<ol>
<li>\r : (캐리지 리턴. CR)커서의 위치를 현재 줄의 맨 앞으로 이동</li>
<li>\n : (라인 피드. LineFeed) 커서를 다음 줄로 이동</li>
</ol>
<ul>
<li>ex. \r<pre><code>sample1 = &quot;       abcd&quot;
sample2 = &quot;     \refgh&quot;
print(sample1)
print(sample2)
</code></pre></li>
</ul>
<p>ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
      abcd
efgh</p>
<pre><code>
- ex. \n</code></pre><p>sample = &quot;abcd\nefgh&quot;
print(sample)</p>
<p>ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
abcd
efgh</p>
<pre><code>&gt; ## 연결 완료 
#### -&gt; 먼저 compile하고 나서 센서 연결해야지 뜸(아래는 연결 코드)

&gt; #### 코드 수정 완료 / Serial1 은 사용 X

&gt; ...___... 이러한 형태로 연결되면 그냥 뺐다가 다시 끼기

#### Demo1 : Raw data export
</code></pre><p>#include &lt;Arduino.h&gt;
#include &lt;60ghzbreathheart.h&gt;</p>
<p>BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;Serial);</p>
<p>void setup() {
  Serial.begin(115200);</p>
<p>  while(!Serial);   //When the serial port is opened, the program starts to execute.</p>
<p>  Serial.println(&quot;Readly&quot;);
}</p>
<p>// the loop function runs over and over again forever
void loop() {
  // put your main code here, to run repeatedly:
  radar.recvRadarBytes();           //Receive radar data and start processing
  radar.showData();                 //Serial port prints a set of received data frames
  delay(200);<br>}</p>
<pre><code>
#### Demo2 : Use of human presence detection function
</code></pre><p>  #include &quot;Arduino.h&quot;
  #include &lt;60ghzbreathheart.h&gt;</p>
<p>  //#include &lt;SoftwareSerial.h&gt;
  // Choose any two pins that can be used with SoftwareSerial to RX &amp; TX
  //#define RX_Pin A2
  //#define TX_Pin A3</p>
<p>  //SoftwareSerial mySerial = SoftwareSerial(RX_Pin, TX_Pin);</p>
<p>  // we&#39;ll be using software serial
  //BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;mySerial);</p>
<p>  // can also try hardware serial with
  BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;Serial);</p>
<p>  void setup() {
    // put your setup code here, to run once:
    Serial.begin(115200);
    //  mySerial.begin(115200);</p>
<pre><code>while(!Serial);   //When the serial port is opened, the program starts to execute.

Serial.println(&quot;Readly&quot;);</code></pre><p>  }</p>
<p>  void loop()
  {
    // put your main code here, to run repeatedly:
    radar.HumanExis_Func();           //Human existence information output
    if(radar.sensor_report != 0x00){
      switch(radar.sensor_report){
        case NOONE:
          Serial.println(&quot;Nobody here.&quot;);
          Serial.println(&quot;----------------------------&quot;);
          break;
        case SOMEONE:
          Serial.println(&quot;Someone is here.&quot;);
          Serial.println(&quot;----------------------------&quot;);
          break;
        case NONEPSE:
          Serial.println(&quot;No human activity messages.&quot;);
          Serial.println(&quot;----------------------------&quot;);
          break;
        case STATION:
          Serial.println(&quot;Someone stop&quot;);
          Serial.println(&quot;----------------------------&quot;);
          break;
        case MOVE:
          Serial.println(&quot;Someone moving&quot;);
          Serial.println(&quot;----------------------------&quot;);
          break;
        case BODYVAL:
          Serial.print(&quot;The parameters of human body signs are: &quot;);
          Serial.println(radar.bodysign_val, DEC);
          Serial.println(&quot;----------------------------&quot;);
          break;
        case DISVAL:
          Serial.print(&quot;The sensor judges the distance to the human body to be: &quot;);
          Serial.print(radar.distance, DEC);
          Serial.println(&quot; m&quot;);
          Serial.println(&quot;----------------------------&quot;);
          break;
        case DIREVAL:
          Serial.print(&quot;The sensor judges the orientation data with the human body as -- x: &quot;);
          Serial.print(radar.Dir_x);
          Serial.print(&quot; m, y: &quot;);
          Serial.print(radar.Dir_y);
          Serial.print(&quot; m, z: &quot;);
          Serial.print(radar.Dir_z);
          Serial.println(&quot; m&quot;);
          Serial.println(&quot;----------------------------&quot;);
          break;
      }
    }
    delay(200);                    //Add time delay to avoid program jam
  }</p>
<pre><code>
#### Demo3 : The use of respiratory and heartbeat functions in the resting people
</code></pre><p>#include &quot;Arduino.h&quot;
#include &lt;60ghzbreathheart.h&gt;</p>
<p>//#include &lt;SoftwareSerial.h&gt;
// Choose any two pins that can be used with SoftwareSerial to RX &amp; TX
//#define RX_Pin A2
//#define TX_Pin A3</p>
<p>//SoftwareSerial mySerial = SoftwareSerial(RX_Pin, TX_Pin);</p>
<p>// we&#39;ll be using software serial
//BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;mySerial);</p>
<p>// can also try hardware serial with
BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;Serial);</p>
<p>void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);</p>
<p>  //  mySerial.begin(115200);</p>
<p>  while(!Serial);   //When the serial port is opened, the program starts to execute.</p>
<p>  Serial.println(&quot;Readly&quot;);</p>
<p>  // radar.ModeSelect_fuc(1);  //1: indicates real-time transmission mode, 2: indicates sleep state mode.
  //After setting the mode, if you do not see data returned, you may need to re-power the sensor.
}</p>
<p>void loop()
{
  // put your main code here, to run repeatedly:
  radar.Breath_Heart();           //Breath and heartbeat information output
  if(radar.sensor_report != 0x00){
    switch(radar.sensor_report){
      case HEARTRATEVAL:
        Serial.print(&quot;Sensor monitored the current heart rate value is: &quot;);
        Serial.println(radar.heart_rate, DEC);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case HEARTRATEWAVE:  //Valid only when real-time data transfer mode is on
        Serial.print(&quot;The heart rate waveform(Sine wave) -- point 1: &quot;);
        Serial.print(radar.heart_point_1);
        Serial.print(&quot;, point 2 : &quot;);
        Serial.print(radar.heart_point_2);
        Serial.print(&quot;, point 3 : &quot;);
        Serial.print(radar.heart_point_3);
        Serial.print(&quot;, point 4 : &quot;);
        Serial.print(radar.heart_point_4);
        Serial.print(&quot;, point 5 : &quot;);
        Serial.println(radar.heart_point_5);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case BREATHNOR:
        Serial.println(&quot;Sensor detects current breath rate is normal.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case BREATHRAPID:
        Serial.println(&quot;Sensor detects current breath rate is too fast.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case BREATHSLOW:
        Serial.println(&quot;Sensor detects current breath rate is too slow.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case BREATHNONE:
        Serial.println(&quot;There is no breathing information yet, please wait...&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case BREATHVAL:
        Serial.print(&quot;Sensor monitored the current breath rate value is: &quot;);
        Serial.println(radar.breath_rate, DEC);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case BREATHWAVE:  //Valid only when real-time data transfer mode is on
        Serial.print(&quot;The breath rate waveform(Sine wave) -- point 1: &quot;);
        Serial.print(radar.breath_point_1);
        Serial.print(&quot;, point 2 : &quot;);
        Serial.print(radar.breath_point_2);
        Serial.print(&quot;, point 3 : &quot;);
        Serial.print(radar.breath_point_3);
        Serial.print(&quot;, point 4 : &quot;);
        Serial.print(radar.breath_point_4);
        Serial.print(&quot;, point 5 : &quot;);
        Serial.println(radar.breath_point_5);
        Serial.println(&quot;----------------------------&quot;);
        break;
    }
  }
  delay(200);                       //Add time delay to avoid program jam
}</p>
<pre><code>
#### Demo4 : Use of the sleep function
</code></pre><p>#include &quot;Arduino.h&quot;
#include &lt;60ghzbreathheart.h&gt;</p>
<p>//#include &lt;SoftwareSerial.h&gt;
// Choose any two pins that can be used with SoftwareSerial to RX &amp; TX
//#define RX_Pin A2
//#define TX_Pin A3</p>
<p>//SoftwareSerial mySerial = SoftwareSerial(RX_Pin, TX_Pin);</p>
<p>// we&#39;ll be using software serial
//BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;mySerial);</p>
<p>// can also try hardware serial with
BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;Serial1);</p>
<p>void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  // Serial1.begin(115200);</p>
<p>  //  mySerial.begin(115200);</p>
<p>  while(!Serial);   //When the serial port is opened, the program starts to execute.</p>
<p>  Serial.println(&quot;Readly&quot;);
}</p>
<p>void loop()
{
  // put your main code here, to run repeatedly:
  radar.SleepInf_Decode();           //Sleep-related information output. Data output begins when the monitoring figure is in bed for five minutes.
  if(radar.sensor_report != 0x00){
    switch(radar.sensor_report){
      case OUTBED:
        Serial.println(&quot;Sensor detects someone currently leaving the bed.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case INBED:
        Serial.println(&quot;Sensor detects that someone is currently in bed.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case NOINOUT:
        Serial.println(&quot;No subject is detected leaving or going to bed.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPAWAKE:
        Serial.println(&quot;Sensor detects that the monitoring people is awake.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPLIGHT:
        Serial.println(&quot;Sensor detects that the monitoring people is in light sleeping.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPDEEP:
        Serial.println(&quot;Sensor detects that the monitoring people is in deep sleeping.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPNONE:
        Serial.println(&quot;Sleep state of the object is not detected.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case AWAKETIME:
        Serial.print(&quot;Sensor monitored the awake sleep time is: &quot;);
        Serial.print(radar.awake_time);
        Serial.println(&quot; min&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case LIGHTTIME:
        Serial.print(&quot;Sensor monitored the light sleep time is: &quot;);
        Serial.print(radar.light_time);
        Serial.println(&quot; min&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case DEEPTIME:
        Serial.print(&quot;Sensor monitored the deep sleep time is: &quot;);
        Serial.print(radar.deep_time);
        Serial.println(&quot; min&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPSCORE:
        Serial.print(&quot;Sensor judgment sleep score is: &quot;);
        Serial.println(radar.sleep_score);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPSTATUE:
        Serial.println(&quot;Sleep integrated state information -- &quot;);
        Serial.print(&quot;Human existence: &quot;);
        if(radar.existence)Serial.println(&quot;human exis&quot;);
        else Serial.println(&quot;human non-existent&quot;);
        Serial.print(&quot;Sleep state: &quot;);
        if(radar.sleep_status == SLEEPDEEP)Serial.println(&quot;sleeping soundly&quot;);
        else if(radar.sleep_status == SLEEPLIGHT)Serial.println(&quot;light sleep&quot;);
        else if(radar.sleep_status == SLEEPAWAKE)Serial.println(&quot;awake&quot;);
        else if(radar.sleep_status == SLEEPNONE)Serial.println(&quot;off the bed&quot;);
        Serial.print(&quot;Average breathing: &quot;);
        Serial.println(radar.breath_rate);
        Serial.print(&quot;Average heart rate: &quot;);
        Serial.println(radar.heart_rate);
        Serial.print(&quot;Number of turning over during sleep: &quot;);
        Serial.println(radar.turn_num);
        Serial.print(&quot;Percentage of substantial exercise during sleep: &quot;);
        Serial.println(radar.substantial_move_ratio);
        Serial.print(&quot;Percentage of small-amplitude movements during sleep: &quot;);
        Serial.println(radar.samll_move_ratio);
        Serial.print(&quot;Number of apnea: &quot;);
        Serial.println(radar.apnea_num);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPQUALITY:
        Serial.println(&quot;Quality of sleep information -- &quot;);
        Serial.print(&quot;Sleep score: &quot;);
        Serial.println(radar.sleep_score);
        Serial.print(&quot;Total time of sleep: &quot;);
        Serial.print(radar.sleep_time);
        Serial.println(&quot; min&quot;);
        Serial.print(&quot;Percentage of waking time: &quot;);
        Serial.println(radar.awake_time_radio);
        Serial.print(&quot;Percentage of light sleep time: &quot;);
        Serial.println(radar.light_time_radio);
        Serial.print(&quot;Percentage of deep sleep time: &quot;);
        Serial.println(radar.deep_time_radio);
        Serial.print(&quot;Total time away from bed: &quot;);
        Serial.print(radar.outbed_time);
        Serial.println(&quot; min&quot;);
        Serial.print(&quot;Total number of times out of bed: &quot;);
        Serial.println(radar.outbed_num);
        Serial.print(&quot;The number of turning over during sleep: &quot;);
        Serial.println(radar.turn_num);
        Serial.print(&quot;Average breathing: &quot;);
        Serial.println(radar.breath_rate);
        Serial.print(&quot;Average heart rate: &quot;);
        Serial.println(radar.heart_rate);
        Serial.print(&quot;Number of apnea: &quot;);
        Serial.println(radar.apnea_num);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPLESS4H:
        Serial.print(&quot;The monitored subjects slept for less than 4 hours.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case SLEEPOVER12H:
        Serial.print(&quot;The length of sleep of the monitored subjects exceeded 12 hours.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case LONGTIMENOONE:
        Serial.print(&quot;Abnormally unoccupied for long periods of time.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
      case ERRORNONE:
        Serial.print(&quot;No abnormal information.&quot;);
        Serial.println(&quot;----------------------------&quot;);
        break;
    }
  }
  delay(200);                       //Add time delay to avoid program jam
}</p>
<pre><code>
#### Demo5 Send data to Sensor
</code></pre><p>#include &quot;Arduino.h&quot;
#include &lt;60ghzbreathheart.h&gt;</p>
<p>//#include &lt;SoftwareSerial.h&gt;
// Choose any two pins that can be used with SoftwareSerial to RX &amp; TX
//#define RX_Pin A2
//#define TX_Pin A3</p>
<p>//SoftwareSerial mySerial = SoftwareSerial(RX_Pin, TX_Pin);</p>
<p>// we&#39;ll be using software serial
//BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;mySerial);</p>
<p>// can also try hardware serial with
BreathHeart_60GHz radar = BreathHeart_60GHz(&amp;Serial1);</p>
<p>const unsigned char DevID_buff[10] = {0x53, 0x59, 0x02, 0xA1, 0x00, 0x01, 0x0F, 0x5F, 0x54, 0x43};</p>
<p>void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  // Serial1.begin(115200);</p>
<p>  //  mySerial.begin(115200);</p>
<p>  while(!Serial);   //When the serial port is opened, the program starts to execute.</p>
<p>  Serial.println(&quot;Readly&quot;);
}</p>
<p>void loop()
{
  // put your main code here, to run repeatedly:
  radar.send_func(DevID_buff, 10, false);
  delay(50);                       //Do not set the delay time too long, as this may affect the reception of the data frames returned by the radar.
}
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[첫 인사글]]></title>
            <link>https://velog.io/@korea_no_1/firstgreeting</link>
            <guid>https://velog.io/@korea_no_1/firstgreeting</guid>
            <pubDate>Mon, 04 Sep 2023 08:12:48 GMT</pubDate>
            <description><![CDATA[<hr>
<p>Mark Zuckerberg, Elon Musk, Bill Gates 등등
세계 각국의 유명 IT 기업인들이 있다면</p>
<p>한국에는 korea_no_1이 있다</p>
<p>대학 동기인 <a href="https://velog.io/@nomercyboy">희령</a>과 함께 앞으로 세계를 제패할 예정이다.</p>
<blockquote>
<p>&quot;비록 시작이 미비할지라도 그 끝은 창대할 것이니라&quot;</p>
</blockquote>
<p>지금은 학교 도서관에서 노트북을 두들기고 있지만</p>
<p>먼 훗날 우리는 이 날을 안주로 삼으며 높은 빌딩에서 이야기를 나누겠지</p>
<p>후훗</p>
<p>앞으로의 이야기를 기대하라구</p>
<p><img src="https://velog.velcdn.com/images/korea_no_1/post/a94b32c1-0eec-4691-a02f-213a9edd75fa/image.png" alt=""></p>
]]></description>
        </item>
    </channel>
</rss>