제목을 어떻게 지어야 할지 애매한 상황인데, 어쨋든 내가 Ubuntu 16.04에서 Virtualbox를 설치하고 나서 겪은 문제를 해결한 비교적 짧은 삽질기이다.

 

일단 환경 자체는 일반 데스크탑 PC에 iptime wirelss NIC(무선랜카드) 드라이버를 설치하면서 커스텀 MOK.priv / MOK.der라는 걸 만들어서 커널 모듈들을 해당 키로 서명을 했었는데 그 상황 때문에 생긴 문제이다.

 

https://eine.tistory.com/entry/Ubuntu-1804%EC%97%90%EC%84%9C-iptime-A2000UA-Wireless-LAN-%EB%93%9C%EB%9D%BC%EC%9D%B4%EB%B2%84-%EC%9E%A1%EA%B8%B0%EC%82%BD%EC%A7%88%EA%B8%B0

 

Ubuntu 18.04에서 iptime A2000UA Wireless-LAN 드라이버 잡기(삽질기)

본 방법은 제가 수행한 방법으로, 환경마다 조금씩 방식은 다를 수 있습니다. 수행 환경과 버전 Desktop Ubuntu 18.04 4.15.0-52-generic iptime A2000UA Wirelss Lan 카드 USB 버전 일단 그냥 USB를 꼽았을 때는..

eine.tistory.com

위 글에서 한 것 과 비슷하게 iptime A2000UA를 설치를 해 놓은 상태이다. 위 글은 Ubuntu 18.04 기준이긴 한데 이번에는 Ubuntu 16.04 환경이다.

 

Virtualbox 공식 홈페이지에서 Linux distribution에서 알맞은 데비안 패키지 파일을 받아서 sudo dpkg -i virtualbox.deb 명령어로 설치를 했었다.

이제 Win키를 누른 뒤 virtualbox를 실행하면 그냥 잘 될 줄 알았으나 그렇진 않았다.

일단 걍 실행하고 Vbox 이미지를 import한 뒤 실행을 하려니 아래와 같은 메시지가 나왔다.

 

Effective UID is not root (euid=1000 egid=1000 uid=1000 gid=1000) (rc=-10)
Please try reinstalling VirtualBox.
where: SUPR3HardenedMain what: 2 VERR_PERMISSION_DENIED(-10) - Permission denied.

 

 

뭐 대충 이런 메시지가 나오길래, root로 재설치를 하라는데, sudo로 설치했으니 root로 설치된게 맞다.

뭔 소리지 싶어서, 터미널에서 sudo virtualbox로 다시 실행해 보았다.

 

root로 돌린 virtualbox에서 똑같이 이미지 import를 다시 하고 실행을 시키려니, 이번엔 좀 다른 메시지가 나왔다.

Kernel driver not installed (rc=-1908)
The VirtualBox Linux kernel driver is either not loaded or not set up correctly. Please try setting it up again by executing

'/sbin/vboxconfig'

as root.

If your system has EFI Securie Boot enabled you may also need to sign the kernel modules (vboxdrv, vboxnetflt, vboxnetadp, vboxpci) before you can load them. Please see your Linux system's documentation for more information.

where: sublibOsInit what: 3 VERR_VM_DRIVER_NOT_INSTALLED(-1908) - The support driver is not installed. On linux, open returned ENOENT.

뭐 커널드라이버가 설치가 안됬니 뭐니 하면서 vboxconfig를 실행하라는데 찾아보니 나한테는 없는 프로그램이었다.

대충 구글링 해보니 스택오버플로에 아래와 같은 명령어로 설치를 하란다.

 

$ sudo apt install --reinstall -y virtualbox-dkms

 

치니까 apt가 apt-get -f install을 치라고 하더라. 그래서 그냥 쳤다.

 

$ sudo apt-get -f install

 

이제 vboxconfig라는 바이너리가 위에서 말하는 경로에 생겼다. sbin에 있는 바이너리니 당연 sudo 넣어서 실행을 해야겠다 싶었다.

 

$ sudo vboxconfig

 

근데 뭐 좀 되는 것 같더니만 fail을 내뿜는다. dmesg로 확인을 해보란다.

그래서 dmesg로 확인해보니, modprobe에서 에러가 났으며 해당 드라이버 서명이 제대로 안됬다고 한다.

modprobe는 커널 드라이버 로드하는 명령어이다.

 

맨 위에서 말한것 처럼 무선랜카드 드라이버 빌드해서 적제할려고 MOK.der라는 키들을 새로 만들었는데, 아마 이 키로 서명된게 아니라서 그런 것 같다.

 

대충 컨텍스트를 보니 vboxconfig를 실행하면 내 리눅스 시스템에 맞는 vbox용 드라이버를 빌드해서 사이닝 한 뒤 load까지 해주는데 내가 이 커널에서 신뢰하는 키를 새로 만들어버려서 등록을 했으니 signing이 제대로 안되는 것이다.

 

그래서 vboxconfig 로그메시지를 대충 보니, vboxdrv.sh라는 파일에서 빌드하고 서명하고 그런 동작들을 하는 것 같더라.

 

경로를 찾아보니 /usr/lib/virtualbox/vboxdrv.sh 이었다.

 

파일을 열어보자.

kmodsign sha512 /var/lib/shim-signed/mok/MOK.priv \
/var/lib/shim-signed/mok/MOK.der \
/lib/modules/"$KERN_VER"/misc/"$i".ko

그냥 쉘 스크립트 파일이고, setup()이라는 함수 쪽을 보니, 506~508라인이 kmodsign이라는 명령어로 빌드된 모듈들을 서명해주는 것 같았다.

저기서 MOK.priv와 MOK.der파일의 경로만 내 키의 경로로 바꾸어주고 다시 실행해보았다.

vscode로 실행해서 저장을 해 주었다. vscode가 기특한게 저장할때 permission denied가 뜨니까 sudo로 할 건지 아래에 창이 따로 떠서 누르면 password 인증으로 sudo save가 되게 되어있다.

 

그리고 다시 vboxconfig를 실행해보았다.

옳지! 잘된다. Fin!

 

나랑 비슷한 상황에 겪는 사람은 별로 없겠지만, 그래도 혹시모르는 누군가에게 내 글이 도움이 되기를 하고자 하는 마음에 포스팅을 작성한다.

리눅스, 제가 사용하던 버전은 Ubuntu 18.04와 Ubuntu 16.04에서 동일한 문제였는데, python3를 삭제를 한 적이 있습니다.

두개의 버전 다 동일한 문제가 생겼는데, 삭제를 할 때 까지는 별 일 없는 것 같았는데, 터미널을 다 끄고 다시 키니 터미널 폰트가 맛이 가있습니다?

 

그리고 뭐지? 하고 보니 launcher도 안보이고 이상하다 싶어서 재부팅을 해 보니 GUI desktop은 부팅도 제대로 안되는 기현상들이 나타났습니다.

 

그래서 좀 구글링을 해 보니 리눅스에서 파이썬3를 지우지 말라고 하더군요. apt remove python3 이런식으로 지웠었는데 지워지면서 관련 dependencies들이 영향을 다 받은 모양입니다.

 

생각보다 복구방법은 간단했습니다.

 

일단 Ctrl+Alt+F1를 누르면 까만화면에 CLI Only 인터페이스가 뜨게 되는데, 여기서 username/password를 쳐서 로그인을 합니다.

 

그리고 삭제된 패키지들을 아래의 명령어들도 설치/재설치를 해준 뒤 reboot을 해주면 정상적으로 다시 복구가 됩니다.

 

 

sudo apt install -y python3-all
sudo apt install -y software-center
sudo apt install -y gnome-software
sudo apt install --reinstall -y ubuntu-desktop

저 같은 경우는 회사컴퓨터에서 위 현상을 겪었고, 라우팅 테이블을 좀 고쳐놔서 apt 레포지토리에서 파일을 못받아오는 현상도 있어서, 라우팅 테이블을 CLI 환경에서 고치느라 애를 좀 더 먹었었네요.

 

python3을 지우면 왜 ubuntu-desktop, gnome-terminal 등이 맛탱이가 가는지 자세한 내용들은 나중에 한번 시간나면 좀 더 분석해서 올려보도록 하겠습니다.

References

https://askubuntu.com/questions/810854/i-deleted-package-python3-on-ubuntu-and-i-have-lost-dashboard-terminal-and-un

https://askubuntu.com/questions/384033/removed-python-3-and-now-ubuntu-software-center-terminal-and-other-applications

https://stackoverflow.com/questions/34198892/ubuntu-how-do-you-remove-all-python-3-but-not-2/34198961

Rust를 공부해야지 공부해야지 하다가 매우 오랜 시간 동안, 결국은 아무것도 안하고 있길래, 그냥 무작정 만들어보기로 했다.

 

그리고 아래 글을 읽은 이유도 있다.

http://egloos.zum.com/agile/v/5664879

 

프로그래밍 언어 배우기의 달인

미육군에서는 9년간 약 4천만불을 들여 개발한 지뢰 탐지 시스템(Handheld Standoff Mine Detection System, HSTAMIDS 나중에 PSS-14로 개명)을 취소하려고 하고 있었습니다. 프로토타입의 실 테스트에서 지뢰 탐

egloos.zum.com

대충 언어를 새로 배울 때 세가지 원칙을 기준으로 공부를 한다는 점이다.

1. 이 언어로 뭘 만들지를 생각하면서 튜토리얼을 본다.

2. 공부할 때, 표준 라이브러리 코드를 읽는다.

3. 다른 사람이작성한 코드에 내가 필요한 기능을 추가한다.

 

위 글을 보고 영감을 받아서, 그냥 무작정 지루한 챕터들을 읽기 보다는 바로 무언가를 만들어 보는게 낫지 않나 싶다.

 

 

뭘 만들면 좋을까 하다가, 간단한 웹 서버를 만들어 보기로 했다. 어차피 간단한 웹서버는 정말 간단하고, 기능들을 추가하고자 한다면 계속해서 추가할 수 있으니 말이다.

 

Rust 개발환경 구축은 다음 링크 글에서 확인해볼 수 있다.

https://eine.tistory.com/entry/Rust-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95

 

Rust 개발 환경 구축(Windows10에서 Sublime Text 3 / VS code)

느닷없이 Rust를 배우고 싶어져서 Rust 개발환경을 한번 구축해보도록 하겠습니다. 사실 지금 글을 쓰는 이 시점에는 Rust를 공식적으로 지원하는 IDE나 그런 녀석들은 잘 없는데, 그래도 제일 많이

eine.tistory.com

 

일단 개발 환경은, 내가 주로 윈도우 PC를 사용하므로 아래와 같을 예정이다.

개발환경

 - Windows 10

 - rustc 1.44.0-nightly (f509b26a7 2020-03-18)

 - cargo 1.44.0-nightly (7019b3ed3 2020-03-17)

 

일단 github 레포지토리와 개발할 코드 디렉토리를 만들어보자.

 

 

그리고 repository를 clone할 디렉토리에서 WSL win bash를 켠 뒤, git clone을 해준다.

 

 

Rust 프로젝트 생성

이제 rust project를 카고로 만들어줘야 하는데, cargo new rust_web_server --bin 이라는 명령어로 프로젝트 디렉토리를 만들 수 있다.

 

 

근데 안에 디렉토리가 또 생겨버렸다. 이미 README.md와 .git이 있는 디렉토리므로 저 명령어 말고, 다른 명령어를 써야 하는 것 같다.

cargo init --bin이라고 치니 되는 것 같다.

 

 

디렉토리 구조를 보니 바람직하게 만들어진 듯 하다.

일단 VScode로 해당 디렉토리를 열어서 Hello world가 잘 동작하는지 확인해보자.

 

 

기본적으로 소스코드에 hello world프로그램이 작성되어 있다.

아래 터미널을 열어서 cargo build와 cargo run을 쳐 보니, Hello, world!가 잘 되었다.

 

네트워크 기능부터

일단 웹 서버이니 TCP 소캣을 열 수 있어야 한다. Rust에서 소캣 프로그래밍을 어떻게 하는지를 한번 알아보자.

 

소캣 프로그래밍

https://doc.rust-lang.org/std/net/struct.TcpListener.html

 

std::net::TcpListener - Rust

pub struct TcpListener(_); A TCP socket server, listening for connections. After creating a TcpListener by binding it to a socket address, it listens for incoming TCP connections. These can be accepted by calling accept or by iterating over the Incoming it

doc.rust-lang.org

TcpListener라는 녀석이 있다. 일단 소캣을 하나 열어서 Listening하는 예제 코드가 있으니 한번 테스트 해보자.

 

use std::net::{TcpListener, TcpStream};

fn handle_client(stream: TcpStream) {
    println!("Connection!")
}

fn main() -> std::io::Result<()> {
    let listener = TcpListener::bind("127.0.0.1:80")?;

    // accept connections and process them serially
    for stream in listener.incoming() {
        handle_client(stream?);
    }
    Ok(())
}

접속이 되면 stdout에 Connection!이라고 출력만 된다.

일단 여기까지 하고 initial commit을 한번 해 놓겠다.

 

이제 Tcp로 데이터를 전송을 해보고싶은데, Docs랑 예시 코드를 좀 보겠다.

https://riptutorial.com/rust/example/4404/a-simple-tcp-client-and-server-application--echo

 

Rust - A simple TCP client and server application: echo | rust Tutorial

rust documentation: A simple TCP client and server application: echo

riptutorial.com

https://doc.rust-lang.org/std/net/struct.TcpStream.html

 

std::net::TcpStream - Rust

A TCP stream between a local and a remote socket. After creating a TcpStream by either connecting to a remote host or accepting a connection on a TcpListener, data can be transmitted by reading and writing to it. The connection will be closed when the valu

doc.rust-lang.org

stream.write라고 하면 될 것 같은데, 사이에 &는 뭐고 ?는 또 뭔지 모르겠다.

 

찾아보니, &는 burrow라고 해서 인자를 넘겨줄 때, C++의 Reference variable 처럼 Call by reference로 넘기도록 하는 것이고, ?는 Result<T>를 리턴하는 값을 unwrap을 자동적으로 해주도록 하는 매크로이다.

 

 

웹 브라우저로 요청을 보내보니, Response는 안오긴 하는데 Connection이라고 찍히긴 한다.

 

 

그래서 대충 static한 HTTP Response를 찍도록 조금 변경해 보았다.

use std::net::{TcpListener, TcpStream};
use std::io::{Write};

fn handle_client(mut stream: TcpStream) {
    println!("Connection!");
    let data = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=iso-8859-1\r\nConnection: close\r\nContent-Length: 14\r\n\r\nHello world!\r\n";
    stream.write(data.as_bytes());
    
}

fn main() -> std::io::Result<()> {
    let listener = TcpListener::bind("127.0.0.1:80")?;

    // accept connections and process them serially
    for stream in listener.incoming() {
        handle_client(stream?);
    }
    Ok(())
}

그래서 브라우저로 접속을 해볼려고 했는데, 여러번 하면 한번정도 성공하는듯?? 왜 되었다 안되었다 하는지 모르겠다. 

성공하는 확률은 10%정도로 뭔가 Tcp 연결을 잘 못 짠거같긴 하다.

 

그리고 빌드할때마다 다음 warning이 뜬다.

 

 

에러 핸들링을 제대로 안해서 그런 것 같다.

아래와 같이 코드를 바꾸니 warning은 안뜨긴 한다만, 여전히 응답은 제대로 안된다.

use std::net::{TcpListener, TcpStream};
use std::io::{Write};

fn handle_client(mut stream: TcpStream) {
    println!("Connection!");
    let data = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=iso-8859-1\r\nConnection: close\r\nContent-Length: 14\r\n\r\nHello world!\r\n";
    stream.write(data.as_bytes()).expect("Response error");
    
}

fn main() -> std::io::Result<()> {
    let listener = TcpListener::bind("127.0.0.1:80")?;

    // accept connections and process them serially
    for stream in listener.incoming() {
        handle_client(stream?);
    }
    Ok(())
}

근데 약간 이상한것은, Ubuntu 16.04에서 Firefox로 접속하니, hello world!가 잘 찍힌다.

왜 Windows 10에서 크롬으로 접속을 하면 제대로 안되는 것일까..?

 

나중에 확인해보니, tcpstream 마지막에 flush를 해 주니, chrome이든 firefox든 둘 다 잘 돌아간다.

대충 아래와 같은 코드로 고쳐보았다. /로 요청할때와 그 외의 경로로 요청할때의 응답이 다르다.

from_utf8_lossy는 u8 byte stream 값을 readable한 문자열로 변경해주는 함수이다. lossy는 유효하지 않은 UTF-8 배열을 만났을때 어떻게 처리할 것인가에 대한 내용이다. 유효하지 않은 배열 값은 U+FFFD Replacement character라는 값으로 바꾸게 된다.

use std::net::{TcpListener, TcpStream};
use std::io::{Write};
use std::io::prelude::*;

fn handle_client(mut stream: TcpStream) {
    //get request and dump
    let mut request = [0; 1024];
    stream.read(&mut request).unwrap();
    println!("Received HTTP Request...\n{}", String::from_utf8_lossy(&request[..]));
    let response;
    if request.starts_with(b"GET / HTTP/1.1\r\n") {
        //send hello world response
        response = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=iso-8859-1\r\nConnection: close\r\nContent-Length: 14\r\n\r\nHello world!\r\n";
    } else {
        response = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=iso-8859-1\r\nConnection: close\r\nContent-Length: 4\r\n\r\nNope\r\n";
    }
    stream.write(response.as_bytes()).unwrap();
    stream.flush().unwrap();

}

fn main() -> std::io::Result<()> {
    let server = "127.0.0.1:1024";
    let listener = TcpListener::bind(server)?;

    // accept connections and process them serially
    println!("Server is running on {}...", server);
    for stream in listener.incoming() {
        handle_client(stream?);
    }
    Ok(())
}

 

서문

인문학을 전공한 친구의 요청으로, 코딩을 전혀 접해보지 않은 사람을 대상으로 한 "코딩이란 무엇일까?"라는 주제로 포스팅을 해보게 되었다.
이해하기 쉬운 글을 쓰기 위해서, 필자가 쓴 글이 다소 엄밀한 정의와는 거리가 있을 수 있고 예시나 비유를 많이 들 수 있지만, 사전적인 정의보다는 전체적인 흐름을 이해하는데 초점을 맞추어서 글을 읽어주기를 바란다.

코딩이뭔데?

코딩은 영어로 coding인데, 부호를 나타내는 code라는 단어 뒤에 ing가 들어가게 된다. 사전적인 의미로 code는 부호라는 뜻이고, ing은 이 부호를 작성하는 것, 혹은 부호로 바꾸는 것 이라는 뜻이 된다.

여기서 코드(부호)라는 것은 컴퓨터가 처리할 수 있는 명령어라고 보면 된다. 크게 소스코드(source code)와 머신코드(machine code)로 나눌 수 있는데, 이 부분은 자세히는 다루지 않도록 하겠다.

그래서 코딩이란 컴퓨터에게 일을 시키기 위한 코드를 작성하는 것이라고 볼 수 있다.

그러면 프로그래밍은?

프로그래밍은 프로그램을 만드는 것을 프로그래밍이라고 한다. 프로그램은 코드의 모음집이다. 우리가 흔히 쓰는 윈도우 10같은 운영체제도 프로그램이고, 인터넷 익스플로러나 크롬 같은 웹 브라우저도 프로그램이다.
이런 프로그램을 작성하는 것이 프로그래밍이다.

코딩이랑 사실 큰 뜻의 차이는 없고, 코딩은 프로그래밍보다는 좀더 가볍게 적은 양의 코드를 작성한다는 뉘앙스의 차이가 있을 뿐이다.

그러면 코딩을 배우면 무엇을 할 수 있나?

코딩이 컴퓨터에 명령을 내리는 코드를 작성하는 것이니, 당연 코딩을 할 수 있으면 컴퓨터에 명령을 내릴 수 있다.

코딩을 몰라도 명령을 내릴 수 있는데?

맞다 우리는 이미 기본적인 컴퓨터를 사용할 줄 안다. 전원버튼을 눌러서 컴퓨터의 전원을 킬 수 있고, 웹 브라우저를 실행해서 웹 서핑을 할 수 있다. 이미 우리는 코딩을 할 줄 모르지만, 컴퓨터를 사용할 수 있다.

하지만 우리가 이렇게 컴퓨터를 사용하는 것은, 이미 잘 만들어진 다양하고 유용한 컴퓨터 프로그램들이 잘 존재하기 때문이다.

장부같은것을 관리하기 위해서는 엑셀과 같은 스프레드시트 프로그램을 이용하고, 발표자료를 만들기 위해서는 파워포인트같은 프레젠테이션 프로그램을 이용한다. 문서작업을 하기 위해서는 워드와 같은 워드프로세서 프로그램을 이용한다.

그래서 코딩이 왜 유용한건데?

윗 단락에서 컴퓨터로 할 수 있는 다양한 작업들의 예시를 보았다. 그런데 한번 상상해보자.
만약 내가 컴퓨터를 통해서 하려는 작업과 부합하는 프로그램이 없다면? 아니면 가능은 하지만 매우 비효율적으로 해야한다면?

비효율적인 반복 작업을 자동화

예를 하나 들어보자. 당신은 어떤 기업의 행정직으로 입사를 하게 되었다. 당신이 해야 할 일은 회사 전산 시스템에 접속해서 최근 5개년치 회계장부 파일을 모조리 프린트 해야 한다. 그런데 이 회계 장부 파일의 개수가 매우 많아서 하나하나 전산시스템에서 찾아내서 다운로드 받은 뒤, 인쇄를 하려니 단순반복 작업을 매우 많이 해야 한다.

이럴 때, 당신이 코딩을 할 수 있다면 이러한 반복작업들을 처리해주는 프로그램을 작성한 뒤, 이 프로그램이 일을 대신 하도록 맡기고, 당신은 커피한잔의 여유를 가지면서 쉴 수 있다.

실제로 이러한 사례들은 꽤 있으며, 그 중 하나 화제가 되었던 사건이 있다. 아래 유투브 링크를 클릭해서 사례를 참고해보도록 하자.

https://youtu.be/_-ugbwhhApI



 내가 하려는 작업을 해줄 수 있는 프로그램이 없다면?

요즘에는 사람들이 쓸만한 기능에 대한 프로그램들이 꽤나 많이 공유되어 있는 편이다. 하지만 최신기술에 대한 프로그램이나, 특수한 상황에서만 쓰이는 프로그램 등은 누군가가 만들어놓은 경우가 없을 수 있는데 이러한 경우 프로그래밍 능력이 있는 사람에게 돈을 지불하고 외주를 주거나, 직접 해당 프로그램을 작성하거나 해야 한다. 이러한 경우에도 코딩 능력이 있다면 직접 프로그램을 작성할 수 있게 된다

기타 사례들

만약 본인이 유럽여행을 다녀오면서 수 많은 사진을 찍었는데, 이 사진들의 이름을 적절히 변경해서 관리하고 싶을 수 있다. 수천장의 사진의 이름을 일일히 변경할수도 있지만, 사진들을 찍은 시간 순서대로 정렬해서 일정 범위의 사진의 이름 앞에 찍은 도시이름을 포함해서 변경하고 싶을 수 있다. 예컨데 IMG_001 부터 IMG_100까지는 파리_001부터 파리_100 와 같은 식으로 말이다. 이런 경우 파이썬 이나 윈도우 배치 파일을 작성해서 파일명을 한꺼번에 바꾸거나, 다크네이머같은 프로그램을 이용해서 변경할 수 도 있다.

이와 같이 코딩능력이 있거나, 각기 필요한 상황에 쓸 수 있는 프로그램을 안다면 유용하게 사용하여 작업시간들을 단축할 수 있다

철봉여지도 바로가기

개발 동기

요즘 자꾸 배가 나와서 운동을 다시 시작하려고 하는데, 맨몸운동을 한번 시작해볼까 하면서 주변에서 철봉을 찾으려고 했다. 그런데 요즈음 대 IT 시대에 해외 여행을 가서도 구글링과 어느정도 검색만으로 왠만한 맛집도 다 찾고 다 하는 시댄데, 철봉을 찾기가 어려웠다. 내가 어렸을 때만 해도 철봉이랑 평행봉이 어느정도는 있었던 것 같았는데도 불구하고 말이다.

그래서 이것저것 검색을 해 보다 보니, 나와 비슷한 생각을 하는 사람들이 좀 있었다. 어떤 사람은 구청에 철봉 만들어달라고 민원도 넣었다고 한다.

그래서 나도 민원을 넣었다.

나와 비슷한 생각을 했던 사람들이 꽤 있다.

그리고 얼마 안 되어서 답변이 왔다.

철봉이 이미 많다고 한다.

그래서 이렇게 철봉이 많지만 내가 찾기 힘들었으니, 이를 찾아주는 서비스를 한번 만들어 보면 어떨까 싶어서 만들어 보았다.

 

어떻게 만들었는가?

일단 내가 만든 서비스의 가장 중요한 요구사항은 이것이다. 유지비용이 들지 않을 것!

그래서 네이버 지도 API와 구글 지도 API를 알아보았는데, 네이버 지도 API는 사실상 무료나 다름없었다. 그래서 네이버 지도 API를 이용했다.

그리고 DB따위는 쓰지 않는 정적 HTML+CSS+JS 웹 호스팅을 하였는데, 이 또한 github 블로그 페이지를 이용해서 유지비용 0으로 만들었다.

 

데이터는 어디서 구했는가?

저기 구청장님께서 알려주신 데이터 + 내가 발품팔아서 알아낸 데이터가 전부이다. 지금 이 글을 쓰는 시점에는 9개 정도 밖에 없다. 물론 내가 쓰기에는 무리가 없는 듯 하다. 추가적으로 데이터를 기부받고 싶은데 그래서 홍보를 해야 하는데 좀 귀찮기도 하다.

버그같은걸 발견하거나 데이터를 추가하려면 어떻게 해야하는가?

일단 철봉 지도 웹 하단에다가 링크를 두긴 했는데, 데이터 추가는 내 이메일로 철봉의 위도, 경도, 간단한 설명과 사진 정도를 보내주면 된다. 위도와 경도는 저기 지도 웹에서 우측 하단에 +라고되있는 버튼을 누르면 숫자로 나타나게 된다.

그러면 내가 하나하나 검토해서 수작업으로 올릴 예정이다. 아직 홍보를 1도 안했으니 제보도 1도 안왔다.

 

버그발견시도 웹 하단에 링크에 github issue 페이지로 연결시켜놨다. 그쪽으로 남겨주면 내가 확인하고 처리하겠다.

https://www.acmicpc.net/problem/2748

 

2748번: 피보나치 수 2

문제 피보나치 수는 0과 1로 시작한다. 0번째 피보나치 수는 0이고, 1번째 피보나치 수는 1이다. 그 다음 2번째 부터는 바로 앞 두 피보나치 수의 합이 된다. 이를 식으로 써보면 Fn = Fn-1 + Fn-2 (n>=2)가 된다. n=17일때 까지 피보나치 수를 써보면 다음과 같다. 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597 n이 주어졌을 때, n번째 피보나치 수를

www.acmicpc.net

Rust로 PS하기 두번째 문제이다.

 

러스트 깃북을 보다가 피보나치 수 구하기를 만들어 보라길래, 한번 간단하게 짜 보았다.

 

Rust는 역시 input 받는 것부터 난관이다.

 

책 예제대로 String으로 받은 뒤 int로 parse해서 사용했다.

 

 

use std::io;

fn fib(n : i32) {
	let mut a: i64 = 1;
	let mut b: i64 = 1;
	let mut c: i64 = 0;
	for _ in 2..n {
		c = a + b;
		a = b;
		b = c;
	}
	println!("{}", c);

}
fn main() {
	let mut input = String::new();
	io::stdin().read_line(&mut input)
		.expect("read line error");
	let n : i32 = input.trim().parse()
		.expect("Parse error");

	match n {
		1 => println!("1"),
		2 => println!("1"),
		_ => fib(n),
	}
}

코드는 간단했다. _라는 값이 예약어라는 것도 좀 신기했다. (Anything을 뜻하는 듯)

그리고 Match 구문이 switch 구문보다 더 강력하다고 한다.

 

그리고 unnecessary value, syntax에 대하여 강력한 warning으로 내 정신을 쏙 빼놓는다.

 

책만 보면 재미가 떨어지니 이렇게 간혹 코딩을 하면서 진행을 해야겠다.

https://www.acmicpc.net/problem/1620

 

1620번: 나는야 포켓몬 마스터 이다솜

첫째 줄에는 도감에 수록되어 있는 포켓몬의 개수 N이랑 내가 맞춰야 하는 문제의 개수 M이 주어져. N과 M은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수인데, 자연수가 뭔지는 알지? 모르면 물어봐도 괜찮아. 나는 언제든지 질문에 답해줄 준비가 되어있어. 둘째 줄부터 N개의 줄에 포켓몬의 번호가 1번인 포켓몬부터 N번에 해당하는 포켓몬까지 한 줄에 하나씩 입력으로 들어와. 포켓몬의 이름은 모두 영어로만 이루어져있고, 또, 음... 첫 글자만

www.acmicpc.net

Rust언어를 공부하면서 책을 보고 예제를 보고는 있는데 그래도 코드를 좀 짜봐야지 익숙해질 것 같은 느낌이 든다. 그래서 백준 문제중에서 만만한 것들을 Rust로 좀 풀어보기로 하였다.

 

일단 만만한 문제의 기준은 https://solved.ac/class/에 있는 녀석 중 내가 아직 안 푼 문제들이다. 

일단근데 Rust는 Input 받는것 부터 잘 몰라서, 다음 깃허브에 있는 녀석들을 한번 참고하면 좋을 듯 하다.

https://github.com/EbTech/rust-algorithms

 

EbTech/rust-algorithms

Common data structures and algorithms in Rust. Contribute to EbTech/rust-algorithms development by creating an account on GitHub.

github.com

깃허브 자체가 Rust로 Contest나가는거니... scanner도 보인다.

 

문제 자체는 간단하다, String 배열로 받아서 저장해놓고 그때그때 맞는 녀석 출력하면 될 듯 하다. 한번 Rust로 짜보자..!

 

#![allow(unused_imports)]
#![allow(dead_code)]
use std::cmp::*;
use std::collections::*;
 
struct Scanner {
   buffer : std::collections::VecDeque<String>
}
 
impl Scanner {
 
   fn new() -> Scanner {
      Scanner {
         buffer: std::collections::VecDeque::new()
      }
   }
 
   fn next<T : std::str::FromStr >(&mut self) -> T {
 
      if self.buffer.len() == 0 {
         let mut input = String::new();
         std::io::stdin().read_line(&mut input).ok();
         for word in input.split_whitespace() {
            self.buffer.push_back(word.to_string())
         }
      }
 
      let front = self.buffer.pop_front().unwrap();
      front.parse::<T>().ok().unwrap()
   }

   fn next_str(&mut self) -> String {
    if self.buffer.len() == 0 {
       let mut input = String::new();
       std::io::stdin().read_line(&mut input).ok();
       for word in input.split_whitespace() {
          self.buffer.push_back(word.to_string())
       }
    }
    self.buffer.pop_front().unwrap()
    
 }
}
fn main() {
    let mut cin = Scanner::new();
    let n:usize = cin.next();
    let m:usize = cin.next();
    let mut arr = vec![]; // index to string
    let mut hash = HashMap::new(); // string to index
    
    for i in 0..n {
        let name = cin.next_str();
        arr.insert(i, name.clone());
        hash.insert(name.clone(), i);
    }
    for _ in 0..m {
        let query = cin.next_str();
        if query.parse::<i32>().is_ok() {
            let index: usize = query.parse::<usize>().unwrap();
            println!("{}", arr[index-1]);
        } else {
            match hash.get(&query) {
                Some(index) => println!("{}", index+1),
                None => println!("Error case!")
            }
        }
    }

}

어째 저째 대충 짜본 코드이다. 

스캐너로 input 받는것은 아래 레퍼런스를 참고했다.

http://codeforces.com/contest/702/submission/19589375

 

Submission #19589375 - Codeforces

 

codeforces.com

정답은 나올거같은데, TLE가 난다. 왜그런진 모르겟음

 

그래서 답답한 마음에 C++로 후다닥 다시 짜서 보았다.

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define MAXN 100005
string arr[MAXN];
map<string, int> mm;
int main() {
    int n, m;
    cin >> n >> m;
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    
    for(int i=1 ;i <= n; i++) {
        string s;
        cin >> s;
        arr[i] = s;
        mm[s] = i;
    }
    for (int i=0; i < m; i++) {
        string v;
        cin >> v;
        if (v[0] >= 'A') {
            cout << mm[v] << endl;
        } else {
            int idx = atoi(v.c_str());
            cout << arr[idx] << endl;
        }
    }
}

하 C++로 하면 이렇게 간단하게 코드를 짤 수 있는데... 근데 보니깐 sync_with_stdio(false)를 넣지 않으면 TLE가 나는걸로 봐서는 아마 러스트 코드에서 TLE가 나는것은 Scanner가 느리거나, 인풋 받는데 vector를 선언해서 받고 하는데 이런게 느려서 그런거지 않을까 싶다.

 

고로... PS는 C++이 참 편하긴 한듯.

느닷없이 Rust를 배우고 싶어져서 Rust 개발환경을 한번 구축해보도록 하겠습니다.

 

사실 지금 글을 쓰는 이 시점에는 Rust를 공식적으로 지원하는 IDE나 그런 녀석들은 잘 없는데, 그래도 제일 많이 쓰이는 조합이 Visual Studio Code + Rust plugin인 것 같다. 해당 조합은 VS코드에서 Syntax highlighting을 지원합니다.

그리고 RLS라는 Rust Language Server라는 녀석이 있는데 이 녀석은 백그라운드로 실행되면서 코드 에디터나 다른 툴에게 Rust에 대한 정보를 넘겨주는 그런 녀석입니다. syntax상 에러 같은거를 알려주고, 선언부로 이동하기 라던지 IDE에서 제공하는 기능들을 모듈화 된 프로그램이라고 보면 됩니다.

 

근데 아직 RLS도 Stable 버전이 나온 상태는 아니라서 다른 언어에 비해좀 느리거나 중간에 동작하지 않거나 하는 경우가 좀 있다고 합니다. 그래도 쓸만하다고 하네요.

 

제가 구축할 환경은 Windows 10 + Sublime Text3 + Rust plugin 이 되겠습니다.

 

Rustup 설치

Rustup은 rust 툴체인 인스톨러라고 합니다. Rustup을 쓰지 않더라도 러스트를 설치할 수 있지만, rustup을 이용하면 다른 컴포넌트들을 쉽게 설치할 수 있어서 추천한다고 합니다.

https://rustup.rs/

 

rustup.rs - The Rust toolchain installer

To install Rust, if you are running Unix, run the following in your terminal, then follow the onscreen instructions. curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

rustup.rs

홈페이지로 가서 다운받은 뒤 설치를 완료해봅시다.

만약 WSL를 사용하시는 분이라면 아래 curl로 시작하는 명령어를 치라고 하네요. 저는 고전 방식으로 rustup-init.exe를 다운받은 뒤 설치를 진행해보도록 하겠습니다.

1번을 선택한 뒤 계속 진행해보도록 하겠습니다.

설설치가 완료된 뒤 cmd창에서 rustc라고 쳐보도록 하겠습니다.

rustc 컴파일러가 설치된 것을 확인할 수 있네요.

 

Sublime text3에 Rust 플러그인 설치

Rust 플러그인은 Sublime text 3이전 버전은 지원할 계획이 없다고 합니다.

서브라임 택스트에서 Ctrl + Shift + P를 누르면 명령 창이 나타나게 됩니다.

여기서 Package install을 입력한 뒤, Package Control: Install Package를 선택하고 엔터를 눌러봅시다.

그러면 패키지 목록들이 나타나는데, 그 중 Rust enhanced를 설치해보도록 하지요.

 

조금 기다리면 설치가 완료됩니다.

 

Rust 프로젝트 만들기

서브라임 텍스트는 단순 에디터이니, 터미널을 통해서 프로젝트를 생성해줍니다.

그리고 서브라임 텍스트로 프로젝트 디렉토리를 열어줍니다.

$ cargo new hello_world --bin
$ subl ./hello_world

 

Sublime Text3를 위한 RLS 설치 및 연동

 

설치

Rust는 nightly, beta, stable의 3가지 버전이 있는데 unstable한 기능들은 nightly rust에서만 가능하다고 합니다. RLS가 아직 unstable해서 그런지 nightly rust에서만 사용이 가능하다고 합니다.

nightly rust toolchain를 사용해야 하는데, 만약 설치가 되어 있지 않다면 다음 과정에서 설치가 됩니다.

 

Nightly rust tool-chain은 rustup을 이용해서 설치를 할 수 있는데, 저는 이미 stable이 rustup설치시 같이 설치가 된 상태인 것 같군요.

다음 명령어로 설치된 toolchain 상태들을 알 수 있습니다.

$ rustup show

그리고 다음 명령어로 nightly toolchain으로 설정할 수 있습니다.

$ rustup default nightly

만약 nightly 툴체인이 설치되어 있지 않다면 설치도 같이 진행을 합니다.

 

 

그리고 나서 RLS를 설치합니다.

$ rustup update
$ rustup component add rls rust-analysis rust-src

그리고 rls가 제대로 동작하는지를 다음 명령어로 확인합니다.

$ rustup run nightly rls --version
rls 1.41.0 (5fde462 2020-02-21)

이제 RLS가 잘 설치된 것 같군요.

 

서브라임 텍스트와의 연동

서브라임 텍스트에서 RLS와 연동하려면 Package Control에서 LSP라는 녀석을 설치하면 됩니다.

 

아까처럼 Ctrl+shift+p로 명령어창을 띄운 뒤 , package install을 치고 엔터를 누릅니다.

좌측 하단에 Progress bar가 나타난뒤, 패키지 목록 검색 창이 뜨면 LSP를 고르면 됩니다.

 

Detail 설명란에 Language Server Protocol이라고 나와있는 녀석입니다.

설치가 완료되면 위와 같은 메시지가 뜨네요.

 

그리고 LSP for Rust를 활성화를 시켜줘야 하는데, Rust Project를 아무거나 열고, main.rs나 lib.rs같은 파일을 하나 엽니다.

그리고 아까처럼 커맨드 팔렛트를 연뒤 (Ctrl+Shift+P) LSP:Enable 로 검색하면 아래와 같이 뜹니다.

둘 중 하나를 고르면 됩니다. 이 프로젝트에서만 활성화 할 것인지, 아닌지를 고를 수 있네요.

그리고 언어도 골라야하는데, rust를 선택해줍니다.

어허 또 무슨 에러일까요.

RLS가 실행이 안되어서 그런 것 같으니, 터미널을 하나 열어서 따로 실행을 시켜줍니다.

실행을 하고 나서 다시 LSP: Enable 설정을 해 주면 설정이 완료되었습니다.

 

RLS가 잘 동작하는지 확인해보기위해서, rs 확장자로 된 파일에 적당히 수정을 해 보도록 하겠습니다.

use std::fmt;를 추가해주고 저장을 하니 unsed import라고 warning이 뜨는군요. RLS가 잘 설정된 것으로 보입니다.

 

Visual Studio Code 를 위한 RLS 설치 및 연동

VS Code에서 RLS 설치 및 연동은 서브라임 텍스트에 비해 비교적 쉬운편입니다.

일단 Visual Studio Code와 Rustup가 설치가 되어있다는 가정하에 진행해보도록 하겠습니다.

 

VScode에서 Rust Extension을 설치해보도록 하겠습니다. Ctrl + P를 눌러서 ext install rust를 입력해서 검색을 합니다.

이중에서 Rust (rls)를 눌러서 Install을 합니다.

설치가 다 된 이후 reload를 하면 되는데 Ctrl + Shift + P를 눌러서 커맨드 팔렛트를 연 뒤 reload를 치면 됩니다.

 

그리고 Rust 프로젝트 디렉토리를 열면 자동적으로 Rustup component를 설치하려고 합니다.

 

rs 확장자로 된 파일을 하나 열면 아래에 저런 창이 뜹니다.

rustup을 찾지 못하는 것 같으니, nightly를 아까 서브라임 환경 설정할 때 처럼 설정해주도록 합시다. 아니면 VS code를 다시 시동을 하면 아마 인식을 할 것 같네요.

 

이제는 Rustup을 못찾는다는 이야기는 안하고 RLS가 설치되어 있지 않다고 합니다. Yes를 눌러서 설치를 해줍니다.

터미널에 무언가가 뜨면서 설치가 진행되는 것 같습니다.

설치가 완료되었네요. 좌측 하단 상태바에서도 RLS가 돈다고 뜹니다.

저런 tooltip도 뜹니다. 성공적으로 된 것 같네요.

빌드와 실행도 잘 됩니다.

굿!


 

https://github.com/sublimelsp/LSP

https://rinthel.github.io/2017/08/20/rust-vscode-macos/

https://github.com/rust-lang/rustup
https://github.com/rust-lang/rust-enhanced

 

 

Visual studio 2019에서 프로젝트 생성해서 코딩을 하다가, 디버깅 하지 않고 실행을 눌렀을 때 콘솔이 솨라락 하고 바로 꺼져버리는 경우가 있습니다.

 

일단 위 매뉴로 갑니다.

좌측 디버깅-일반 가서 쭉 내리면 아래 항목이 있습니다.

저 항목을 체크를 해 줍니다.

 

콘솔을 닫는다를 체크하는데 왜 되는지는 잘 모르겠네요.

Microsoft SQL Server와 SSMS를 설치했으니 이를 이용해서 쿼리를 한번 써 봐야겟다.

SQL 쿼리문은 SQL 표준 쿼리를 대부분 지원할 것이고, MS-SQL 만의 특별 기능들이 조금 있을 수 있다. 이번 포스팅에서는 그러한 기본 SQL 쿼리문은 다 안다고 생각하고, SSMS의 GUI기능들을 최대한 활용하는 방식으로 접근해보고자 한다.

 

SSMS 실행 및 DB연결

일단 SSMS를 실행해야 하므로, 시작메뉴에서 SSMS를 검색한다.

Microsoft SQL Server Management Studio라는게 뜬다. 클릭해서 실행한다.

 

프로그램이 꽤나 무거워서 실행하는데 시간이 좀 걸린다.

 

SQL 서버 접속 관련된 내용이 뜨는데, 그냥 기본값 그대로 연결을 눌러본다.

 

새 데이터베이스 생성

그리고 새 데이터 베이스를 생성하기 위해 좌측 트레이에서 데이터베이스 항목에 우클릭을 한다.

데이터베이스 이름에 test라고 입력 해보았다. 그러자 아래에 논리적 이름에 2개의 항목이 자동으로 이름이 기입이 된다.

 

그리고 확인 버튼을 눌러서 새 데이터베이스를 추가한다.

새 데이터베이스 "test"가 추가된 것을 알 수 있다.

GUI 방식 말고도, SQL쿼리로 데이터베이스가 어떻게 생겨났는지를 확인할 수 있는 방법이다. 위와 같은 경로로 따라가서 클릭하게 되면 아래와 같은 트레이가 나타나게 된다.

해당 db를 만들 때 위와 같은 SQL 쿼리로 만들어졌음을 알 수 있다.

 

테이블 생성

테이블을 생성할 데이터 베이스의 하위 기능을 확장한 뒤, 테이블 쪽에서 마우스 우클릭을 해서 새로 만들기 - 테이블을 클릭한다.

그러면 위와 같이 테이블 생성 마법사가 나타나게 된다.

열 이름과, 데이터 형식을 설정한 뒤 탭에 마우스 우클릭을 해서 저장을 누른다.

테이블 명을 입력하라고 하는데 user라고 입력했다.

그리고 나서 좌측 창에 있는 새로고침 버튼을 눌러본다.

그러면 하단에 새로운 테이블 dbo.user가 추가된 것을 확인할 수 있다.

 

테이블에 데이터 추가

이제 user라는 테이블에 데이터를 추가해보자.

위와 같은 경로로 새 쿼리 편집기 창을 켜면, INSERT INTO 쿼리가 어느정도 완성되어서 나타나게 된다.

values에 값을 넣어보도록 하자.

그리고 쿼리를 실행하기 위해 실행 버튼을 누르도록 하자.

값을 넣고 잘 들어갔는지 확인을 해보자.

그러면 결과값을 볼 수 있다.

값이 잘 들어간 것을 확인할 수 있다.

 

 

 

------------------------------------------------------------------------------------------

https://www.guru99.com/ms-sql-server-tutorial.html
https://docs.microsoft.com/ko-kr/sql/relational-databases/database-engine-tutorials?view=sql-server-ver15
https://www.guru99.com/sql-server-database-create-alter-drop-restore.html

+ Recent posts