<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>popcorn_kim93.log</title>
        <link>https://velog.io/</link>
        <description>개발하다가 나온 여러가지 고민과 그에 대한 해결책들을 간결하지않고 일기처럼 끄적여봅니다.</description>
        <lastBuildDate>Sun, 23 Oct 2022 06:05:25 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>popcorn_kim93.log</title>
            <url>https://images.velog.io/images/popcorn_kim93/profile/d697fb74-a928-428c-a686-ea63de7ab269/CircleLogo_png.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. popcorn_kim93.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/popcorn_kim93" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Ubuntu 에 Code-server 설치]]></title>
            <link>https://velog.io/@popcorn_kim93/Ubuntu-%EC%97%90-Code-server-%EC%84%A4%EC%B9%98</link>
            <guid>https://velog.io/@popcorn_kim93/Ubuntu-%EC%97%90-Code-server-%EC%84%A4%EC%B9%98</guid>
            <pubDate>Sun, 23 Oct 2022 06:05:25 GMT</pubDate>
            <description><![CDATA[<p>이제 Ubuntu 에 Code-server 를 깔아볼건데... 사실 까는방법은 ubuntu codeserver 라고만 검색해봐도 수두룩하게 나온다...
하지만 우리는 그 수많은 방법중에서도 특히나 너무나도 쉬운 방법을 사용할건데</p>
<p>ubuntu 를 열어서 아래 명령어 하나만 친다.</p>
<p><code>apt install code-server</code></p>
<p>그럼 설치됨.</p>
<p>다 깔리게 되면</p>
<p><code>code-server</code>를 치면 code server 가 실행된다.</p>
<p><img src="https://velog.velcdn.com/images/popcorn_kim93/post/bd20d29e-0ee5-4dc4-8088-6ce062fc0347/image.png" alt=""></p>
<p>혹시 저번 포스팅에서 접속 테스트를 하는 순서를 기억하는가?
내가 명확하게 순서를 정리하지는 않았지만 글 전체적으로 봤을때 크게 아래와 같은 순서이다.</p>
<ol>
<li>localhost 접속 테스트</li>
<li>내부망 접속 테스트</li>
<li>외부망 접속 테스트</li>
</ol>
<p>당연하게도 1번이 되야 2번이 되고, 2번이 되야 3번이 된다.
그러니 1번 테스트인 localhost 부터 테스트해보자.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/popcorn_kim93/post/94b6d46c-189f-4db4-a01e-dcac4acf9401/image.png" alt=""></p>
<p>위 사진같이 떴다면
<code>HTTP server listening on http://0.0.0.0:port/</code>
라고 되어있는 텍스트가 보이는데 0.0.0.0 뒤에있는 포트번호를 기억하고 인터넷 창을 열어
<code>localhost:port</code> 를 주소창에 쳐보자.
혹시 접속이 되는가...? 지금 같은 환경을 해보면서 할수가 없는상황이라 재현을 못해보고 작성하고있는데... 생각해보니 될수도있고 안될수도 있을것같다.</p>
<p>저번 포스팅에서 작업스케쥴러로 만든 스크립트의 내용 중 <code>@port=</code> 를 적는 부분이 있는데 이 부분에도 위 포트를 추가 한 다음 스크립트를 다시 실행해야한다.
그리고 localhost 는 정말 자신의 ip로 가는거기때문에... 아마 안될수도 있겠다...
코드서버는 우리가 실행한 컴퓨터에서 실행된거긴 하지만 네트워크 위치가 우리가 실행한 컴퓨터가 아니라 <strong>그 컴퓨터 안에있는 wsl2</strong>이다. 그러니... 테스트를 해보려면 해당 컴퓨터가 공유기에 할당된 <strong>사설ip</strong>를 입력하고 그 뒤에 포트를 붙이면 접속이 될것같다.</p>
<p>자 그럼 포트도 바꾸고싶고 접속이 된다면 비밀번호를 묻는 창이 나올수도있을것이다. 비밀번호를 설정할 수도 있는데 그러한 설정값들은 어디서 설정을 하느냐...</p>
<p>위 로그를 살펴보면
<code>Using config file ~/.config/code-server/config.yaml</code>
이라는 로그가 있다. code server 를 띄울때 전체적인 설정값들을 이 문서에서 읽어와 설정한다는 의미이다. 그럼 이 문서를 열어보면 뭔가 설정할 수 있는게 있는지 확인해보겠다.</p>
<p>우선 저번 포스팅에서 vim을 설치한 바가 있다.
<code>vim ~/.config/code-server/config.yaml</code>
를 치면 아래와 같은 문서가 나온다.
<img src="https://velog.velcdn.com/images/popcorn_kim93/post/4cc4c98d-2d88-451e-955f-ba73809a72a1/image.png" alt="">
<code>bind-addr:</code> 은 접속주소 및 뒤에는 port 번호가 있다. 127.0.0.1로 하면 localhost 만 되며 0.0.0.0를 하면 외부접속 혹은 이 컴퓨터의 ip로 접속 가능하다. 뒤에 포트는 다른 포트와 충돌되지 않는 선에서 바꿔주거나 그대로두면된다.
<code>auth:</code> 인증방식인데 password 밖에 모른다. 뭐... 다른방식도 있는것같던데 불안하면 설정방법 찾아보길바란다.
<code>password:</code> 설정할 비밀번호다. 접속하면 password 를 묻는 창이 나오는데 그때 여기에 적은 문자를 쓰면 된다.
<code>cert:</code> 이거는 https로 접속하게 할것인지를 묻는건데... false 로 하면 http로 접속된다.
만약 https 로 붙고싶다면 인증서 경로를 적어주면 된다. 인증받은 인증서를 내보내기하면 cert.pem, privkey.pem 파일이 있을텐데 그 파일을 적당한 위치에 옮겨두고</p>
<pre><code>cert: /경로오오오오.../cert.pem
cert-key: /경로오오오오.../privkey.pem</code></pre><p>이렇게 두줄을 입력해주면 된다.</p>
<p>다 수정했으면 insert 모드에서 빠져나와 <code>:wq</code>를 입력하여 저장하고 나온다.</p>
<p>그리고나서 다시 <code>code-server</code>를 입력하면 새로 설정된 설정값으로 실행된다.</p>
<p>그럼 이제 거의 끝이다. 이제 스스로 접속테스트만 해보는 일만 남았다.
예를들어 외부ip <strong>123.123.123.1</strong>이고, 사설ip <strong>192.168.0.40</strong> 컴퓨터에서 code server 포트를 <strong>9990</strong>으로 한다면</p>
<ol>
<li>code server 의 포트 변경</li>
<li>code server 의 포트 wsl2 포트포워딩 스크립트에 추가</li>
<li>포트 포워딩 스크립트 실행</li>
<li>공유기 포트포워딩 설정</li>
<li>내부 ip 로 접속 테스트 (192.168.0.40:9990)</li>
<li>외부 ip 로 접속 테스트 (123.123.123.1:9990)</li>
</ol>
<p>이 정도가 끝일것같다.</p>
<hr>
<p>나같은 경우에는 갤탭으로 코딩을 하려고 했는데 간단한건 가능했지만 터치로는 블럭지정이나 복사 붙여넣기... 같은게 키보드를 연결하지 않으면 불가능해서 터치만으로는 코딩하기가 좀 불편했으나, 키보드 마우스를 블루투스로 연결하면 pc와 거의 흡사한 환경으로 개발이 가능했었다.
개인적으로 지하철타고 이동하는 시간이 좀 길어서 너무 아까웠는데 이걸로 개인적으로 개발하고싶은게 있어서 개발을 좀 했더니 요즘엔 그 시간이 참 빠르게 가는것같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[자동매매봇 패치...]]></title>
            <link>https://velog.io/@popcorn_kim93/%EC%9E%90%EB%8F%99%EB%A7%A4%EB%A7%A4%EB%B4%87-%ED%8C%A8%EC%B9%98</link>
            <guid>https://velog.io/@popcorn_kim93/%EC%9E%90%EB%8F%99%EB%A7%A4%EB%A7%A4%EB%B4%87-%ED%8C%A8%EC%B9%98</guid>
            <pubDate>Tue, 04 Oct 2022 17:10:49 GMT</pubDate>
            <description><![CDATA[<p>요즘 근황이다.
최근 여기 남긴것처럼 수해를 당했으나 이제 어느정도 복구가 되어 일상으로 돌아왔다.</p>
<p>그전까지 내 놀고있는 노트북 한대를 이용해 코드서버를 만들고 그 코드서버에 빗썸에서 자동매매를 할수있는 봇을 만들고 있었다. 하지만 나스가 침수되어 물거품이 되는듯 했으나 나스는 퍼포스 서버로 버전관리만 하는거였고 복제된 코드들은 다행히도 노트북에 갖고있었기때문에 어느정도 다행이라 생각했으나 더 다행인건 나스가 침수되었어도 살아있었다는 사실이었다.</p>
<p>내가 침수된 상황을 본거는 아니었어서 나스에 어느정도까지 물이 찼는지는 모르겠으나 확실한건 아래쪽엔 흙탕물이 쌓여있는듯한 흔적이 있었고 그쪽엔 하드디스크의 접지부가 있었기때문에 망했다고 생각했다. 1주일 완전건조를 하고 전원 어댑터는 완전 침수되었어도 말렸으나 1주일이 지났는데도 계속 흔들면 물이 나오는 상황이었어서 새로 사는걸 결정했고 새로 산 어댑터를 1주일 말린 나스에 연결하니 다행히도 작동이 되었다.</p>
<p>하지만 내 나스는 2bay 였는데, 한... 3주인가 4주정도 지나니까 갑자기 한 하드디스크에 불량섹터가 급증하더니...
사망했다.
다행히도 사망하기전에 다른하드로 백업을 해서 살려놓긴 했으나 어느파일이 깨졌는지는 파악이 안된다... 뭐 여튼...</p>
<p>다시 회사를 다니며 짬짬히 코인봇을 열심히 만들었는데 <strong>역시 태블릿으로 코드서버가 되니 무료했던 이동시간이 매우 유익해졌고 그 시간이 짧은 시간은 아니니 개발속도도 빨랐던것같다.</strong></p>
<h2 id="현재-코인봇의-구현기능들은">현재 코인봇의 구현기능들은</h2>
<ul>
<li>자동 매매, 매수</li>
<li>최초 투자금보다 많은 돈이 이익이 발생하면 그 돈을 킵해두는 기능</li>
<li>현재 알고리즘으로 1분,3분,5분 등 원하는 시간대로 쌓여있는 데이터를 받아와 빠르게 백테스팅</li>
<li>현재 알고리즘으로 실전과 같이 테스트(실제돈은 안들어감)</li>
<li>각종 이벤트때 텔레그램으로 알림</li>
</ul>
<p>음... 생각나는건 이정도...?</p>
<hr>
<p>그런데 시퀀스가... <del>매우 많이 프로토같다...</del></p>
<p>일단 시작하려면 <strong>무조건 main.py 파일을 컴퓨터에서 실행해야하며, 어떤 일을 할지는 번호로 입력, 입력된 수행이 끝나면 그냥 강종되고 다시 실행되지 않는다.</strong> 뭐 그건 별로 큰일은 아닌것같고... 사용자만 불편하지 않으면 되니까... <del>사용자는 나니까</del>
텔레그램에게 알림이 가는 일은 뭐 그렇다치고... 봇이 돌다가 특정 이벤트(매수, 매매등)가 발생하면 로그를 찍도록 했는데 그때 필요한 정보들을 출력했다. 이렇다보니 지금 당장 어떤 정보를 얻고싶은데 해당 이벤트가 실행되기 전까지는 절대 알 수 없고, 또한 런타임 중에 어떤 변수를 수정해야 할때도 마이너한거를 수정한다거나, 상황마다 변수를 바꾸면서 테스트를 해봐야 할때도 매번 코드 수정하고 봇을 강종했다가 다시 실행하고 를 반복해야했는데, 그렇게 되면 현재까지 매수했던 코인들과 기록들이 전부 없어진다. 한마디로 전체적으로 <strong>라디오같은 매우 수동적인 의사소통 관계</strong>가 됐으며 뭔가 내가 요구하고싶은데 그 요구를 들어줄 수 있는 방안이 없었다.</p>
<p>물론 저런 기록들은 파일로 저장을 해놓은 다음 그걸 읽어와서 다시 한다던가... 음? 이것도 좋아보이는데 이것도 한번 생각해보고...</p>
<p>그러다가 갑자기 텔레그램 봇이 <strong>자동답장</strong>도 할 수 있으니까 그 기능을 이용해 내가 원하는 정보를 텔레그램으로 물어보면 그 정보를 알려주게 하자는 아이디어가 떠올라서 실행에 옮겼다.</p>
<p>일단 답장을 하려면 <code>updator</code>객체를 만들어 <code>updator.start_polling()</code>을 해야했다.
근데 문제는 이게 한 봇에 한해 한번만 풀링이 가능하다는 것이다.</p>
<p>이게 왜 문제냐면...</p>
<p>나는 봇을 여러개를 돌리고 있었다. 예를들어 <code>main.py</code>를 한개 실행하고 한번 실행할 때 타겟으로 할 <strong>ticker</strong>를 결정할 수 있게 했는데 만약 두개, 혹은 세개의 코인이 좀 눈에 들어와서 자동봇을 돌려놓고싶다면 <code>main.py</code>를 <strong>여러개 실행하여 ticker가 여러개 돌릴 수 있게 했다.</strong> 여러개의 인스턴스가 생기는것이다. 하지만 telegram의 polling 은 <strong>한 봇에 한 인스턴스만 polling이 가능하다...</strong> 그래서 여러개의 ticker를 돌리고 싶을때는 한개의 인스턴스에서 해야할 필요가 있어서 고민을 좀 했다.</p>
<p>일단 여러개의 <code>main.py</code>를 돌려야했던 이유는 매 초마다 현재의 가격을 bithum에서 가져와 그 가격을 가지고 계산하고 그 다음 <code>time.sleep(1)</code>을 이용해 1초 기다린 후 영원히 반복하는 <code>while</code>문을 사용했기 때문이다. 하지만 여러개의 ticker를 지정하고 싶을때는 이 모든기능을 <strong>메인스레드에서 도는게 아니라 멀티스레드로 처리할 필요가 있었다.</strong></p>
<p>스레드는... 텔레그램 봇을 만들때 잠깐 쓰레드로 처리할 필요가 있어서 잠깐 바꾼적이 있었는데, 그걸 참고해서 어렵지않게 모든기능을 쓰레드로 바꿨고 이제 어떤 ticker 를 대상으로 할지만 기다리고 한번 입력하면 thread 로 봇 로직을 타게 던진다음 다시 어떤 ticker 로 봇을 돌릴건지 기다리게 수정했다.</p>
<p>자, 일단 이건 이렇게 됐는데... <strong>문제는 또 있다...</strong> 만약 ticker 가 여러개 생겼는데 봇에게 현재정보를 출력하거나 봇에게 어떤일을 지시할 때 <strong>어떤 ticker 에게 지시할지 모호한 상황이 되었다.</strong>
ticker 로 하게 된다면 그것도 문제가 생긴다. 만약 로직이 변경되어서 다시 <code>main.py</code>를 실행해야 할 일이 생긴다면 현재 돌고있는 봇은 지금부터 매수를 금지하고 매도모드에만 들어가게 한 후 그것이 다 끝날때까지는 봇이 살이있다가 다 끝난다면 자연스럽게 종료되어야한다. 종료될때까지 기다렸다가 새 <code>main.py</code>를 실행하기엔 시간이 너무 아깝기때문에 그냥 매도모드로 변경한 후 바로 새 <code>main.py</code>를 실행해야하는데 같은 ticker 를 사용했을때는 명령어를 내릴때 어떤 ticker 로 명령이 내려질지도 모호해진다. 한마디로 ticker 는 유일한 객체로 보장하기엔 좀 아쉬운 변수라는 뜻이다. 그래서 <strong>봇이 만들어질때 unique id 를 할당했고 그 unique id를 텔레그램에서 쓰고 명령어를 쓰면 그에대한 일을 수행하도록 했다.</strong></p>
<p>사실 위 문제는 두개의 인스턴스에서 polling이 안되기 때문에 저렇게 하기위해선 먼저 끝내려는 봇의 <code>main.py</code>를 죽여야만 새 인스턴스에서도 정상적으로 polling 이 가능하기때문에 어쩌피 종료해야한다. 하지만 종료하지않아도 <code>update.stop()</code>을 호출하면 그 인스턴스에서는 polling 이 멈추고 새 인스턴스에서 polling이 가능해진다. 그래서 이전 인스턴스에서는 polling을 그만두고 새 인스턴스에서만 polling 이 가능하도록 수정했다.</p>
<p>이제 어느정도 텔레그램으로 원하는정보를 출력하게 보내면 봇이 <del>내가 미리 설정한거지만</del> 내가 한 말에 알맞은 답장을 하게했다. 하지만 또 고민이 있는데... <strong>명령어를 내가 다 알고있지 않아서 생각이 안날땐 코드를 매번 봐야한다는 것이다...</strong>
그래서 <code>help</code>같은게 필요한데... 문제는 이걸 하드하게 해버리면 <code>help</code>를 출력하는곳에도 명령어를 추가해야하고 실제 명령어를 실행하는 곳에도 명령어를 추가해야한다. 명령어를 실행하는 곳에는 전부 <code>if ~ elif</code>로 되어있기때문에 하나하나 다 가서 추가해야하고 <code>help</code>를 출력하는것도 그 목록만 출력해야하기때문에 <strong><code>if ~ elif</code>로 입력한 모든걸 다 <code>help</code>출력함수에다가 추가해야하는것이다.</strong></p>
<p><strong>나는 개인적으로 개발하면 뭔가 하나를 추가할때 여기도 수정하고 저기도 수정하는걸 매우 싫어한다. 그렇게 되면 유지보수가 나중에는 개같아지기때문이다.</strong>
나는 이 상황을 절대로 참을 수 없었기 때문에 머리를 굴려봤는데 바로 명령어를 <code>enum</code>으로 만드는 것이다. 혹은... <strong>명령어</strong>로 된 배열을 하나 생성하는것도 좋은방법일것같다.
음... 이 글을 쓰기 전까지는 <code>enum</code>으로 만들어야지~ 했는데 가만 생각해보니 그냥 배열만드는게 더 간단해 보이는데...? 그냥 그렇게 해야겠다.</p>
<p>자... 그 다음 해야할게... 매도모드는 추가해놨고, <strong>매도모드로 이제 거의 다 팔았을 때 스스로 종료하는 시퀀스</strong>까지도 추가해야한다. 이건 어떻게 해야하는지 아직 아이디어가 없어서 아이디어 생기면 작업하면 될것같고...</p>
<p>그리고 또 아까 텔레그램의 <code>updator.start_polling()</code> 이라는 함수 호출이 어떤 함수 안에서 호출하는게 아니라 <strong>걍 전역에서 호출</strong>하고있기때문에 <strong>매매봇만 실행해도 텔레그램 봇도 같이 polling 이 돌아버려서</strong> 텔레그램 봇 필요없는데도 <strong>너 polling 두번했는데 그라면안돼~</strong> 하면서 난리를 친다. <del>이미 하나는 돌고있는 상태에서 테스트를 하기때문에...</del> 그래서 이것도 정말 봇이 필요할때만 polling 관련 함수가 돌 수 있도록 수정해야한다. 일단 polling 함수가 있는 코드는 따로 함수화를 시켜놨는데 이걸 언제 호출하게할지가 고민이다. <code>main.py</code>에서 봇이 필요할때만 이 polling 함수를 호출하게 할지... 근데 그렇게 되면 이걸 해야하는곳에 전부 다 가서 하나하나 추가해줘야한다. <del>또 참을 수 없는 뭔가가 올라오는데...</del> 하지만 매매봇이 하나 돌때마다 이걸 맨날 <code>start polling</code>을 한다면 음... 그것도 또 문제다. 한번만 호출하면 되는데 왜 굳이 또 할 필요가 있나... 이미 활성화 됐는지 체크하면 되긴하는데 그 체크하는 작업 마저도... 불필요한데 말이다. 그래서 그건 사알짝 고민중~</p>
<p>또한 전부 텍스트로만 알려주다보니 실제로 어느 시점에 팔고, 어느 시점에 샀는지, 혹은 지금 추세는 어떤지를 파악하기 어려운데 <code>numpy</code> 를 이용해 그래프를 생성할 수 있길래 그걸 이미지 파일로 만든 후 텔레그램으로 전송하게 하는것도 생각중이다.</p>
<p>어찌하다보니 개발로그가 됐는데
음... 이것도 나쁘지 않은것같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[20220808 물난리]]></title>
            <link>https://velog.io/@popcorn_kim93/20220808-%EB%AC%BC%EB%82%9C%EB%A6%AC</link>
            <guid>https://velog.io/@popcorn_kim93/20220808-%EB%AC%BC%EB%82%9C%EB%A6%AC</guid>
            <pubDate>Tue, 09 Aug 2022 02:58:00 GMT</pubDate>
            <description><![CDATA[<p>폭우로 인해 집에 홍수가 났다.
나는 회사에 있었고... 집에 물이찬다는 연락을 받고 집에 부랴부랴 달려왔는데 달려오는 도중 원격으로 접속해보니... 접속이 안된다...
35분전 오프라인...
최소 전원이 나간걸로 보이는데...
택시를 타고 가면서도 곳곳에 도로가 침수되어 멈춘 차량이 많이 보였고 인도도 엉망이었다...
점점 더 불안해진다...</p>
<p>집에 들어와보니 다행히도 물은 이미 빠졌었지만 물이 올라온 자국을 보니... 집에 물이 4분의 1 가량 찼었다는 자국이 있었다.</p>
<p>바닥에는 노트북 충전기, 공유기, 공유기 전원, 나스전원, 나스, 그걸 연결해놓은 멀티탭까지... 모두 바닥에 깔려있었기 때문에
모두...
죽었다...</p>
<p>몇가지 문제가 있고 이를 어떻게 해결해야할지 고민중이다.</p>
<ol>
<li>synology 220+가 침수됐다. 그 안에있는 두개의 4TB 하드도 침수됐다. 살릴수있을까...</li>
<li>노트북은 괜찮으나 노트북 충전기가 전부 침수되었다.</li>
</ol>
<p>젖은 옷이고 물건이고 이런건 다시 사면되지만
잃어버린 데이터는 다시 살 수가 없다.
또한 코드서버를 구축해 놓은 것도 그렇고... 여러가지 nas 설정도 전부... 날라갔다...
개인 nas는 자신만의 클라우드 서버를 만들 수 있는 크나큰 장점이 있다.
하지만 내가 그 데이터를 관리해야하기 때문에 천재지변이 일어나면 데이터를 모두 잃어버릴 수 있다.
근데... 에이... 천재지변이 일어나겠어..? 했는데...</p>
<p>일어났네...? ㅎ...</p>
<p>나스를 바닥에 깔아놓은게 잘못이지...</p>
<p>구글드라이브 같은 클라우드 서비스 쓰시는 분 중에 nas 를 할 줄 몰라서 안쓰기 보다 구글이라는 대기업이 자기 데이터를 관리해 주기때문에 안전해서 쓰는사람도 있다더라..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[WSL2에 ssh 서버와 외부연결 환경 구축]]></title>
            <link>https://velog.io/@popcorn_kim93/WSL2%EC%97%90-ssh-%EC%84%9C%EB%B2%84%EC%99%80-%EC%99%B8%EB%B6%80%EC%97%B0%EA%B2%B0-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95</link>
            <guid>https://velog.io/@popcorn_kim93/WSL2%EC%97%90-ssh-%EC%84%9C%EB%B2%84%EC%99%80-%EC%99%B8%EB%B6%80%EC%97%B0%EA%B2%B0-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95</guid>
            <pubDate>Sun, 07 Aug 2022 17:45:32 GMT</pubDate>
            <description><![CDATA[<p>저번까지 WSL2를 적용하고 Ubuntu 를 설치하는것까지 해보았다.</p>
<p>이번엔 ssh 서버를 구축하고 외부에서 접속까지 가능하도록 해볼것이다.</p>
<p>ssh 설치하고 서버를 구축하는건 매우 쉽다. 그냥 구글 검색만 해도 나보다 훨씬 좋은 방법으로 인도해줄것이다.</p>
<p>일단 맨 처음 apt를 업데이트 해줘야한다.
ubuntu 를 실행하고 간단하게
<code>apt update -y &amp;&amp; apt upgrade -y</code>
를 입력하면 편하게 업데이트가 된다. 아... sudo까지 붙여야함
<code>sudo apt update -y &amp;&amp; sudo apt upgrade -y</code></p>
<p>그럼 모두 자동으로 업데이트가 된다.</p>
<p>그리고 openssh 를 설치해준다.</p>
<p><code>apt install openssh</code>
권한때문에 안된다면 앞에 sudo를 붙이고..</p>
<p>그리고 ssh 서비스를 스타트 해주면 ssh server 를 열 수 있다.</p>
<p><code>service ssh start</code>
이것도 역시나 권한에 문제가 있다면 sudo를 앞에 붙인다.</p>
<p>서비스가 잘 확인되고있는지 확인은
<code>service ssh status</code>
ssh 멈춤은
<code>service ssh stop</code></p>
<p>ssh의 기본 포트는 22인데 나는 이 포트를 보안상 바꾸려고 한다. 포트를 바꾸려면 sshd_config 파일을 수정해줘야하는데 이 파일은 아래의 명령어를 치면 알 수 있다.</p>
<p><code>cd /etc/ssh/</code></p>
<p>아래 경로에 sshd_config 파일이 있을것이다. <strong>ssh_config 와 헷갈리지 말것.</strong>
이걸 vim으로 열어보자.
vim 이 없다면 <code>apt install vim</code>을 쳐서 vim을 설치해준다.
vim 으로 열려면
<code>vim ./sshd_config</code>
를 입력하면 된다. 사실 cd로 디렉토리 이동을 하지 않고 그냥 홈 디렉토리에서
<code>vim /etc/ssh/sshd_config</code>
를 쳐도 바로 열 수 있다. 일일이 치는것보다 파일명의 일부를 입력하고 탭을 누르면 자동완성이 되거나 이름이 애매할 경우 탭을 한번 더 누르면 그 이름과 비슷한 파일들을 해당경로에서 찾아서 보여준다.</p>
<p><img src="https://velog.velcdn.com/images/popcorn_kim93/post/58aaaf4b-53e2-4a6b-acc2-a5ab79051773/image.png" alt=""></p>
<p>이 파일을 수정하려면 읽기전용이기 때문에 sudo 를 붙여야한다.
<code>sudo vim /etc/ssh/sshd_config</code>
를 치면 여러가지 설정값들이 나오는데 그 중 Port 라고되어있는 부분이 있고 앞에 #이 있을것이다. #을 쓰면 주석처리가 되기때문에 #을 제거하고 port 뒤에는 자기가 쓰고싶은 포트번호를 넣으면 된다. 포트 말고도 다른 설정값들이 있는데 이는 버전마다 기본값으로 되어있는 경우도 있고 아닌경우도 있었다. 혹시 몰라 내 설정값을 올려놓았다.
각 설정값에 대한 설명은 아래에서 찾아보면 된다.
<a href="https://webdir.tistory.com/119">https://webdir.tistory.com/119</a></p>
<p>이제 접속을 해야하는데 이렇게 ssh server 를 열고나서 한번 잘 열렸는지 테스트를 해보자.</p>
<p><code>ssh 사용자@접속주소 -p 포트번호</code> 이런 양식으로 치면 되는데 원래는<code>ssh 접속주소</code>만으로도 가능하다. 이는 접속 사용자 아이디를 현재 사용자와 동일하게 간주하고 또한 포트번호도 기본값인 20을 간주하고 접속하는 형태이다 여기서 사용된 기본값은 위에서 헷갈리지 말라고했던 <code>ssh_config</code>에서 설정할 수 있다.</p>
<p>자신의 ssh에 접속해보려면 간단하다.
<code>ssh localhost -p 접속포트</code>
이렇게 입력했을때 접속이 되면 일단 된것이다.</p>
<hr>
<p>이제 외부접속을 되게 해야한다.
저번 포스트에서 wsl2 는 마치 이 컴퓨터를 라우터로 사용하여 서브에 내부망이 하나 더 설치된것같은 느낌으로 동작한다고 했었다. hyper-v 어댑터가 하나 더 생성되어 우리가 설치한 ubuntu 는 이 어댑터에 연결되어 있는것이다.</p>
<p>다른 컴퓨터가 있다면 이 컴퓨터로 연결을 테스트해보길 바란다. 지금 ssh server 를 연 사용자가 good 이고 ip 가 <code>192.168.0.30</code>, 포트번호가 7554 라면
<code>ssh good@192.168.0.30 -p 7554</code>
라고 입력하면 비밀번호를 입력하고 접속하라고 할것이다. 비밀번호는 우리가 ubuntu 를 처음 실행하고 사용자 이름을 설정하기위해 입력했을테고 그 다음 비밀번호를 설정하기 위해 입력했을 것이다. 그때 사용한 사용자 이름과 비밀번호를 입력하면 된다.
혹은 모바일로도 가능하다 <code>Termux</code>라는 어플을 사용하면 모바일에서도 터미널을 사용할 수 있다.
현재 날짜 기준 termux 는 구글스토어에는 올리지 못하는 상황이 되었으며 apk를 받고싶다면 공식 홈페이지에 들어가서 받아야 한다.
<a href="https://termux.dev/en/">https://termux.dev/en/</a></p>
<hr>
<p>접속이 되는가...? <strong>아마 안될것이다.</strong> 무엇이 문제일까 생각해보았다. 일단 우리는 ssh의 기본 포트인 22번을 쓰지않고 우리 임의의 포트를 사용하고 있다. 그럼 22포트로 설정한 다음 ssh server 를 실행했을때는 정상접속이 되어야한다.</p>
<p>여기서 가정해야할 일이 좀 있다.</p>
<hr>
<h3 id="수정된-포트로-접속이-안된다---기본-포트인-22포트로-접속해본다">수정된 포트로 접속이 안된다. -&gt; 기본 포트인 22포트로 접속해본다.</h3>
<p><strong>접속이 된다?</strong>
22 포트는 열려있고 내가 설정한 포트는 안열려있다는 말. 그럼 어디인가 22포트를 열어놓은 설정값이 있을것이다.
<strong>접속이 안된다?</strong>
ssh server 가 실행이 안되있다는 것이거나 접속시도를 엉뚱한 ip로 했다는 뜻이다.</p>
<h3 id="내부는-수정된-포트가-접속이-되는데-외부는-안된다">내부는 수정된 포트가 접속이 되는데 외부는 안된다.</h3>
<p>포트 포워딩을 내부는 허용했으나 외부에는 허용을 안해놨을것이다. 내부에서 허용한 설정값이 있을테니 찾아봐야한다...
등등...</p>
<hr>
<p>굉장한 많은 삽질이 있었다. 집에 노트북이 두대가 있는데 A는 wsl1을, B는 wsl2를 설치했다. 각각 ssh server 를 실행해봤으나 둘다 접속이 되지 않았다. 무언가 막고있다는 생각이 들어서 포트포워딩을 살펴보니 역시나 포트가 문제였다.</p>
<p>공유기를 쓰고있다면 포트포워딩 설정을 가서 우리가 임의로 설정한 포트를 받는다면 해당 ip로 넘겨주는 규칙을 만들어야 한다.</p>
<p>일단 나의 경우에는 synology nas 에 의해 도메인을 받아와서 도메인을 입력하면 집 공인 ip로 접속이 가능하다. 그리고 접속한 다음 어느포트를 사용하냐에 따라서 집에 연결된 수많은 기계중 하나로 연결되게 포트포워딩을 설정해 놓아야 한다.</p>
<p>할게 좀 뒤죽박죽이지만 차근차근하게 설명하자면</p>
<blockquote>
<ol>
<li>localhost 접속 테스트</li>
<li>내부망 접속 테스트</li>
<li>외부망 접속 테스트</li>
</ol>
</blockquote>
<p>이런 순서대로 하는게 좋다.
그럼 첫번째 localhost 는 접속이 되었고... 혹시나 이게 안되더라도 사실 건너뛰어도 된다. wsl의 네트워크 구성에 따라 localhost 는 접속이 안되나 내부망은 접속이 되는경우가 있었다. 그래서 1번은 그렇게 신경 안써도 되고 <code>service ssh status</code>를 쳤을때 sshd가 실행중이라고 뜨기만 하면 일단 ssh server 는 정상실행이 되고있다고 간주한다.</p>
<p>그럼 두번째... 내부망 테스트를 해보자. 포트포워딩 설정방법은 공유기가 다 다를테지만 나는 iptime이기 때문에 그거로 포트포워딩 하는방법만 찾아주겠다.
<a href="https://velog.io/@moey920/iptime-%EA%B3%B5%EC%9C%A0%EA%B8%B0-%ED%8F%AC%ED%8A%B8-%ED%8F%AC%EC%9B%8C%EB%94%A9-%EC%84%A4%EC%A0%95">https://velog.io/@moey920/iptime-%EA%B3%B5%EC%9C%A0%EA%B8%B0-%ED%8F%AC%ED%8A%B8-%ED%8F%AC%EC%9B%8C%EB%94%A9-%EC%84%A4%EC%A0%95</a></p>
<p>일단 포트포워딩 방법은 알았으니 우리는 ssdh_config 에서 지정한 포트번호로 접속이 되면 ssh server 를 연 컴퓨터로 포워딩을 해주면 된다.
프로토콜은 TCP 로 해주고, 내부, 외부 포트번호는 다 ssh server 를 연 컴퓨터로 설정한다.</p>
<p>그리고 내부망에서 접속테스트를 해보면... wsl1이었다면 됐었을거다... 하지만 wsl 에선 되지 않는다...
다시한번 그림을 그리자면
만약 외부 도메인이 good.okok 로 설정되었고, ssh server를 연 컴퓨터의 내부 ip 망은 192.168.0.43, 포트는 7556 포트를 사용하여 열었다고 간주해보자.</p>
<p><img src="https://velog.velcdn.com/images/popcorn_kim93/post/7d627676-45bf-4721-abf1-c0bd4ba27afd/image.png" alt=""></p>
<p>포트포워딩이 되면 위 그림처럼 접속이 된다. wsl1이라면 192.168.0.43번 컴퓨터에 서버가 열려서 저렇게 접속이 되지만... wsl2는 다르다...
ubuntu 에서 <code>hostname -I</code>를 입력해보면 wsl1 이라면 이 컴퓨터의 ip가 나오지만 wsl2에서는 172로 시작하는 이상한 아이피가 나온다...
그렇다... 바로 아래그림과 같은 형태가 되는것이다.</p>
<p><img src="https://velog.velcdn.com/images/popcorn_kim93/post/8c2ede3b-54cc-4088-ac8b-77c606b3ce20/image.png" alt=""></p>
<p>그럼 우리는 외부와 내부에서는 포트포워딩으로 7556 포트로 오는 접속시도는 192.168.0.43 으로 정상적으로 보냈으나 사실은 192.168.0.43이 그걸 받으면 안되고 그림에서 보이는 ip인 172.19.130.94가 이 ip를 받아야 하는것이다.
<img src="https://velog.velcdn.com/images/popcorn_kim93/post/bbae2c73-3bb5-45be-91b3-a2430ee76be0/image.png" alt="">
위 그림과 같이 192.168.0.43 에서 포트포워딩으로 172.19.130.94로 보내야하는것이다.</p>
<p>여기서 갑자기 172라는 ip가 왜 나왔는지 궁금하다면 아래에 잘 설명되어있다.
<a href="https://velog.io/@hidaehyunlee/%EA%B3%B5%EC%9D%B8Public-%EC%82%AC%EC%84%A4Private-IP%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90">https://velog.io/@hidaehyunlee/%EA%B3%B5%EC%9D%B8Public-%EC%82%AC%EC%84%A4Private-IP%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90</a></p>
<p>자, 그럼 받은 192.168.0.43에서 포트포워딩을 통해 wsl2로 보내야한다.. 이건 어떻게 해야하는가... 이러한 포트를 막는 행위는 모두 방화벽에 의해 차단되는데 윈도우 방화벽 설정에서 해당 포트에 대한 혹은 프로세스에 대한 접근을 허용해줘야 한다. 나는 포트로 접속을 하기때문에 해당포트로 들어오는 접속은 그대로 wsl2로 보내야 하는 설정이 필요하다.</p>
<p>방화벽 설정은 powershell을 통해 설정할 수도 있다.
power shell을 관리자 권한으로 연 다음 아래의 명령어를 통해 해당포트로 들어오는 신호를 wsl2로 전달이 가능하다.</p>
<p><code>netsh interface portproxy add v4tov4 listenport=$port listenaddress=&#39;0.0.0.0&#39; connectport=$port connectaddress=172.19.130.94</code></p>
<p>근데 여기서 골때리는 문제가 생긴다... wsl2는 컴픁가 재시작될 때 마다 ip가 바뀌는데 위 명령은 컴퓨터를 한번 껏다키면 매번 바꿔줘야하는 문제가 생긴다.
그리하여 뭔가 스케쥴러 같은거를 통해서 컴퓨터가 켜질 때 자동으로 실행되는 스크립트가 필요했고 다행히도 전세계에 나와 같은 생각을 한 사람들이 많았기에 검색을 통해 아래의 포스트를 얻을 수 있었다.
<a href="https://velog.io/@sjuun/WSL-2-%EC%99%B8%EB%B6%80-%EC%A0%91%EC%86%8D-%ED%97%88%EC%9A%A9">https://velog.io/@sjuun/WSL-2-%EC%99%B8%EB%B6%80-%EC%A0%91%EC%86%8D-%ED%97%88%EC%9A%A9</a></p>
<p>그리고 결론으로 아래 스크립트를 얻게 되었다.</p>
<pre><code>$remoteport = bash.exe -c &quot;ifconfig eth0 | grep &#39;inet &#39;&quot;
$found = $remoteport -match &#39;\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}&#39;;

if( $found ){
  $remoteport = $matches[0];
} else{
  echo &quot;The Script Exited, the ip address of WSL 2 cannot be found&quot;;
  exit;
}

#[Ports]
#All the ports you want to forward separated by coma
$ports=@(80, 1000,2000,3000,5000,8000,8002,8080);


#[Static ip]
#You can change the addr to your ip config to listen to a specific address
$addr=&#39;0.0.0.0&#39;;
$ports_a = $ports -join &quot;,&quot;;


#Remove Firewall Exception Rules
iex &quot;Remove-NetFireWallRule -DisplayName &#39;WSL 2 Firewall Unlock&#39; &quot;;

#adding Exception Rules for inbound and outbound Rules
iex &quot;New-NetFireWallRule -DisplayName &#39;WSL 2 Firewall Unlock&#39; -Direction Outbound -LocalPort $ports_a -Action Allow -Protocol TCP&quot;;
iex &quot;New-NetFireWallRule -DisplayName &#39;WSL 2 Firewall Unlock&#39; -Direction Inbound -LocalPort $ports_a -Action Allow -Protocol TCP&quot;;

for( $i = 0; $i -lt $ports.length; $i++ ){
  $port = $ports[$i];
  iex &quot;netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$addr&quot;;
  iex &quot;netsh interface portproxy add v4tov4 listenport=$port listenaddress=$addr connectport=$port connectaddress=$remoteport&quot;;
}</code></pre><p>위 스크립트를 <code>.ws1</code>확장자로 저장한 다음 위 코드 중 <code>$ports=@</code>라고 되어있는 괄호 안에 열고싶은 포트번호를 입력하고 스크립트를 실행하면 된다.
이 스크립트는 컴퓨터가 다시 재시작될때마다 실행되야 하기에 <strong>작업 스케쥴러</strong>를 통해 설정해놓는게 좋다.</p>
<p><img src="https://velog.velcdn.com/images/popcorn_kim93/post/0e709989-9e12-496f-adf3-42f8f2f22c96/image.png" alt=""></p>
<p>윈도우 키를 누르고 그냥 <strong>작업 스케쥴러</strong> 를 입력하면 나온다.
<strong>작업 만들기</strong>를 누른다.
<img src="https://velog.velcdn.com/images/popcorn_kim93/post/16df1161-8364-4fa9-ad72-a43e7ac60d51/image.png" alt=""></p>
<p>적당한 이름을 입력하고 <strong>트리거</strong> 탭을 누른다.
<img src="https://velog.velcdn.com/images/popcorn_kim93/post/e037274d-3c5a-4548-a1c6-960f650dedbf/image.png" alt=""></p>
<p><strong>새로 만들기</strong>를 누른 후 <strong>작업 시작</strong> 드롭박스를 눌로보면 여러가지가 나오는데 그 중 wsl의 ip는 컴퓨터가 새로 시작할 때 바뀌기 때문에 <strong>시작할 때</strong>를 선택하고 <strong>확인</strong>을 누르면 된다.
<img src="https://velog.velcdn.com/images/popcorn_kim93/post/62f90a4a-9d43-46b9-91b8-d145dbd190b8/image.png" alt="">
<img src="https://velog.velcdn.com/images/popcorn_kim93/post/adb21892-9dc8-45c2-8281-405ad8d2a948/image.png" alt="">
<img src="https://velog.velcdn.com/images/popcorn_kim93/post/648a25d0-d6f5-450c-8a42-2f680863897d/image.png" alt=""></p>
<p>그 후 <strong>동작</strong> 을 눌러준다
<img src="https://velog.velcdn.com/images/popcorn_kim93/post/2756e4c3-1d1b-4506-aaf0-0453a2190a7c/image.png" alt=""></p>
<p><strong>새로 만들기</strong> 를 누르면 아래의 창과 같이 나온다.
<img src="https://velog.velcdn.com/images/popcorn_kim93/post/1afbd965-54ad-415a-b35d-e2d16508cea7/image.png" alt=""></p>
<p>각 구간에는 아래와 같이 입력하면 된다.</p>
<h4 id="프로그램스크립트">프로그램/스크립트</h4>
<p>powershell 의 실행 경로를 넣으면 된다.</p>
<blockquote>
<p><code>%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe</code></p>
</blockquote>
<h4 id="인수-추가">인수 추가</h4>
<p><code>-File</code>옵션 후에 나오는 <code>.\wsl-connect-external.ps1</code> 는 실행할 파워쉘의 이름을 입력하면 된다.</p>
<blockquote>
<p><code>-ExecutionPolicy Bypass -File .\wsl-connect-external.ps1</code></p>
</blockquote>
<h4 id="시작-위치">시작 위치</h4>
<p>위에서 지정한 <code>wsl-connect-external.ps1</code> 가 있는 위치를 입력하면 된다.</p>
<blockquote>
<p><code>C:\PowerShellScript</code></p>
</blockquote>
<p>확인하여 만들고 만들어진 작업을 오른쪽 클릭하면 <strong>시작</strong>이라는 메뉴가 있다. 이 메뉴를 눌러주면 자동으로 스크립트가 실행된다.
혹시나 스크립트가 동작하지 않았더라도 <strong>작업 스케줄러</strong>가 해당 스크립트를 물고있기때문에 다시 <strong>작업 스케줄러</strong>로 들어와서 생성한 테스크를 <strong>오른쪽 클릭</strong> 한 다음 <strong>시작</strong>하면 된다.</p>
<hr>
<p>이제 외부 접속 테스트를 하면 동작을 할것이다.</p>
<p>이 짓을 왜 하냐... ssh뿐만 아니라 나는 ubuntu 에서 code server 를 실행하여 붙을것이기 때문이다. code server 는 ubuntu 로 실행할 생각이고 이 code server는 인터넷으로 연결하기 때문에 port 를 지정할 수 있는데 보안을 위해 또한 외부 입력이 가능하게 한다면 내 synology nas 에서 만든 도메인에다가 code server의 포트번호만 입력한다면 code server 로 쉽게 붙을 수 있을것이다. 이 code server 도 역시나 서버를 열 port 번호를 수정가능한데, 이는 code server 를 본격적으로 설치할 때 포스팅 할 예정이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Code Server 에 node.js 와 npm, vue.js 를 깔기]]></title>
            <link>https://velog.io/@popcorn_kim93/Code-Server-%EC%97%90-node.js-%EC%99%80-npm-vue.js-%EB%A5%BC-%EA%B9%94%EA%B8%B0</link>
            <guid>https://velog.io/@popcorn_kim93/Code-Server-%EC%97%90-node.js-%EC%99%80-npm-vue.js-%EB%A5%BC-%EA%B9%94%EA%B8%B0</guid>
            <pubDate>Sat, 06 Aug 2022 16:13:02 GMT</pubDate>
            <description><![CDATA[<p>아는분이 <strong>경기 콘텐츠 코리아 랩</strong>에서 열리는 <strong>창작 모꼬지</strong> nft 교육 프로그램의 강사로 나가게 되었는데 그분의 권유로 나도 강좌를 듣게됐다.</p>
<p>대강 교육 방향은 자신만의 nft 거래소를 만들어보는거였다.
오늘은 대망의 첫시간이었는데 모든 강의의 첫시간은 첫출근과 마찬가지로 개발환경을 구축하는 시간을 가졌다.</p>
<p><strong>경기 콘텐츠 코리아 랩</strong>은 원래 주말에는 운영되지 않는 곳이라 그런지는 모르겠으나 거기 컴퓨터는 사용할 수가 없었다. <del>데이터 저장이 안된다고했었나...</del> 그래서 개인 작업용 노트북을 가져갔어야 했는데 나는 어쩌피 내 태블릿에 <strong>Code Server</strong> 를 구축해놨으니 거기에 개발환경을 구축하려고 했었다. 언제나 그렇듯 내 상황과 완전히 같을 순 없고 여러가지 케이스를 테스트해볼 수 없었어서 단지 내가 당면한 문제와 그에 대한 해결책만 써내려 갈 것이다.</p>
<p>본 강의에서 필요한 툴은 아래와 같다.</p>
<ol>
<li>node.js</li>
<li>vue.js</li>
<li>Remix IDE</li>
</ol>
<p>이렇게 세가지 이다. 세번째꺼는 웹에서 돌아가는 툴이기 때문에 태블릿의 크롬 브라우저에서도 사용 가능하여 패스, 문제는 1번 2번인데 대부분 윈도우 아니면 맥을 썼기에 node.js 같은 경우에는 홈페이지에서 .exe 파일같은 설치파일을 실행해 대부분 설치했으나 code server 에서는 터미널로 이런 일을 해야했기에 거기서부터 1차 관문에 부딛혔다...</p>
<p><img src="https://velog.velcdn.com/images/popcorn_kim93/post/3cc06d22-e6cf-4e99-93bb-642e707aa704/image.png" alt=""></p>
<p>우선 새 터미널을 만들고 아래의 명령어를 쳐봤다.</p>
<p><code>nodejs</code></p>
<p>이걸치니 친절하게 <code>apt install nodejs</code> 로 설치하라고 떴다.</p>
<p>얼른 쳐봤으나... 권한이 없었다... <code>sudo</code> 를 앞에 붙여주자. <code>sudo apt install nodejs</code>
그러더니 뭐가 슝슝 깔린다. 이제 nodejs 를 치니 뭐가 작동한다.
그리고 <code>npm</code>을 통해 vue를 깔아주어야한다. 그래서 <code>npm</code> 을 쳤다.
찾을 수 없다고 뜬다...
현재 강의에서 설치하라고 권장한 node.js 버전은 <code>14.16.1</code>
나도 한번 쳐봤다. 명령어는 <code>node -v</code>.
버전을 보니 <code>10.</code>어쩌고 버전이었다..
node js 버전을 업그레이드 해야한다. 검색을 해봤다.
모두 <code>npm</code>을 사용해 하는방법 밖에 없었다... 아니... <code>npm</code> 자체가 안된다구...</p>
<p>강의 중 강사님이</p>
<blockquote>
<p>혹시 윈도우나 맥 말고 다른 운영체제는 없으시죠? 다른 강의에서는 CentOS도 봤어요 ㅋㅋㅋㅋ 자 그럼 다들 되는거죠???</p>
</blockquote>
<p>조용히 손을 들었다..</p>
<blockquote>
<p>슨생님.. 저...</p>
</blockquote>
<p>달려와서 같이 봐주셨고 나랑 마찬가지로 버전을 올리려고 했으나 버전을 올리려면 <code>npm</code>이 필요하고 하지만 그건 없기때문에 할수없는 상황에 놓이자 강사님은 조금 고민을 하시다가</p>
<blockquote>
<p>아 그럼 nvm을 써봅시다. 이거는 버전 매니저니까 curl 을 이용해서 바로 깔면 될거예요. 깃에서 찾아보세요!</p>
</blockquote>
<p>검색하니 바로 나왔고 주소는
<a href="https://github.com/nvm-sh/nvm">https://github.com/nvm-sh/nvm</a>
이 주소 중 아래에 보면 <code>Install &amp; Update</code> 라는 부분이 있는데 아래의 명령어가 있다.
<code>curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash</code></p>
<p>이걸 그대로 복사해서 붙여보니 <code>nvm</code>을 설치할 수 있었고, 아래의 명령어를 입력하면 원하는 node js 버전을 설치할 수 있었다.
<code>nvm install 14.16.1</code></p>
<p>그 후 <code>node -v</code>를 쳐보니.. 내가 그토록 원하던 14.16.1 버전이 표시되었다.</p>
<p>그다음 <code>npm</code>을 쳐보니 정상적으로 되었다.</p>
<p>이제 <code>vue.js</code>를 설치해야하는데 설치법은 아래의 명령어를 친다.
<code>npm install -g @vue/cli@5.0.8</code>
대충 vue 의 클라이언트를 설치하는데 버전은 5.0.8을 깔라는말인것같지?</p>
<p>이걸 치면 깔리기 시작한다.</p>
<p>다 깔렸으면 이제 vue 프로젝트를 만들어야하는데 원하는 경로로 이동하여 (<code>cd</code>) 거기서 <code>vue create &lt;프로젝트명&gt;</code>을 치면 프로젝트 이름으로 디렉토리가 생성되며 그 안에 vue 프로젝트가 생성된다.</p>
<p>프로젝트가 생성되면 해당 디렉토리로 이동하여 <code>npm run serve</code>(<del>server 가 아님</del>)을 입력하면 웹브라우저로 <code>localhost:8080</code>를 접속해보면 vue로 생성된 웹페이지가 열린다.</p>
<p>vue를 설치할때인지 프로젝트 파일을 만들때인지... 2.0으로 할래 3.0 으로 할래를 물어보는게 있었는데 본 강의는 3.0 으로 진행되서 그거로 선택했다. yam을 쓸래 npm 을 쓸래 라고 물어보는것도 있다면 npm을 사용한다고 하면 된다.</p>
<hr>
<p>자 그럼 개발환경이 어느정도 완성이 되었는데... 대강 작업은 code server 로 vue 프로젝트 내 node js 파일들을 수정하면서 프로그래밍 하고, npm 을 이용해 <code>run serve</code> 를 하면 웹 서버가 실행되고, 실행된거는 어쩌피 code server 를 실행할때는 크롬을 켜놨을테니, 새탭 열어서 localhost 입력해보면 되는것이지.</p>
<p>아 참고로 내 상황은 code server 를 외부에서 바로 접근할 수 있지는 않고 vpm 으로 집 네트워크로 우회한 다음 거기서 내부망 ip를 통해 code server 로 접근해 놓은 상태이다. 그래서 지금 집에있는 내부망을 쓰고있는것과 똑같은 환경이기에 음... 해보지는 않았으나 아마 code server 를 실행한 컴퓨터의 ip를 치고 포트번호는 8080을 쳐야 정상적으로 홈페이지를 확인할 수 있지 않을까 싶다.
만약 안된다면, 공유기의 포트 포워딩 중에 내부망 8080을 개방해야 할 수도 있을것같다. 그래도 안된다면 <code>run serve</code>를 할때 <code>localhost</code>만 사용할 수 있게 해놨는지도 확인해봐야할듯 하다. ip를 설정할 수 있는 부분이 있다면 그 부분을 자신의 ip로 설정해놔야 가능하지 않을까.
외부에 오픈한다면 어쩌피 synology nas 에 의해 도메인은 따놨으니 외부 포트로 접속했을 시 포트포워딩으로 code server 를 실행한 컴퓨터로 포워딩되게 설정하면 더 쉽게 접근이 가능할듯도 하다. 이거는 다음시간에 실습해보면 될것같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[윈도우에 Ubuntu 설치하기 (WSL2)]]></title>
            <link>https://velog.io/@popcorn_kim93/%EC%96%B8%EC%A0%9C-%EC%96%B4%EB%94%94%EC%84%9C%EB%82%98-%EB%8B%B9%EC%8B%A0%EC%9D%98-%EC%8A%A4%EB%A7%88%ED%8A%B8%ED%8F%B0-%ED%83%9C%EB%B8%94%EB%A6%BF%EC%9C%BC%EB%A1%9C-vscode-%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%A0-%EC%88%98-%EC%9E%88%EB%8A%94-%EC%BD%94%EB%93%9C%EC%84%9C%EB%B2%84-%EA%B5%AC%EC%B6%95%EA%B8%B0..1</link>
            <guid>https://velog.io/@popcorn_kim93/%EC%96%B8%EC%A0%9C-%EC%96%B4%EB%94%94%EC%84%9C%EB%82%98-%EB%8B%B9%EC%8B%A0%EC%9D%98-%EC%8A%A4%EB%A7%88%ED%8A%B8%ED%8F%B0-%ED%83%9C%EB%B8%94%EB%A6%BF%EC%9C%BC%EB%A1%9C-vscode-%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%A0-%EC%88%98-%EC%9E%88%EB%8A%94-%EC%BD%94%EB%93%9C%EC%84%9C%EB%B2%84-%EA%B5%AC%EC%B6%95%EA%B8%B0..1</guid>
            <pubDate>Sat, 16 Jul 2022 08:15:59 GMT</pubDate>
            <description><![CDATA[<p>가장 첫번째로 해야할 일은</p>
<h1 id="윈도우에-ubuntu설치">윈도우에 ubuntu설치</h1>
<p>미안한 얘기지만 여기서 첫번째 관문이 있다. 윈도우에 리눅스 버전은 아무나 깔 수 없고 <strong>윈도우 11 또는 윈도우 10의 21H2버전 이상</strong>이어야만 깔 수 있다.
윈도우에서는 리눅스 가상머신을 돌릴 수 있게 해놓았는데 이걸 <strong>WSL</strong> 라는 이름으로 부르고있다. <del>window service for linux였던가...</del></p>
<p>이걸 까는 방법은 또 여러가지가 있지만 공통적으로 해야하는 일이 있다.</p>
<h2 id="1-linux용-window-하위-시스템-활성화">1. Linux용 Window 하위 시스템 활성화</h2>
<p>제어판 -&gt; 프로그램 및 기능 -&gt; Windows기능 켜기/끄기 -&gt; Linux용 Window하위 시스템 체크!
<img src="https://velog.velcdn.com/images/popcorn_kim93/post/bbc7784f-8181-4d9f-b901-c590f3f7f6c5/image.jpg" alt=""></p>
<p>하고 확인을 누르면 뭔가 설치되면서 컴퓨터 재시작이 필요했었나... 안했었나... 걍 됐었나... 가물가물하긴한데 여튼 당황하지말고 컴퓨터가 하고싶은대로 나두면 된다. <del>다 필요한 일들이겠지</del></p>
<h2 id="2-개발자-모드-활성화">2. 개발자 모드 활성화</h2>
<p>호오오옥시 안되있다면 킨다.
설정 -&gt; 업데이트 및 보안 -&gt; 개발자용 -&gt; 개발자 모드 켬
이거하고 재시작 하라고 안내하는곳도 있긴한데 진행하다가 뭐가 안되면 재시작해보자 <del>또 하면 귀찮으니까...</del></p>
<h2 id="3-ubuntu-설치">3. ubuntu 설치</h2>
<p>이제 Ubuntu 설치이다. 이 방법은 크게 두가지가 있다.</p>
<ul>
<li>Microsoft Store에서 설치</li>
<li>Power shell에서 설치</li>
</ul>
<p>사실 두가지 다 결과는 같다. 나는 편하게 Microsoft Store에서 설치하겠다. Power shell같은 명령창은 나중에 눈에 쥐나도록 볼것이다.<del>눈에 쥐나면 어떤기분이지</del></p>
<p>윈도우 키를 누르고 그냥 키보드를 치면 바로 검색을 할 수 있는데 거기에다가 <strong>Microsoft store</strong>라고 입력하면 store가 뜬다.
<img src="https://velog.velcdn.com/images/popcorn_kim93/post/69506191-c2e9-451b-b508-85991855c87a/image.jpg" alt=""></p>
<p>...라고 생각해보니... 나는 Power shell로 깔았던것같은데.... 어.... 이렇게 해도되나....?</p>
<p>뭐 이렇게 해보고 안되면 power shell로 설치해보자. power shell로 설치하는 방법도 매우 쉽다.
우선 Power shell을 관리자 권한으로 실행한 후 아래의 명령어를 쳐보자</p>
<p><code>wsl --install</code></p>
<p>그럼 여러가지 무슨 설명같은게 많이 나온다. 차차 읽어보면 어떤 명령어를 써야할지 알 수 있겠지만 간단 명료하게 아래 명령어를 한번 더 친다.</p>
<p><code>wsl --list --online</code></p>
<p>그럼 아래와 같이 현재 온라인에 배포되는 linux가 표시된다. 아래의 이미지와 다를 수 있다.
<img src="https://velog.velcdn.com/images/popcorn_kim93/post/a8b297bc-bf03-4de3-94b5-f328ee2af354/image.jpg" alt=""></p>
<p>저기서 배포판 이름을 볼 수 있는데 그 이름을 입력하면 된다. 우리는 Ubuntu를 설치할것이니</p>
<p><code>install -d Ubuntu</code></p>
<p>를 하면 된다. 이렇게 되면 자동으로 wsl 2 로 실행이 된다.</p>
<p>위 행동에 대한 자세한 내용은 Microsoft docs에 있다.
<a href="https://docs.microsoft.com/ko-kr/windows/wsl/install">https://docs.microsoft.com/ko-kr/windows/wsl/install</a></p>
<p>이렇게 설치는 끝났고...</p>
<p>다음엔 ssh를 설치하고 접속이 가능하도록 하는것까지 해보겠다.</p>
<p>추가로 할 얘기는 wsl1과 wsl2인데 이 차이점에서도 ms doc에 명시되어있다.
<a href="https://docs.microsoft.com/ko-kr/windows/wsl/compare-versions">https://docs.microsoft.com/ko-kr/windows/wsl/compare-versions</a></p>
<p>뭔말인지 대강은 알겠는데 일단 우리에게 필요한 기능은 외부에서 여기로 접속하는 부분이다.
근데 wsl1과 wsl2버전에서는 결정적으로 이 부분이 다르다.</p>
<p>wsl1에서는 <del>얼핏 듣기로...</del> power shell에서 가상으로 돌리는거였어서 현재 컴퓨터의 ip와 동일한 ip로 wsl이 실행되는데 wsl2는 이와 무관한 완전한 VM에서 돌아간다. 그래서 사용하는 ip도 다르다... 이 방식은 hyper-v가상방식으로 돌아가기때문에 현재 컴퓨터의 상위에 있는 공유기 네트워크에 wsl이 하나 추가되는게 아니라 wsl가 실행되고있는 컴퓨터 아래에 붙는다. 말로는 설명이 조금 힘든데 그림으로 표현하자면...
<img src="https://velog.velcdn.com/images/popcorn_kim93/post/f6c0a436-c6b9-44c1-9259-efc8481f2195/image.jpg" alt=""></p>
<p>그런데 빡치는게... 각 구다리마다 방화벽이 다 막고있어서 외부포트를 뚫어주기 위해서는 이 포트를 다 뚫어야한다....
아... 이건 다음 글에서 쓸 글을 약간 먼저말했는데 여튼 이러한 문제해결을 다음 글에서 다뤄보겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[서론]]></title>
            <link>https://velog.io/@popcorn_kim93/%EC%96%B8%EC%A0%9C-%EC%96%B4%EB%94%94%EC%84%9C%EB%82%98-%EB%8B%B9%EC%8B%A0%EC%9D%98-%EC%8A%A4%EB%A7%88%ED%8A%B8%ED%8F%B0-%ED%83%9C%EB%B8%94%EB%A6%BF%EC%9C%BC%EB%A1%9C-vscode-%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%A0-%EC%88%98-%EC%9E%88%EB%8A%94-%EC%BD%94%EB%93%9C%EC%84%9C%EB%B2%84-%EA%B5%AC%EC%B6%95%EA%B8%B0..%EC%84%9C%EB%A1%A0</link>
            <guid>https://velog.io/@popcorn_kim93/%EC%96%B8%EC%A0%9C-%EC%96%B4%EB%94%94%EC%84%9C%EB%82%98-%EB%8B%B9%EC%8B%A0%EC%9D%98-%EC%8A%A4%EB%A7%88%ED%8A%B8%ED%8F%B0-%ED%83%9C%EB%B8%94%EB%A6%BF%EC%9C%BC%EB%A1%9C-vscode-%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%A0-%EC%88%98-%EC%9E%88%EB%8A%94-%EC%BD%94%EB%93%9C%EC%84%9C%EB%B2%84-%EA%B5%AC%EC%B6%95%EA%B8%B0..%EC%84%9C%EB%A1%A0</guid>
            <pubDate>Sat, 16 Jul 2022 07:05:54 GMT</pubDate>
            <description><![CDATA[<p>요즘 어느 사람을 만나더라도 어색하지 않은 화제거리가 바로 <strong>코인</strong>이다.
진짜 치트키처럼 좀 어색하다 싶으면</p>
<blockquote>
<p>저기... 혹시 코인 하세요...?</p>
</blockquote>
<p>이 말 한마디면 정적을 깨고 말문이 트일 정도다.</p>
<p>나 역시도 코인을 하고있는데 주식같은 경우에는 장종 시간도 있고... 주말에는 쉬지않는가... <del>물론 해외주식을 같이하고있다면 잘시간도 없겠지만</del> 근데 코인은 밤낮도없고... 주말도없고... 걍 쉬는시간이 없으니 사람들이 하루종일 잠도못자고 보고있는게 아닌가 싶다.
이럴때 필요한게 <strong>봇</strong>이 아니겠는가?!</p>
<p>그래서 파이썬으로 코인 자동매매봇을 만들어보기로 했다. 일단 어떤 라이브러리를 써서 코인을 매수하고, 매매하고, 데이터를 어떻게 얻어오며 어떤 데이터를 얻어올 수 있는지도 알아냈고 이제 가장 중요한 어떨때 팔고, 어떨때 사야하는지를 결정하는 핵심인 <strong>알고리즘</strong>만 남았다.</p>
<p>자... 여기까지 갑자기 내가 잘못찾아왔나...? 분명 제목은 <strong>코드서버 구축기</strong> 인데 무슨 코인자동매매야...? 하겠지..?</p>
<p>일단 여기까지 잠깐 스탑하고... 언제 어디서든지 코인 자동매매가 잘 되고있는지 혹은 알고리즘이 이상하게 되서 긴급하게 패치를 해야할 경우 언제어디서든지 코드에 접근하여 수정하거나 패치를 해야할 경우가 있을것같다는 생각이 들었다. 그러기 위해선 언제어디서든 코드를 수정할 수 있는 개발환경이 갖춰져야 하는데...</p>
<p>회사는 <strong>언리얼 엔진</strong>을 쓰고있어서 사실 코드 에디터 만으로 할수있는게 없다. 엔진을 실행시켜야하는데 이걸 할빠엔 직접 돌리거나 정 상황이 안된다면 원격툴같은 (나 같은 경우에는 <strong>AnyDesk</strong>를 쓰고있다.) 걸로 접속을 해야하는데 태블릿 버전은 영... 좋지않아서...<del>일단 단축키나 윈도우 키+다른키 같은 명령도 안먹고 어쩌고저쩌고...</del> 회사생각하면 언제어디서든 개발하는 환경 자체가 필요하지 않다. 집에서는 집컴도 좋아서 집에서 걍 하면되고 회사에서는 회사컴이 좋으니 하면되고 다른곳에서도...? 어... 워라밸은 지키자... 내 좌우명이 <strong>할땐 하고 놀땐 놀자</strong>이다. 그날 못 끝낸 일이라면 야근을 해서라도 하고 <strong>주말이나 쉴때는 쉬자 제발...</strong></p>
<p>그래서 별 필요없던 이런 환경 자체가 파이썬을 배우면서 확 달라졌다. 이러한 환경이 필요했고 파이썬 정도면 가능하기때문에 구축하기를 시작했다...</p>
<p>검색을 쫌 하니 <strong>code server</strong> 라는것을 찾았다. 제대로 찾아본건 아닌데 vscode가 웹으로 돌아가기 쉬운 언어로 베이스가 짜져있어서 이렇게도 가능한거라고 본거같다.</p>
<p><strong>code server</strong>는 웹에서 vscode인터페이스가 뜨고 vscode 처럼 쓸 수 있는 환경을 제공한다. 하지만 code server라는 이름에 걸맞게 웹에서 스탠드 얼론으로 돌아가는게 아닌 <strong>server</strong>가 필요하다. 이 서버는 사실 어떤거라도 될 수 있다. 컴퓨터, 안드로이드, ios,맥... 어... 사실 ios랑 맥은 안해봤다. 내겐 애플제품이 한개도 없어서...</p>
<h3 id="뭐-여러가지-다른-환경이-있지만-여기선-내-상황만-고려한-해결책을-서술할-것이다">뭐 여러가지 다른 환경이 있지만 여기선 내 상황만 고려한 해결책을 서술할 것이다.</h3>
<p>내 네트워크 환경은 일단...
<img src="https://velog.velcdn.com/images/popcorn_kim93/post/7f559fd4-de5c-4f80-99cf-ba34348f042a/image.jpg" alt=""></p>
<p>이렇게 구성되어 있고, NAS는 <strong>Synology nas</strong>라서 <strong>도메인</strong>을 발급받아 놨다. 그래서 우리집 ip는 도메인으로도 접속이 가능한 상태이고 접속 시 1번 컴퓨터에 붙을지, 2번 컴퓨터에 붙을지, 나스에 붙을지를 <strong>공유기에서 포트포워딩으로 결정</strong>하도록 했다.</p>
<p>1번 컴퓨터는 주로 사용하는 메인컴퓨터고 2번 컴퓨터는 사실 1번 컴퓨터를 사고 난 다음 버림받은 컴퓨터라 아무것도 안하고 놀고있다. 이걸 팔까 하는 생각도 했었는데 어느 날 2번 컴퓨터에는 원래 ssd와 hdd가 설치되어 있었는데 ssd가 인식이 안되더니 그때부터 컴퓨터가 엄청나게 느려지는 현상이 발생했었다. 나는 이게 컴퓨터가 수명이 다되서 그런가... 생각해서 그냥 방치를 하다가 파는걸 생각하니 진짜 믿을수없을정도로 느려 터졌는데 이걸 팔기에는 엄청난 양심의 가책이 느껴져 파는걸 포기했었다.
어느 날 이 컴퓨터에도 서브로 돌릴 일이 생각나서 잠깐 써보려고했는데 진짜... 여전히... 너무나도 느린것이다... 근데 갑자기 이 컴퓨터 사양을 생각하니 도저히 이렇게 느려질 수가 없는데... 내가 이 노트북에 쓴 돈이 그래도 적은돈은 아닌데... 하는 생각에 분노와 억울함이 밀려오더니 ssd때문인걸까 하고 NVMe ssd를 하나 주문했다.
교체하려고 기판을 뜯어보니 ssd는 죽은것같고... hdd를 보니... 무슨... 첨보는 하드가 들어있는것이다... rpm도 낮고... 그리곤 생각났다.</p>
<blockquote>
<p>아... 이거 가성비 쩌는거였지...</p>
</blockquote>
<p>알고보니 ssd에만 몰빵하고 <del>생각해보니 ssd가 그렇게 망가지는거면 몰빵도 안한것같네...</del> hdd에는 겁나 구린걸 넣어놓은것이다. 그로인해 내 돈은 구매당시에 어느정도 세이브를 했기에 뭐... 그렇게 화가 나지는 않았지만 여튼 그렇게 ssd를 까니 2번 컴퓨터는 다시 그렇게 원래 모습대로 돌아와줬다...</p>
<p>그렇게 원래대로 돌아온 컴퓨터지만 여전히 할일이 없어서 놀고있었는데 바로 코드서버로 만들기로 했다.</p>
<p>code server를 윈도우에 설치하는 방법보다 먼저 생각해야하는 방법이 <strong>어떻게 실행하는가</strong> 인데, 크게 두가지가 있다.</p>
<ul>
<li>Power shell</li>
<li>Ubuntu</li>
</ul>
<p>나같은 경우에는 조금 생각해보니 git이나 perforce같은 소스컨트롤을 사용해야할 일이 있을것같아서 원격으로 접속 가능한 ssh를 사용할 일이 많을것같았다. 또한 ssh명령어를 생각하면 power shell보다는 개인적으로 ubuntu가 더 익숙했기에 ubuntu를 사용한 설치방법을 써내려갈것이다.</p>
<p>리눅스를 윈도우에 설치하려면 또 여러가지 설정을 해야했었고 설치법도 wsl1과 wsl2 이렇게 두가지로 나뉘어지고 두가지에 따라서 결정적으로 hyper-v 로 인해 가상랜을 하나 더 만드는게 달랐어서 애를 먹었다... 이건 나중에 차차 자세하게 설명을 할것이다.</p>
<h2 id="그래서-순서에-대해서-간략하게-정리를-하면">그래서 순서에 대해서 간략하게 정리를 하면</h2>
<ol>
<li>Ubuntu설치</li>
<li>SSH 서버 구축</li>
<li>code-server 설치</li>
<li>외부에서 code-server로 접속 가능한 환경 만듬</li>
</ol>
<p>하지만 이걸 하면서도 여러가지 문제가 많이 발생했기에 아마 글이 더 길어질것이다.
이 글은 이 모든일을 겪고 난 다음 기록으로 남겨둬야겠다고해서 쓰는거라... 후... 그래도 결국 해냈다... 다 하는데 2주정도 삽질을 한것같다...
<del>이제 코인매매 알고리즘을 짜면되는데... 글이나 쓰고있네...</del></p>
<p>언제만드냐고오...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[애니메이션 블루프린트를 스켈레톤이 달라도 상속하는 방법]]></title>
            <link>https://velog.io/@popcorn_kim93/howtoinheritanceabpdfferentbone</link>
            <guid>https://velog.io/@popcorn_kim93/howtoinheritanceabpdfferentbone</guid>
            <pubDate>Wed, 26 May 2021 01:54:22 GMT</pubDate>
            <description><![CDATA[<p><strong>언리얼</strong>은 <strong>객체지향</strong>을 하고있으므로 어떤 겹치는 기능들이 있다면 그걸 Base 로 내리고, 세부한 기능들은 자식에서 구현할 수 있습니다. 그래서 매번 캐릭터가 생겨날때마다 캐릭터 이동, 마우스 입력, 키보드 조작 등의 로직을 일일이 다 만들 필요 없이 Base 에서 그 기능을 만들고 그 클래스를 상속받으면 모든 기능들은 포함한 체로 새로운 캐릭터를 구현할 수 있다는 장점이 있죠!</p>
<p>애니메이션 블루프린트도 물론 상속을 받을 순 있습니다! 다만 여러가지 제약이 있습니다...</p>
<p>일단 방법 한번 보시죠!</p>
<h3 id="절차">절차</h3>
<h4 id="1-base부모가-되는-애님블루프린트를-생성">1. Base(부모)가 되는 애님블루프린트를 생성!</h4>
<h4 id="2-부모가-되는-애님-블루프린트를-오른쪽-클릭하여-자식-블루프린트-생성">2. 부모가 되는 애님 블루프린트를 오른쪽 클릭하여 자식 블루프린트 생성!</h4>
<h4 id="3-자식-애님-블루프린트를-열어-target-skeleton-변경">3. 자식 애님 블루프린트를 열어 Target Skeleton 변경!</h4>
<p><img src="https://images.velog.io/images/popcorn_kim93/post/58d04d3c-3fb4-46df-accc-5ee9f20775df/20210526_095724.png" alt="">
이는 &#39;클래스 세팅 - 클레스 옵션(메뉴확장) - Target Skeleton&#39; 에 있습니다.</p>
<p>이렇게 바꾸면 프리뷰 메쉬는 변경되지 않은 체로 T 자세를 취하는데
쫄지마시고 컴파일, 저장 후 자식 블루프린트를 닫고 다시 열어보면 새 메쉬, 스켈레톤으로 변경 되어 있습니다.
(컨텐츠 브라우저 아이콘에서도 바뀐 새 메쉬로 보일꺼예요!)</p>
<h3 id="자-이렇게-하면-되는데">자 이렇게 하면 되는데...</h3>
<p>뭔가 찜찜하죠...? 뭔가 껴맞추는 느낌 들죠...?</p>
<p>그리고 심지어...
<img src="https://images.velog.io/images/popcorn_kim93/post/16208db1-3627-42cf-9fd2-5ea6cbbb99f0/20210526_100136.png" alt="">
Anim Graph를 수정할 수가 없습니다... 전혀 보이지도 않습니다... 부모 애님 블루프린트의 변수, 함수 등 이벤트 그래프에 있는것들은 Override 가능하지만 Anim Graph 는 Override가 안됩니다...</p>
<p>그럼 애님그래프에서 구현한 스테이트머신... 그 안에 들어가는 애니메이션등은... 스켈레톤이 다르면 전혀 동작하지 않을텐데... 어떻게 해야할까...</p>
<h4 id="변수로-만들면-됩니다">변수로 만들면 됩니다!</h4>
<p>변수와 함수 등은 오버라이드 된다고 했죠?? 변수로 만들어서 오버라이드 하면 됩니다!
어떻게 하냐면...</p>
<h3 id="임시해결책">임시해결책</h3>
<p>예시로 설명 드리겠습니다.</p>
<p>아래와 같은 죽는 애니메이션 스테이트 머신을 구현했다고 칩시다.
<img src="https://images.velog.io/images/popcorn_kim93/post/f861872f-a95d-4451-8395-c17b65111827/20210526_100716.png" alt="">
그중 스타트를 열어볼께요 더블클릭!
<img src="https://images.velog.io/images/popcorn_kim93/post/9d67ddaa-2cec-4be9-ad32-8366e9bc86f9/20210526_100730.png" alt="">
그리고 애니메이션 재생 노드를 클릭하면 디테일 패널에 &#39;Sequence&#39; 라는 변수가 있습니다. 이 변수를 핀으로 노출합니다.
<img src="https://images.velog.io/images/popcorn_kim93/post/5c84ee17-d1c0-4cbf-83a3-b623c3039ab8/20210526_101338.png" alt="">
그럼 이렇게 노출이 됩니다!
<img src="https://images.velog.io/images/popcorn_kim93/post/4920aead-eb10-4878-afd7-e9c4c4c2d6ef/20210526_100816.png" alt="">
변수로 승격 후 한번 컴파일 해주면 기본값을 설정할 수 있습니다.
<img src="https://images.velog.io/images/popcorn_kim93/post/b49e38eb-7c8d-446a-b380-af8af007853b/20210526_100825.png" alt="">
<img src="https://images.velog.io/images/popcorn_kim93/post/87ccd401-1512-47cf-b1ff-f5d4c80c4be7/20210526_100842.png" alt="">
자식에서 구분 가능할 수 있도록 변수 이름을 바꿔주도록 하겠습니다.
<img src="https://images.velog.io/images/popcorn_kim93/post/fc6b19d6-d7c6-45ee-904b-599e23bf0feb/20210526_100859.png" alt="">
<del>↑ 아주 좋네요</del></p>
<p>그렇다면 자식 블루프린트를 열어본다음 이렇게 클래스 디폴트를 열면 우리의 죽는 시작 애니메이션인 <strong>&#39;YES DIE START&#39;</strong> 를 볼 수 있습니다!
<img src="https://images.velog.io/images/popcorn_kim93/post/56263c48-f68c-42e2-b50c-ad3de258654e/20210526_100939.png" alt="">
만약 안보인다면 부모 애님 블루프린트를 컴파일, 저장 하고 난 다음 자식 애님 블루프린트를 닫고나서 다시 열어보세요!</p>
<h3 id="찜찜한-느낌">찜찜한 느낌</h3>
<p>자...그래도 역시나 찜찜한 느낌을 지울수가 없군요...
흐으으음... 뭔가 껴맞추는 느낌이고 만약 자식 애님 블루프린트에서 Anim Graph 의 스테이트머신 이라던지 조건이 바뀐다면 혹은 추가되야하는 애니메이션이 존재한다면 구현할 수 없는 약간 반쪽짜리 상속같은 느낌을 지울 수 없습니다.</p>
<p>그렇다면... 상속을 받으면서도 애님그래프를 수정할 수 있는 방법은 없는걸까요?
불행히도...
있긴 있습니다.</p>
<h4 id="바로-c-클래스로-만들어-생성하는겁니다">바로 C++ 클래스로 만들어 생성하는겁니다.</h4>
<p>모든 블루프린트 클래스는 열어보면 오른쪽 상단에 어떤 부모클래스를 상속받았는지 나옵니다.
애니메이션 블루프린트도 블루프린트이기 때문에 당연히 오른쪽 상단에 상속받은 클래스가 무엇인지 나오죠.
<img src="https://images.velog.io/images/popcorn_kim93/post/ee28dc2f-a1a9-48d0-9f44-a3cc786e76d5/20210526_103025.png" alt="">
애니메이션 블루프린트는 Anim instance 라는 클래스를 상속받아서 만들어졌습니다. 그래서 C++ 클래스를 만들때 이 Anim Instance 를 상속받아서 만들면 그 클래스를 상속받아서 애님블루프린트를 만들 수 있습니다.</p>
<p>이 방법은 그렇다~ 라는것만 아시면 될듯하고... 여기서 부터는 프로그래밍적인 지식만 전달하도록 하겠습니다.</p>
<p>Blueprint 를 생성할 때 부모 클래스를 선택할 수 있습니다. 만약 C++로 만든 Anim Instance 를 상속받아 애님 블루프린트를 만들고 싶다면, 일단 C++로 Anim Instance 를 상속받아 클래스를 하나 만들고, 엔진에서는 그냥 애님블루프린트를 만듭니다.
그리고 그 애님 블루프린트의 부모 클래스를 생성했던 C++ 클래스로 변경해야 합니다.
모든 블루프린트는 생성 후 부모클래스를 변경할 수 있는거 아시죠???
위치는 <strong>&#39;클래스 세팅 - 클래스 옵션 - 부모클래스&#39;</strong> 입니다.
<img src="https://images.velog.io/images/popcorn_kim93/post/595293a8-668b-4e24-a52d-9d1d42eaf630/20210526_095724222.png" alt=""></p>
<p>그래서 C++ 로 생성한 Anim Instance 자식 클래스를 저 애님 블루프린트의 부모로 지정하면 이벤트 그래프도 쓸 수 있으며 애님 그래프도 사용 가능합니다.
다만 C++로는 이벤트 그래프(BeginPlay, Initialize, Update 등) 내의 로직은 구현이 가능합니다.</p>
<p>아래는 언리얼 엔진 Anim Instance 안에 있는 코드입니다.</p>
<pre><code>// the below functions are the native overrides for each phase
// Native initialization override point
virtual void NativeInitializeAnimation();

// Native update override point. It is usually a good idea to simply gather data in this step and 
// for the bulk of the work to be done in NativeUpdateAnimation.
virtual void NativeUpdateAnimation(float DeltaSeconds);

// Executed when begin play is called on the owning component
virtual void NativeBeginPlay();</code></pre><p>하지만 애님그래프 내의 로직을 구현할 수 있는지는... 모릅니다... 일단 함수는 있는걸 봤는데 어떻게 사용하는지는 아직 찾아보진 못했습니다.</p>
<p>제 예상으로는 C++ 에서</p>
<pre><code>virtual void NativePostEvaluateAnimation();</code></pre><p>이 함수를 오버라이드하면 가능하지 않을까... 생각이 듭니다...</p>
<p>이상... 아주 찜찜하지만... 가능은 하다... 같은 글이었습니다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Animation Custom Node...]]></title>
            <link>https://velog.io/@popcorn_kim93/thinkaboutanimcustomnode</link>
            <guid>https://velog.io/@popcorn_kim93/thinkaboutanimcustomnode</guid>
            <pubDate>Fri, 21 May 2021 04:15:25 GMT</pubDate>
            <description><![CDATA[<p>Anim Instance 를 상속받는 법은 알고있었어. C++에서 상속받은 UClass 를 생성하여 그 클래스를 상속받아 만들면 C++에서 구현한 적어도 로직, 이벤트 그래프 부분만은 사용할 수 있지.</p>
<p>블루프린트에서도 애니메이션 블루프린트를 상속받아 만들 수 있는데 심지어 <strong>Target Skeleton 가지 변경 가능</strong>해서 Skeleton 은 다르지만 쓰이는 애님 블루프린트 로직은 같을 때 매우 유용하게 쓸 수 있어.</p>
<h3 id="단점은">단점은...</h3>
<p><strong>애님 블루프린트를 상속받아서 자식클래스를 만들면 자식에서 Anim Graph를 수정할 수 없다는거야...</strong> 이거 매우 슬픈얘기야... 하지만 변수로 뺀것들은 전부 수정이 가능하기 때문에 애님 그래프에서 스테이트 머신을 만들고 Bool 로든 어떤 변수로든 그 과정을 거쳐서 사용할 애니메이션을 결정할텐데 그 애니메이션이 Anim Montage 이든 Anim Sequence 형태일꺼야. 그 부분을 Static 하게 결정하는게 아니라 그 부분도 변수로 뺄수가 있거든. 그래서 그 변수에다가 자식 블루프린트에서 그 본에 맞는 Anim Montage, Anim Sequence 를 설정하면 어느정도 애님그래프도 상속 받는다는 느낌을 줄 수가 있지.</p>
<h3 id="근데-특이한건">근데 특이한건</h3>
<p><strong>Anim Instance 를 상속받은 C++클래스를 상속 받아 애님블루프린트를 만들면 그건 애님그래프를 수정할 수가 있어.</strong> 흠... 내가 알아보진 못했지만 C++ 단의 Anim Instance 에서 Anim Graph 쪽을 건들 수 있는지는 안알아봤는데... 글을 적다보니 그것도 괜찮은 방법 같은데...? 만약 가능하다면 C++에서 부모가 되는 Anim Graph Logic 을 만들고 자식에서는 그걸 약간 Override 하면 되지않을까...?</p>
<h3 id="여튼">여튼...</h3>
<p>일단 지금 하고싶은건 로직부분이야 뭐 원래 되는거 알고있었고... Anim Graph 부분을 해결해야해. 머리가 Target Actor 혹은 Target Location 뭐... Target Actor 도 결국 Location 을 알아야하니까 Target Location 을 바라보게 만드는 로직을 상속받아서 작동하게 만들고 싶은데 Skeleton 마다 전부 BoneName 이 다르니 상속받은 블루프린트에서 어떤 본이 Head 로 설정을 할거며 좀 더 확장한다면 이걸 맵으로 만들어서 본마다 Target Location 을 바라볼 Alpha 값을 주면 어떨까... 하는 생각이 드는데 <strong>Anim Graph 에는 특정 본이 Target Location 을 바라보게 만드는 편한 노드가 있지 바로 한글로는 &#39;보는 방향&#39; 이라는 노드야.</strong> 영어로는 &#39;LookAt&#39;이라고 되어있는것같애.</p>
<p>이러한 노드는 디테일패널에서 여러가지 값들을 하드하게 넣을 수도 있고 변수로 생성할 수도 있지. 하지만 아쉬운건 <strong>어떤본이 영향을 받을지는 변수로 뺄 수 없게 만들어놨어...</strong> 그럼 애니메이션 블루프린트 상속은 전혀 의미가 없게 되버리는거야...</p>
<p>리서치를 하던 도중 이 Anim Node 자체를 만들 수 있는 방법이 있는것같아 찾아보고있어. 또 새로운 부분에서 파헤치는거라 엄청난 삽질이 예상돼... 안그래도 어제 이거 리서치하고 코드로 만들고 컴파일 성공만 하루종일 붙들고 있었거든... 근데 그래도 결국 실패했지만 오늘 다시 해보니 이제 문제가 보이기 시작하는것같애. 내가 놓친 부분들. 그리고 이해가 안갔던 부분이 조금씩 이해가는것같애. <strong>가끔 잘 안풀릴땐 한숨 자는게 답일때가 있지.</strong></p>
<p>일단 지금까지 알아낸건 <strong>AnimGraphNode 와 AnimNode... 이게 다른거였다는거야. AnimGraphNode 는 이 노트가 블루프린트에 나타내기 위한 UClass 였고 AnimNode는 이 노드가 실행될 때 실행될 로직들이 들어있는 UStruct였어.</strong> 일단 지금은 아 이게 문제였고 그럼 이제 다음단계로는 내가 생각한대로 그런 노드를 만들 수 있을까? 왜 언리얼은 Bone을 변수로 뺄 수 없게 만든걸까... 뭔가... 이유가 있을법하지만 그래도 지금은 막혔던 부분이 풀려서 그 시원함과 또 밀려오는 뭔가모를 불안감... 과연 어떻게 될까...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[배열을 복붙하는 방법]]></title>
            <link>https://velog.io/@popcorn_kim93/howtocopyarray</link>
            <guid>https://velog.io/@popcorn_kim93/howtocopyarray</guid>
            <pubDate>Thu, 20 May 2021 04:44:49 GMT</pubDate>
            <description><![CDATA[<p>Unreal Engine 의 구조체 뿐만 아니라 배열의 구성요소들은 기본적으로 복사 및 붙여넣기가 됩니다!
심지어 이름은 다른 구조체지만 그 구성요소가 비슷하거나 같다면 약간 번거롭지만 그 내용을 어느정도 복사 붙여넣기가 가능합니다.</p>
<p>제가 했던 프로젝트를 예로들면</p>
<pre><code>(SurfaceType_6_073CB35A420A6079C4E128AD404E3202=SurfaceType1,
HitEmmiter=ParticleSystem&#39;&quot;레퍼런스 경로&quot;&#39;,
HitDecal=MaterialInstanceConstant&#39;&quot;레퍼런스 경로&quot;&#39;,
HitSound=SoundCue&#39;&quot;레퍼런스 경로&quot;&#39;),</code></pre><p>이 구조체는 
SurfaceType
HitEmmiter
HitDecal
HitSound</p>
<p>라는 다섯개의 구성요소로 되어있습니다.
사실 배열의 복사 붙여넣기는 제이슨 형태로 저장되어 붙여지는 것이므로 이름만 넣으면 됩니다.
여기서 언리얼에서는 구별하기위함인지는 모르겠으나 surface Type 같은 경우처럼 <em>6</em>073CB35A420A6079C4E128AD404E3202 이런 이상한 문자를 추가합니다.
그 문자를 제거하고 구성요소에 맞는 이름으로 수정해서 붙여넣으면 올바르게 들어갑니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[몬스터 헌터 라이즈를 하면서...]]></title>
            <link>https://velog.io/@popcorn_kim93/afterpalaymhr</link>
            <guid>https://velog.io/@popcorn_kim93/afterpalaymhr</guid>
            <pubDate>Thu, 20 May 2021 04:25:10 GMT</pubDate>
            <description><![CDATA[<p>요즘 &#39;몬스터헌터 라이즈&#39;를 아주 즐겁게 하고있어.
하고있으면서 참 많은 생각이 들어.</p>
<p>우리 회사 프로젝트는 간단하게 말하면 1인칭 서바이벌 장르야. 거기서 NPC를 내가 개발했었거든. Behavior Tree 를 처음 써본건 아니지만 상대적으로 경험이 부족하기때문에 삽질을 많이했어. 또한 &#39;몬스터 헌터 라이즈&#39; 를 하면서 &#39;아... 내가 삽질을 했구나...&#39; 라는 부분을 또 느낄 수 있었어.</p>
<p>개발하면서 내가 개발한 NPC와의 차이, 또 부족한점이 보였어. 게임할때는 별로 대수롭지 않게 생각했던 것들이었는데 내가 몬스터헌터 라이즈를 플레이하면서 우리게임에 필요하다고 느낀점은 3가지였어.</p>
<h3 id="첫번째-대형몬스터의-yaw-는-항상-캐릭터를-바라보지않아">첫번째, 대형몬스터의 Yaw 는 항상 캐릭터를 바라보지않아.</h3>
<p>내가 만든 NPC중에 대형몬스터가 나오기는 하지만 일단 잡몹부터가 항상 플레이어 캐릭터를 바라보게 만들었어. &#39;Set Focus&#39; 라는 함수를 사용하면 그때부터 몬스터의 Yaw 값은 Focus Actor 를 항상 향하게 돼. 회전하는 애니메이션은 있었지만 플레이어 캐릭터가 감지되지마자마자 이 함수를 실행해서 그때부터 모든 행동을 할때 항상 캐릭터를 바라보게 짰어.</p>
<p>그래서 플레이어를 감지하면 플레이어를 향해 일직선으로 달려가 공격을 하니 보통 이 부분은 이상하게 보이지 않았지만 문제는 공격 애니메이션을 할때 발생했어. 공격 애니메이션을 하는 중 플레이어들은 당연히 가만히 있지 않겠지. 좌우 무빙을 칠꺼야. 그렇게 되면 공격 애니메이션에는 회전하기위해 발구르는 애니메이션이 없는데 그 상태에서 Yaw 만 미끄러지듯 도는 어색하게 보이는 상황이 연출되는거지.</p>
<p>하지만 몬스터 헌터는 그렇지않아. NPC를 감지하면 먼저 플레이어를 바라보며 포효를 해. 그 포효를 하는동안 플레이어를 계속 바라보지 않지. 또한 각종 공격을 할때마다 플레이어를 향해 계속 Yaw 값이 돌아가지 않아. 한마디로 &quot;Set Focus&#39; 의 On/Off 가 존재한다는 거지. 특정상황에서는 캐릭터를 향해 Yaw 값이 돌아가기도 하고 아니기도 하고 하지.</p>
<h3 id="두번째-대형몬스터의-목은-항상-캐릭터를-바라보지-않아">두번째, 대형몬스터의 목은 항상 캐릭터를 바라보지 않아.</h3>
<p>내가 만든 NPC 중 머리가 항상 플레이어를 바라보는것도 있고 아닌것도 있어. 하지만 이 부분도 항상 캐릭터를 바라보니 공격중에서도 계속 바라보게 되는거지. 하지만 몬스터헌터에서는 마찬가지로 특정상황에서 플레이어를 바라보고 또는 바라보지않고, 보통 NPC가 바라보고 있는 각도보다 더 뒤로 가버리면 바라보지 않는데 이 부분은 되어있지만 플레이어를 어느상황에 바라봐야하는지 또한 바라보지 않아야하는지도 추가가 되어야할것같아.</p>
<p>한가지 더 고려해야할 사항은 애니메이션은 지금 서버에서 돌고있지가 않거든. 클라에서만 돌기때문에 Anim Blueprint 에 있는 변수들은 리플리케이션이 안될건데... 아 그리고 이건 테스트해보지 않았지만 아마 Anim Blueprint 자체도 리플리케이션이 안될꺼야. 그래서 되고 안되고를 캐릭터 클래스가 브릿지로 리플리케이트 된 변수를 가지고 있어야 하지 않을까... 하는 생각이 드네...</p>
<p>또한 캐릭터를 바라보고 안바라보고는 사실 서버에서 관리할 문제도 아니니... 그냥 Anim Notify 로 빼는것도 좋은방법같애. 굳이 서버를 거쳐서 리플리케이트 할 필요 없을듯한데...? 어쩌피 target Actor 는 리플리케이트 될꺼니...</p>
<h3 id="세번째-플레이어가-어디에-있는지에-따라-공격-방식이-결정돼">세번째, 플레이어가 어디에 있는지에 따라 공격 방식이 결정돼</h3>
<p>나는 두개의 Behavior Tree Task를 만들었어. 첫번째는 AI가 공격방식을 먼저 설정해서 공격 가능한 거리만큼 목표로 접근한 다음 목표를 공격하는것과, AI가 목표가 얼마만큼의 거리에 있는지에 따라 공격방식을 설정하고 다가가 공격을 하는것 이렇게 두개.</p>
<p>하지만 몬헌은 좀 달랐어. 여기서 한가지 더 나아가 목표가 자신의 위치로부터 어느 방향에 있는지에 따라 그 방향으로 공격하는 방식을 결정하고 난 다음 그 애니메이션을 재생하는거였어. 캐릭터가 어디에있는지, 또 어느 방향에 있는지도 고려되는거지.</p>
<p>일단 몬헌은 플레이어가 자신으로부터 멀리 있을땐 주로 앞으로 공격을 했고, <del>아니 생각해보면 뒤로 하는 공격인데 플레이어가 멀리있기때문에 굳이 플에이어 방향쪽으로 공격 유효사거리정도로 움직여서 그곳에서 뒤로돌아서 뒤로 공격을 할 필요는 없잖아...?</del> 어느방향인지 체크하는 공격 같은 경우에는 주로 가까이 있을때 한것같애.</p>
<p>그렇다면</p>
<blockquote>
<p>플레이어와 가까이 있는가?
Yes 어느방향에 있는가?
No 뛰어가서 돌진공격</p>
</blockquote>
<p>와 같이 판단을 한다는거가 되겠지.
또한</p>
<blockquote>
<p>그 방향으로 공격할 수 있는 공격방식이 있는가?
Yes 공격 개시!
No 한바퀴 휘리릭 도는 범위공격 개시!</p>
</blockquote>
<p>같은 느낌도 받았어. 특정한 방향 없이 한바퀴 쭈우우욱 도는 애니메이션이나 크게 훑는 애니메이션을 했었어.</p>
<p>물론 전체적인 큰 패턴도 존재해. 이 공격 다음 이 공격이 나온다 같은...? 하지만 그 공격의 시작은 &#39;나로부터 플레이어의 캐릭터가 어디 방향에 있는가?&#39; 야. 그래서 플레이를 하다보면 &#39;몬스터로 부터 이 방향, 이 정도의 거리에 있으니 이 공격을 하겠지?&#39; 같은 생각이 자연스럽게 들고 또한 그 예상은 적중이 되고 그게 경험이 되면 미리 그 공격에 대해 대비할 수 있게 되는거지.</p>
<p>내가 짠 AI가 단순하다고 생각이 되어지는 이유 중 하나가 이거인것같애. 지금 NPC 들은 전부 앞으로 공격하는 스타일만 있거든. 이게 모든방향, 모든방향은 아니지만 특정방향 그리고 그 방향의 공격이 없을 시 시전할 수 있는 범위공격도 존재해야하는데 그게 없다는거... 단순히 앞으로만 공격할 수 있다 보니 플레이어가 AI 하나 잡아놓고 뱅글뱅글 돌면서 뚝배기 깨버리면 속수무책하게 당한다는거지... 이게 고려되야 첫번째도 적용했을 때 어색하지 않게 적용되지 않을까 생각이 들어.</p>
<h4 id="그래서">그래서...</h4>
<p>물론 1인칭 게임과 3인칭 게임의 AI를 비교해봤자 별로 의미없는 얘기일 수 있지만 또한 일부 얘기는 몬헌은 그만큼 플레이어의 움직임 또한 묵직하기 때문에 대응할 시간이 길게 필요하고, 어느정도 예상할 수 있게 해야하기 때문에 생긴 특징도 있지만 적어도 내가 지적한 3가지의 문제점과 그 대응책은 충분히 내가 짠 AI를 발전시키는데 괜찮은 점들 같아.</p>
<p>일단 이렇게 적으면서 확실하게 할 수 있는게 몇가지 있지만 두번째 문제를 해결하기 위해선 아직 우리 게임에는 없는 애님블루프린트 상속관계 부터 만들어야할듯 하고... 어쩌피 머리가 플레이어를 바라보는 로직은 다른 AI들도 쓰이는 본만 다르지 다 비슷하게 사용될꺼니 그 부분을 상속관계로 구현 가능한지... 알아봐야겠어...</p>
<p>그리고 세번째는... 음... 일단 테스크 만드는거야 별로 어렵지 않지만 문제는 애니메이션이야... 그만큼 필요한 애니메이션이 엄청 많아지는데... 이건 나혼자 고민할 문제는 아니군...</p>
]]></description>
        </item>
    </channel>
</rss>