직전 포스팅에서 엑셀과 데이터베이스를 간단하게 비교를 해 봤는데, 이번 글은 직전 포스팅의 후속글입니다. 따라서 예상 독자도 이전글과 동일하게 엑셀로 현업 실무를 하는, 개발자가 아닌 사람입니다.

 

이번 포스팅에서는 DBMS의 몇가지 종류와 특징들, 그리고 SQL이 무엇인지와 스키마에 대해 간략하게 알아보고자 합니다.

데이터베이스 프로그램(DBMS: Database Management System)의 종류

데이터베이스를 다룰 수 있는 컴퓨터 프로그램들이 어떤 것이 있는지를 구체적으로 알아봅시다. 사실 데이터베이스 프로그램 뿐만 아니라 데이터베이스의 패러다임도 다양한 종류가 있습니다. 일단은 가장 전통적이면서도 강력한 관계형 데이터베이스(Relational Database, RDB) 프로그램에 대해 알아보도록 하겠습니다.

햄버거에 맥도날드, 롯데리아, KFC가 있듯이 DBMS에는 sqlite3, mysql, mariadb, postgre-sql, oracle db 시리즈, mongodb, cassandra 등등 여러가지가 있습니다.

사실 근래들어서 새로운 database의 한 패러다임인 nosql db라는 것도 있는데 해당 내용은 나중에 시간이 남게 되면 추가적으로 다루며, 이번에는 다루지 않겠습니다.

일단 데이터베이스를 다루는 프로그램을 두개의 범주로 나누어 보겠습니다.

파일형 Database(Flat-file database)

엑셀의 경우 그 데이터 값들은 하나의 파일에 다 들어가 있습니다. 마찬가지로 데이터베이스 중에서 하나의 파일 형태로 존재하는 데이터베이스가 있습니다. 대표적인 예시로 SQLite3가 있습니다. 그 외에도 마이크로소프트 액세스 같은 것들도 파일형 데이터베이스를 지원합니다. 이어서 나오는 서버형 데이터베이스에 비해서는 처리할수 있는 규모나 성능은 다소 떨어질 수 있으나, 파일 하나에 데이터가 다 들어간다는 간편성이 있습니다.

서버형 데이터베이스

개발자들이 자주 사용하는 형식의 데이터베이스인 서버형 데이터베이스입니다. 실제 IT 서비스에서 자주 사용되는 데이터베이스들이며 파일형 데이터베이스에 비해 큰 규모의 데이터들도 쉽게 처리하며, 하나의 파일 형태로 존재하는 것이 아닌 하나의 컴퓨터에서 지속적으로 실행되고 있는 형태의 프로그램으로 존재합니다. 따라서 그 컴퓨터와 네트워크 연결이 가능한 다른 컴퓨터에서 원격으로 데이터들을 조회하거나 다룰 수 있으며 따라서 여러명의 사용자가 동시에 사용하는 것도 가능합니다. 이에 따라 인증 및 권한과 동시성과 관련된 다양한 복잡한 기능들도 제공을 합니다. 이에 해당하는 DBMS에는 Mysql, MariaDB, PostgreSQL, 오라클 데이터베이스 등이 있습니다.

 

SQL(Structured Query Language)

직역하면 구조화된 질의어에 해당합니다. SQL은 선언형 프로그래밍 언어에 해당하며, 관계형 데이터베이스 관리 시스템(RDBMS)을 사용하기 위한 컴퓨터용 언어입니다. 엑셀의 경우 GUI(Graphical User Interface)를 지원하기 때문에, 눈에 보이는 버튼들을 누르고 셀을 클릭한 뒤 값을 입력하거나 하는 식으로 직관적인 방법으로 데이터들을 처리할 수 있지만, 앞서 위에서 언급한 (관계형) 데이터베이스들은 데이터를 처리하기 위해서 SQL이라고 하는 프로그래밍 언어를 작성한 뒤 이를 이용해서 명령을 내려야 합니다.

데이터를 조회할때는 Select 구문, 수정할때는 Update 구문, 생성할때는 Insert into 구문, 제거할때는 delete from 구문이라는 프로그래밍 언어 문법(Syntax)에 맞는 SQL 구문을 작성한 뒤, 이를 DBMS에 전송해서 작업들을 수행할 수 있습니다.

따라서 이 RDBMS 종류를 다루기 위해서는 SQL이라는 언어를 잘 알아야 하는 것이지요. 혹은 이 SQL 구문들을 자동으로 생성해서 동작하게 끔 하는 프로그램을 별도로 개발한다면, 엑셀을 다루듯이 클릭 등의 직관적인 방법으로 데이터를 다룰 수 있게 할 수 있습니다.

 

관계형 데이터베이스와 스키마

관계형 데이터베이스(Relational-Database)

앞에서 관계형 데이터베이스에 대해서 자세한 설명을 하지 않고 넘어왔지만, 여기서 간략하게 관계형 데이터베이스가 무엇인지 짚고 가겠습니다.

데이터베이스를 어떤 식으로 저장할지는 여러 패러다임들이 있었지만 지금 가장 많이 쓰이는 형식이 관계형 데이터베이스(Relational Database)이며, 데이터베이스를 표 형태로 표현한다라는 뜻이라고 보시면 됩니다.

위 표를 보시면, 간단한 용어를 확인할 수 있는데, Relation(관계)는 표 자체를 뜻하고, Attribute는 특성값이라고 보시면 됩니다. 사실 엑셀도 표 형식이니 이해하기 어렵지 않을 것입니다.

엑셀에 위와 같은 데이터가 있다고 하면, 첫번째 행에 있는 이름, 국어, 영어, 수학 들은 attribute에 해당하며, 각각의 2번째 3번째 행은 tuple에 해당하게 됩니다. 이것이 표 형태로 있는 것이 relation이 됩니다.

이런 용어들은 크게 신경쓸 필요 없고, 다만 관계형 데이터베이스는 데이터를 위와 같은 표 형태로 나타낸다 라는 것만 기억하시면 됩니다.

데이터베이스 스키마

앞에서 관계형 데이터베이스가 표 형식을 따른다고 했습니다. 이때 이 "표의 형태가 데이터베이스 스키마"입니다. 

위에 예시에서 들은 2명의 학생의 국어,영어,수학 성적에 대한 Relation의 스키마를 표현하자면 다음과 같겠습니다.

이름이라는 attribute는 text 데이터를 저장하고, 국어와 영어 수학이라는 attribute는 정수 값을 저장하는 형태를 띱니다.

이 내용 자체가 성적과 관련된 저 Relation의 스키마입니다.

그리고 이 Relation은 RDBMS 및 SQL에서는 테이블이라고 부릅니다. 테이블은 직역하면 표라는 뜻을 갖지요.

 

References

ko.wikipedia.org/wiki/%EA%B4%80%EA%B3%84%ED%98%95_%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4

namu.wiki/w/Microsoft%20Access

namu.wiki/w/DBMS

ko.wikipedia.org/wiki/%ED%94%8C%EB%9E%AB_%ED%8C%8C%EC%9D%BC_%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4

이 글은 개발자가 아닌 주변 지인들로부터, 현업에서 엑셀로 데이터를 처리하다가 여러가지 한계점을 느끼고 데이터 베이스를 배우고자 하는 니즈가 있다는 것을 알게 되어, 이와 비슷한 경험을 겪은 사람들을 위해 작성된 글입니다.

따라서 추가적으로 질문이나 요청사항이 있다면 이 글에 댓글 등의 방법으로 피드백을 남겨주시면 글에 내용을 추가하거나 추가 글을 작성하도록 하겠습니다.

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

엑셀 vs 스프레드 시트

일단 용어에 대해 살짝 명확하게 하고 가자면, 스프레드시트와 엑셀은 의미에 있어서 차이가 있습니다. 스프레드시트는 표 형식으로 데이터를 처리할 수 있는 컴퓨터 프로그램을 뜻합니다. 엑셀은 마이크로소프트라는 회사에서 만든 스프레드 시트 프로그램의 상표명이라고 볼 수 있죠. 마치 스프레드 시트와 엑셀의 관계는 유리테이프와 스카치테이프, 고체풀과 딱풀, 라면과 삼양라면, 햄버거와 불고기버거의 관계라고 볼 수 있습니다. 엑셀외에도 한컴오피스에서 만든 한셀이라는 프로그램도 스프레드시트 프로그램 중 하나입니다. 엑셀이 제일 유명한 스프레드 시트 프로그램이니, 앞으로는 편의상 엑셀이라고 칭하겠습니다.

 

엑셀을 왜 쓸까요?

엑셀은 표 형식으로 데이터를 처리하는 스프레드시트 프로그램입니다. 따라서 표 형식으로 나타내면 편리한 데이터들을 처리하기 위해서 씁니다.

CRUD 데이터 처리

여기서 데이터 처리라는 것은 데이터 쓰기, 읽기, 바꾸기, 지우기와 같은 동작들인데, 이 용어들을 영어로 표현하면 Create, Read, Update, Delete인데 이 단어들의 앞글자를 따면 CRUD가 됩니다. 이 CRUD는 컴퓨터 프로그램에서 데이터를 처리할때 가장 기본이 되는 4가지 동작들입니다. 엑셀은 이 4가지 동작이 다 손쉽게 가능합니다.

Create를 할 때에는 엑셀의 빈 셀에 값을 쓰면 되고, Read는 해당 셀을 클릭해서 데이터를 확인해볼 수 있습니다. 검색이 필요한 경우 Ctrl + F를 눌러서 검색이 가능합니다. Update(수정)가 필요할때는 셀을 클릭해서 새로운 값을 입력하거나, F2를 누른 뒤 값을 변경하면 됩니다. Delete(삭제)는 해당 셀을 클릭한 뒤 키보드 delete 키를 누르면 됩니다.

다소 복잡한 데이터 처리

데이터 정렬이 필요할때에는, 칼럼 이름에 필터를 건 뒤, 오름차순 혹은 내림차순으로 정렬하기를 누르면 쉽게 정렬이 됩니다. 그 외에도 평균값을 구하거나, 총합을 구하거나, 순위를 구하거나 등의 다소 복잡한 데이터 연산이 필요한 경우 엑셀에 내장된 함수들을 이용해서 계산을 할 수 있습니다.

 

데이터베이스는 뭘까요?

사전적인 의미로는 여러사람들이 공유하여 사용할 목적으로 체계화하여 통합 및 관리하는 데이터 집합이라고 합니다. 데이터를 쉽게 잘 다룰 수 있도록 잘 해놓은 데이터 덩어리라고 보면 된다. 사실 기본적인 내용들은 엑셀과 다를 바 없는 것이, 똑같이 데이터를 다루고, CRUD 연산도 당연히 잘 됩니다.

Database vs DBMS(Database management system)

여기서 데이터베이스(Database)와 DBMS(Database Management System)의 차이를 살짝 짚고 넘어갑시다. 데이터베이스는 데이터들 모여있는 것, 데이터 그 자체를 의미하고, DBMS는 데이터 베이스를 처리하는 컴퓨터 프로그램입니다.

눈치채었을 수 있겠지만, 이제 언급할 것들은 사실 데이터베이스가 아닌 DBMS의 특징들이라고 볼 수 있습니다. 그냥 데이터베이스는 추상적인 개념들이고, DBMS는 우리가 당장 실무에서 써먹을 수 있는 녀석들이니 말입니다.

 

엑셀 vs 데이터베이스(DBMS)?

엑셀과 데이터베이스의 장단점을 매우 간단하게 비교하면 이렇습니다. 엑셀이 배우기는 훨씬 쉽고 직관적입니다. 데이터베이스는 익히고 사용하는데 지식이 더 많이 필요하고 어렵습니다. 

대신 데이터베이스는 엑셀보다 더 좋은 성능과 기능들을 가지고 있습니다. 여기서 더 좋은 성능이라 함은, 엑셀의 경우 데이터가 몇 만개 정도만 되어도 컴퓨터가 버벅이고 느려지고 처리가 힘들어질 수 있으며, 데이터 개수의 제한이 명확하지만 데이터베이스의 경우는 그 보다 더 많은 개수의 데이터도 쉽고 빠르게 처리할 수 있습니다. 또한 엑셀에서 처리하는 것 보다 더 복잡할 수 있는 연산들을 처리할 수 있습니다.

그리고 엑셀의 경우 남과 데이터를 공유하려면, 엑셀파일을 저장한 뒤, 이 파일을 이메일 등을 통해서 공유를 해야 하는데, 데이터베이스의 경우 실시간으로 데이터 편집한 부분을 반영시켜서 남과 동시에 작업이 가능합니다.

구분 엑셀(스프레드시트) 데이터베이스(DBMS)
장점 직관적, 익히기 쉽다 사용 시 쿼리 언어에 능숙해야함
데이터 모델링 시 지식과 숙련도 필요
단점 많은 데이터 처리시 느려짐(저성능)
다소 복잡한 내용 처리 어려움
동시작업 불가능
많은 데이터 쉽게 처리(고성능)
복잡한 처리 가능
동시작업 가능

뭐 쉽게 생각하면, 데이터베이스가 익히기는 어렵지만 엑셀에서 할 수 있는 것들 대부분을 다 할 수 있고 성능도 더 좋고 강력합니다. 하지만 데이터 베이스를 잘 쓰기 위해서는 데이터베이스용 쿼리 언어인 SQL을 사용할 줄 알아야 하고, 데이터 모델링에 대한 지식과 숙련도도 필요합니다.

실제 소프트웨어 회사에서 데이터베이스의 성능을 극대화까지 끌어내기 위해서, 이러한 SQL 쿼리 작성과 데이터 모델링만 전문적으로 행하는 DBA라는 직무가 따로 있을 정도로 깊게 들어가면 매우 어려운 영역입니다.

하지만 그렇게까지 복잡하지 않은 데이터들을 처리할때에는 가볍게 공부해서 시도해볼 수 도 있을 것 같습니다.

References

ko.wikipedia.org/wiki/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4

www.oppadu.com/%EC%97%91%EC%85%80-vs-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%B0%A8%EC%9D%B4%EC%A0%90-1%ED%83%84/

www.oppadu.com/%EC%97%91%EC%85%80-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%B0%A8%EC%9D%B4%EC%A0%90-%EB%B9%84%EA%B5%90/

opentutorials.org/course/3162/19527

https://www.datacamp.com/community/tutorials/role-underscore-python

 

Role of Underscore(_) in Python

In this tutorial, you're going to learn about the uses of underscore(_) in python.

www.datacamp.com

이 글은 위 글의 번역 및 정리 글입니다.

 

파이썬관련 찾아볼 일이 있어서 보다가 언더바에 대한 내용들이 있어서 한번 정리합니다.

파이썬 개발자들 중 많은사람들이 파이썬에서 언더바의 역할에 대해 잘 모르는데, 이를 이용해서 코드 생산성을 늘릴 수 있습니다. 이번기회에 한번 알아봅시다.

for _ in range(100)
__init__(self)
_ = 2

만약 당신이 파이썬 개발자라면, 위와 같은 파이썬 코드들을 본 적이 있을 것입니다.

위에서 _는 각각 다른 조건에서 특별한 의미를 갖습니다.

 

일단 6개의 다른 용도가 있는데 차근차근 알아봅시다.

  1. 인터프리터에서의 사용
  2. 무시하는 값
  3. 루프에서 사용
  4. 숫자값의 분리
  5. 명명용
    1. 앞에 하나가 쓰이는 경우
    2. 뒤에 하나가 쓰이는 경우
    3. 앞에 두개가 쓰이는 경우
    4. 앞 뒤로 두개씩 쓰이는 경우

이제 예제들과 함께 알아봅시다.

 

1. 인터프리터에서 사용

파이썬 인터프리터에서 가장 마지막 표현식의 결과값을 자동적으로 "_"라는 변수에 저장합니다. 물론 여기 저장된 값을 다른데다가 저장할 수 있습니다.

일반적인 값처럼 쓸 수 있습니다.

>>> 5 + 4
9
>>> _
9
>>> _ + 6
15
>>> _
15
>>> a = _
>>> a
15

위와 같이 동작하는걸 볼 수 있습니다.

2. 무시하는 값

언더바는 무시하는 값으로도 쓰일 수 있습니다. 해당 값을 unpack하기 싫다면, 그냥 _에다가 할당하면 됩니다.

## 값을 버립니다.
a, _, b = (1, 2, 3) # a = 1, b = 3, _에 2가 할당됩니다.
print(a, b)

## 여러개 값 버리기
## *(변수) 는 unpack할때, 여러개의 값을 하나의 변수에 저장할때 쓰입니다.
## 이는 확장된 Unpacking이라고 불리며,Python 3.x 버전에서만 가능합니다.
a, *_, b = (7, 6, 5, 4, 3, 2, 1)
print(a, b)

테스트를 해보니, _에다가 할당하면 _도 일반 변수처럼 쓰이고, 1번처럼 Last expression을 저장하지 않게 됩니다. del _를 통해 해당 변수를 삭제하면 1번때처럼 Last expression을 저장하게 됩니다.

 

3. 루프에서 사용

for 루프를 돌 때 사용할 수 있습니다. 아래처럼 쓰는 것도 하나의 방법이 됩니다.

## _를 이용해서 루프를 돕니다.
for _ in range(5):
    print(_)

## 리스트 순회를 _를 이용해서 합니다.
## _ 를 일반 변수처럼 사용할 수 있습니다.
languages = ["Python", "JS", "PHP", "Java"]
for _ in languages:
    print(_)

_ = 5
while _ < 10:
    print(_, end = ' ') # 'end'의 기본값은 '\n'인데 이걸 변경해줍니다.
    _ += 1

실행결과는 예상한 것과 같게 아래처럼 나옵니다.

0
1
2
3
4
Python
JS
PHP
Java
5 6 7 8 9

4. 숫자값의 구분

숫자값이 길다면, 자릿수 구분을 위해 _를 중간중간에 넣어줄 수 있습니다.

이진수값이나 16진수, 8진수 값도 동일하게 적용할 수 있습니다.

## 여러 숫자 표현법
## 아래 값들이 정확한지 확인하기위해 int 함수를 써 볼수도 있습니다.
million = 1_000_000
binary = 0b_0010
octa = 0o_64
hexa = 0x_23_ab

print(million)
print(binary)
print(octa)
print(hexa)

실행 결과는 아래와 같습니다.

1000000
2
52
9131

5. 언더바를 포함한 변수명들

 변수, 함수, 클래스 명 등에 언더바가 사용될 수 있습니다.

  • 앞에 하나의 언더바 _variable
  • 뒤에 하나의 언더바 variable_
  • 앞에 둘의 언더바 __variable
  • 앞과 뒤에 두개의 언더바 __variable__

5.1 앞의 하나의 언더바

앞에 하나의 언더바로 시작하는 이름은, 내부 사용용입니다(internal use only). 일단 예시부터 봅시다.

class Test:

    def __init__(self):
        self.name = "datacamp"
        self._num = 7

obj = Test()
print(obj.name)
print(obj._num)

위 코드를 실행하면 아래처럼 됩니다.

datacamp
7

변수명 앞에 _를 하나 붙였다고 해서, 해당 변수를 접근하지 못하게 되진 않습니다. 하지만 모듈을 import해서 쓰는 경우 효과가 발생합니다.

아래와 같은 코드를 한번 확인해봅시다.

## filename:- my_functions.py

def func():
    return "datacamp"

def _private_func():
    return 7

이제 my_functions.py를 가져오기 위해 import 구문을 써보자. 파이썬은 언더바 하나로 시작한 이름들은 import하지 않는다.

>>> from my_functions import *
>>> func()
'datacamp'
>>> _private_func()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name '_private_func' is not defined

위의 코드 결과를 보다시피, _로 시작한 _private_func는 찾지를 못한다.

위와 같은 에러를 방지하기 위해, from module import *가 아닌 모듈 자체를 import를 해보자. 

>>> import my_functions
>>> my_functions.func()
'datacamp'
>>> my_functions._private_func()
7

앞에 _ 1개로 시작한 이름은 내부 사용 전용이라는 뜻이다.

5.2 뒤의 하나의 언더바

가끔 파이썬 키워드에 해당하는 이름으로 변수명, 함수명, 클래스명으로 쓰고 싶을때가 있을 수 있다. 이럴때 이 방법이 유용하다. 마지막 부분에 언더바를 하나 추가함으로써 파이썬의 기본 키워드들과 충돌하는거를 방지할 수 있다.

>>> def function(class):
  File "<stdin>", line 1
    def function(class):
                 ^
SyntaxError: invalid syntax
>>> def function(class_):
...     pass
...
>>>

마지막에 하나의 언더바를 추가하는 명명법은 파이썬 키워드와 겹치는 경우를 방지하고 싶을때이다.

5.3 앞의 두개의 언더바

앞에 두개의 언더바로 시작하는 명명법은 name mangling이다. mangle은 짓이기다라는 뜻인데, 알아보기 힘든 모양으로 만든다라는 의미로 볼 수 있겠다.

앞에 두개의 언더바로 시작하는 명명법은 파이썬 인터프리터에게 해당 서브클래스의 attribute 이름을 바꾸어서 이름 충돌이 나지 않게 하라고 말하는 것이다. 서브클래스 이야기가 나온걸로 봐서 상속하는 경우와 관련이 있는 것 같다.

 

일단 예시를 보자.

class Sample():

    def __init__(self):
        self.a = 1
        self._b = 2
        self.__c = 3
obj1 = Sample()
dir(obj1)

dir한 결과는 아래와 같이 나온다.

['_Sample__c',
 '__class__',
 '__delattr__',
 '__dict__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__le__',
 '__lt__',
 '__module__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 '_b',
 'a']

dir함수는 클래스 객체의 모든 attribute들을 리턴해준다. 선언한 변수들을 dir 리턴값 중에서 한번 찾아보자.

a와 _b는 잘 보인다. 맨 마지막에 있다. _b는 내부 사용용으로만 쓰인다.

Sample클래스에 분명히 __c라는 맴버변수를 선언했는데, __c는 없고 대신 _Sample__c라는 값이 있다.

이것이 name mangline이다. 나중에 다른 클래스가 Sample이라는 클래스를 상속할때, 그 클래스에서 이 변수를 override하는 걸 방지해준다.

 

다른 클래스를 만들어서 Sample이라는 클래스를 상속해보자.

class SecondClass(Sample):

    def __init__(self):
        super().__init__()
        self.a = "overridden"
        self._b = "overridden"
        self.__c = "overridden"
obj2 = SecondClass()
print(obj2.a)
print(obj2._b)
print(obj2.__c)

상속을 한 뒤, 초기화를 하는 과정에서 Sample의 맴버변수들에 값을 다 대입하고 있다.

overridden
overridden



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

AttributeError                            Traceback (most recent call last)

<ipython-input-2-4bf6884fbd34> in <module>()
      9 print(obj2.a)
     10 print(obj2._b)
---> 11 print(obj2.__c)


AttributeError: 'SecondClass' object has no attribute '__c'

__c를 찾지 못해서 에러가 발생했다. name mangline때문에 obj2.__c가 아닌 obj2.__SecondClass__c로 바뀌었다. obj2._SecondClass__c를 한번 출력해보자.

print(obj2._SecondClass__c)
overridden

편의상 결과도 같이 썼다.

그러면 _Sample__c는 어떻게 되었는지 한번 보자.

print(obj1._Sample__c)
3

mangle 된 이름으로 잘 있다.

 

맴버함수(메소드)를 이용해서 mangle 된 두개의 언더바로 시작하는 변수를 접근할 수 있다. 예시를 보자.

class SimpleClass:

    def __init__(self):
        self.__datacamp = "Excellent"

    def get_datacamp(self):
        return self.__datacamp

obj = SimpleClass()
print(obj.get_datacamp()) ## "Excellent"를 출력한다. __datacamp에 해당하는 값이다.
print(obj.__datacamp)     ## 여기서 에러가 발생한다. 변수 이름이 바뀐다.

메소드(getter, setter)안에서는 잘 접근을 한다. 하지만 외부에서 멤버 변수로 직접 접근하려고 하면 에러가 난다.

 

언더바 2개로 시작하는 명명법은 변수뿐만 아니라 메소드 이름에도 적용이 가능하다. 예시를 보자.

class SimpleClass:

    def __datacamp(self):
        return "datacamp"

    def call_datacamp(self):
        return self.__datacamp()

obj = SimpleClass()
print(obj.call_datacamp()) ## __datacamp()의 리턴값과 같다.
print(obj.__datacamp())    ## 여기선 에러가 난다.

__로 시작한 함수는 안에서만 호출이 되는 용도라고 보면 될 것 같다.

다른 객체지향 언어에서 private access modifier(접근 지정자)의 역할이라고 보면 될 것 같다.

 

다른 예시를 한번 보자.

_SimpleClass__name = "datacamp"

class SimpleClass:

    def return_name(self):
        return __name

obj = SimpleClass()
print(obj.return_name()) ## "datacamp"를 출력하게 된다.

위와 같은 코드도 정상적으로 동작을 한다.

 

좀 특이한 방식의 개념이다.

5.4 앞뒤로 2개의 언더바

파이썬에서 앞뒤로 2개의 언더바로 둘러쌓인 명명법을 본 적이 있을 것이다. 이녀석들은 매직 메소드(magic method) 혹은 dunder 메소드라고 불린다.

class Sample():

    def __init__(self):
        self.__num__ = 7

obj = Sample()
obj.__num__

이 명명방식을 변수 이름으로 사용할 경우 변수명 충돌이 일어날 수 있기 때문에 가급적 삼가하는게 좋다.

dunder method에서 dunder는 double under(score)를 뜻하며, 보통 연산자 오버로딩을 할 때 많이 사용한다고 한다.

매직 메소드는 __init__, __add__, __len__, __repr__등이 있다.

 

__init__메소드는 생성자라고 보면된다. 호출없이 초기화할때 호출되는 함수이며, 클래스의 인스턴스가 생성될때, 실행되게 된다.

 

__repr__ 메소드는 해당 클래스를 출력하고자 할때 내부적으로 호출되는 메소드라고 보면 된다. 자바로 치면 toString() 함수와 유사하다고 볼 수 있겠다.

References

https://www.geeksforgeeks.org/dunder-magic-methods-python/

어쩌다 보니 환경 구축만 계속 여러번 하게 되는 듯 하다.

회사 리눅스 컴이 맛가서 밀고 다시 설치하고, 집컴와서 vm에 Ubuntu 깔고 다시 설치하고 등등... 그냥 이렇게 된 김에 한번 싹 정리하자.

 

Linux에서 포너블 문제풀이든 할 환경을 싹 구축해보자.

사실 그렇게 복잡하진 않다.

Virtualbox에 Ubuntu 18.04 설치

이 과정은 뭐 대충 다 아실거라 생각한다. Virtualbox 설치하고, Ubuntu 18.04 iso 다운받아서, 대충 머신만든 뒤, iso넣어서 부팅하면 아래 처럼 나온다.

Live CD로 플레이하는게 있고, 설치하는게 있는데 당연 설치이다. 언어랑 키보드는 English(US)고르고 그냥 계속 Continue누르면 된다.

Normal install이라고 되있는데 Minimal install으로 바꿔서 했다.

기본 옵션으로 간다.

스왑 알아서 박는다는데 걍 Continue로 간다.

어디있냐는데 Seoul 그대로 간다. 타임존이랑 apt repository 때문에 물어보는거일듯 함.

유저명이랑 패스워드 정하라는데, 어차피 vm안에 놈이니 대충정하자. 좀 기다린다

이제 설치가 다 된거다.

 

virtualbox extension 설치

설치를 하고 나면 화면이 굉장히 작고 host랑 클립보드 공유가 안되는 걸 알 수 있다.

extension을 설치해줘야한다.

게스트 확장 CD 이미지 삽입을 누르면, vbox내에 guest extension 설치 파일이 있는 이미지가 CD로 들어간것처럼 된다

실행하고 안애 파일을 설치시켜주면 된다.

비밀번호를 치면 알아서 설치가 된다.

이제 재부팅을 해주자. 이제 vbox 윈도우를 전체화면을 하면 안에 화면도 꽉차게 된다. 꿀!

 

클립보드 공유도 설정을 해주자.

우분투 화면잠금 해제

Settings -> Privacy -> Screen Lock을 Off해주면 된다.

우분투 sleep mode 해제

Power saving에 never 해준다.

pwntools 설치

일단 python3부터 설치를 해야 한다. 그리고 python3-pwntools를 설치를 하면 된다.

$ sudo apt update && sudo apt install -y python3 python3-dev python3-pip git && pip3 install --upgrade git+https://github.com/arthaud/python3-pwntools.git

 

잘 설치되었는지 한번 확인해보자.

별 다른 에러가 없는거보니, 잘 된 것 같다.

 

gef 설치

$ sh -c "$(curl -fsSL http://gef.blah.cat/sh)"

 

(curl을 미리 설치해야 한다)

 

잘 된다. 사실 뭐 별것없다. 쓰고나니 다 간단하기만 했네

vscode 설치

text editor로 vscode를 깔아보자.

공홈가서 deb 파일을 받은 뒤

$ sudo dpkg -i vscode.deb 하면 된다.

 

References

https://github.com/hugsy/gef

https://github.com/arthaud/python3-pwntools

제목을 어떻게 지어야 할지 애매한 상황인데, 어쨋든 내가 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

http://www.yes24.com/Product/Goods/91433923

 

이것이 취업을 위한 코딩 테스트다 with 파이썬

IT 취준생이라면 누구나 입사하고 싶은 카카오 · 삼성전자 · 네이버 · 라인!취업의 성공 열쇠는 알고리즘 인터뷰에 있다!IT 취준생이라면 누구나 가고 싶어 하는 카카오, 라인, 삼성전자의 2016년

www.yes24.com

이번에는 다른 포스팅과는 다르게 책에 대한 리뷰 겸 홍보를 하려고 합니다. 보통 이런 글은 잘 쓰지 않지만, 지인인 동빈님이 작성하신 첫 종이책이기도 하고, 제가 리뷰어로서 참여한 책이기도 하니 한번 소개해보려고 합니다.

 

무작정 이 책이 좋다, 아니다 어떻다라기 보다는 객관적인 시선으로 이 책의 특징과 장점을 설명하고, 어떠한 사람들이 이 책을 읽으면 좋을 지에 대해 한번 글을 써 보도록 하겠습니다.

 

제가 알고리즘을 처음 공부할 때에는...

제가 알고리즘 문제풀이를 본격적으로 시작했던 때가 딱 3년전인 2017년 즈음 이었던것 같습니다. 그때는 컴퓨터공학과 학부에서 내주는 과제수준의 Naive한 다중 for-loop으로 코드를 짜거나, 함수의 재귀 개념에 스택, 링크드리스트라는게 있다 정도만 아는 정도의 수준이었습니다.

 

그때 알고리즘 분야의 정석 교과서라고 불리던 종만북을 구입을 했었고, 앞에 수십페이지에 달하는 서문을 읽고, 첫번째 문제인 Festival을 알고스팟에서 풀어보려고 했었죠. 당시 종만북 책에는 해당 문제에 대한 해답이 없었던걸로 기억하고, 고로 Festival 문제를 제대로 풀지 못하고 바로 종만북은 책장에 박혀서 먼지가 쌓여갔던 기억이 있습니다.

당시의 저에는 매우 어려운 문제였던 것이지요.

 

그러다가 학교 선배의 추천으로 정보올림피아드 초등부 문제를 풀었었고, 풀다가 막히면 좌절감에 공부를 쉬기도 했었죠. 그리고 강남역에서 있었던 백준님의 오프라인 강의도 돈을 내고 들었었습니다. 제대로 공부해보겠답시고 학부 4학년에 학교 알고리즘 동아리의 문을 두드렸기도 했고, 그때 들은 코드포스에 참여하면서 혼자서 이것저것 시도해보고 막히면 잠시 쉬었다가 다시 공부하고 이런 과정들의 연속이었습니다.

 

어쨋든 시간이 지나고 경험이 쌓이면서 지금은 왠만한 국내 기업들의 코딩테스트에서는 떨어지지 않을 정도의 기반이 쌓이긴 했지만, 꽤나 시행착오도 많이 했었고 중간에 어려운 난이도에 부딪혀서 잠시 공부를 포기하며 쉬는 기간들도 꽤 많았습니다.

 

3년전의 과거의 저에게 지금 이 책이 주어진다면, 좀 더 효율적이고 덜 좌절하면서 공부를 할 수 있었지 않았을까 하는 생각이 듭니다.

 

그래서 이 책의 특/장점은 무엇이냐면

동빈님이 쓰신 이 책의 특징과 장점이라고 하면, 아마 다음과 같은 항목들이지 싶습니다.

취업용 코딩테스트의 최신 트랜드 반영

알고리즘 문제풀이를 공부하는 사람들은 이유가 다양하지만, 일반적으로는 취미용이나 대회용을 타겟으로 한 책들이 많습니다. 취업용 문제풀이의 경우는 취미용이나 대회용 만큼의 고급/심화 내용을 포함하진 않고, 취업용은 이 대회용 문제들의 부분집합이라고 볼 수 있습니다. 물론 고급 내용들도 공부를 하면 무조건 좋지만, 효율적으로 취직을 타겟으로 공부를 할 때에는 조금 돌아가는 부분이 있을 수 있습니다.

이 책에는 취업용 코딩테스트에서 나올 법 한 것들을 모두 잘 커버하며 잘 짜여진 커리큘럼이 있으며, 최근 기출문제들과 관련 유형들을 잘 커버하고 있습니다. 

유명한 종만북과 비교를 하자면, 종만북은 책의 목적이 취업용 코딩테스트를 위한 책이 아니며 책이 쓰인지도 꽤 오래된 편입니다.

알고리즘 문제풀이를 처음 접하는 사람들을 위한 난이도

보통 취업용 코딩테스트를 준비하는 분들은 하나 정도의 프로그래밍 언어를 사용할 줄 알며, 취직 준비를 위해서 알고리즘 문제풀이를 처음 공부하는 사람들이 많습니다. 이미 프로그래밍 대회 등을 준비했던 사람들에게는 따로 준비가 필요없을 수 있거든요. 이렇게 알고리즘 문제풀이에 처음 입문하는 사람들도 쉽게 이해하며 단계별로 계단을 밟아가듯 핵심 개념들을 쉽게 이해할 수 있도록, 이러한 독자들의 눈높이에 맞도록 쓰여진 책이라고 생각합니다.

종만북과 비교를 하자면, 종만북은 예상독자와 책 읽는 목적 자체가 좀 더 향상된 실력에 맞추어져 있어서, 알고리즘 문제풀이를 처음 접하는 사람에게는 진입장벽이 다소 있어서 책을 읽는 처음부터 어느정도 좌절을 할 수 있습니다.

파이썬 및 C++/Java 풀이 제공

코딩테스트 시 3대장 언어가 C/C++, Java, Python입니다. 전통적인 알고리즘 책들은 보통 C++ 코드를 고수하는 경우가 많습니다. 저 역시 알고리즘 문제 풀이 입문을 위해서 PS스타일의 C++와 C++ STL을 따로 공부하며 시간을 투자했습니다. 하지만 요즘에는 컴퓨터 공학 전공자 뿐만 아니라, 그 외의 산업공학과나 수학과 통계학과 경영학과 등 다양한 전공자들이 코딩을 배우는 경우가 많으며, 보통 이 경우 첫 입문 언어로 파이썬을 많이들 배웁니다. 이러한 분들에게 파이썬으로 코딩테스트 문제 풀이를 도와주는 책으로써 가치가 있고, 파이썬 뿐 만 아니라 C++과 Java 풀이 코드도 github를 통해 제공을 하여 공부에 도움을 줍니다.

지속적인 학습을 위한 리소스 제공

저자인 동빈님은 원래 유투브를 통해서 무료 개발과 SW관련 강의들을 많이 찍던 컨텐츠 크리에이터로써, 책과 관련된 강의들도 유투브를 통해 제공을 하고, 정답 코드 들도 친절한 주석과 함께 github에 공개되어 있습니다. 컴퓨터교육과 전공자 출신 답게 전달력있는 강의를 잘 제공하며, 수 많은 교육 경험들이 어우러진 동빈님의 컨텐츠는 공부를 할 방향과 내용들을 쉽게쉽게 이해할 수 있게 해줍니다.

 

어떤 사람들이 읽으면 좋은가?

3년전의 저에게 추천해주고 싶은 책입니다. 여태까지 알고리즘 문제해결 분야에 발을 담그지 않았다가, 이제 곧 취직 준비를 해야 해서 코딩테스트를 준비를 해야 하는 경우, 이 책에 있는 공부법대로 그대로 실시하면 됩니다. 최신 트랜드도 그대로 반영하고 있기 때문에 지금으로서는 이보다 더 가성비 좋은 선택은 없지 않을까 하는 생각이 듭니다.

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 와 같은 식으로 말이다. 이런 경우 파이썬 이나 윈도우 배치 파일을 작성해서 파일명을 한꺼번에 바꾸거나, 다크네이머같은 프로그램을 이용해서 변경할 수 도 있다.

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

개념

Security by obscurity 또는 Security through obscurity라고 부르는 이 녀석은, 어떤 시스템이나 컴포넌트의 보안성을 설계나 구현을 알려지지 않게 하는것에 의존하는 것을 뜻한다.

이 방식만을 이용해서 보안을 적용하는것은 추천되지 않고 있다.

 

내부 구조가 어떻게 생겨먹었는지 알 수 없게 하는 것으로 보안성을 만든다라는 것인데, 약간 말이 이상할 수 있으니 예를 들어보자.

 

예시

 

어떤 컴퓨터가 공공장소에 놓여져 있다. 어떤 사람이 그 컴퓨터를 무단으로 사용하려고(공격하려고)하는데, 버튼을 몇개 눌러보니 윈도우 컴퓨터임을 알 수 있고, 그 윈도우 버전에서 비밀번호 없이 로그인을 할 수 있는 방법이 있음을 알아서 그를 이용해서 로그인을 해서 안에 저장된 자료들을 무단으로 사용하고 온갖 것들을 할 수 있다.

 

그런데 만약 해당 컴퓨터에 Mac OS가 설치되어 있었고, 공격자는 Mac OS를 사용해본 적이 없었다. 그래서 공격을 할 수 없었다고 해보자.

 

공격자는 Mac OS에 대한 이해가 부족하기 때문에 공격에 실패했다. 이러한 방식의 보안을 Security by obscurity라고 볼 수 있다.

 

물론 여기서 아니 누가 Mac OS를 몰라?라고 생각할 수 있는데 그러면 AIX 운영체제나 더 오래된 옛날 Unix 운영체제, Dos 운영체제 등의 예시를 들어보자.

 

잘 안쓰이고 오래되어 잊혀진 구조를 갖는것으로 보안성을 획득하는 것이라고 보면된다.

 

다른 예시를 들어보면, 어떤 파일을 압축을 해서 저장을 한다고 해 보자. 널리 쓰이는 deflate 알고리즘이나 PK zip, gunzip 등의 압축 포맷으로 압축을 하면, 해당 포맷에 대한 압축해제를 하는 프로그램과 알고리즘들이 잘 공개되어 있어서 쉽게 압축을 풀 수 있다. 하지만 만약 공개되지 않은 새로운 압축 알고리즘, 자신들만 쓰는 압축 알고리즘으로 압축을 해 놓으면 이것이 암호화가 아니지만, 그 알고리즘을 모르기 때문에 압축을 풀 수 없다.

이 압축 알고리즘을 알려지지 않도록(비밀로 유지)해서 보안을 성취하는 것 역시 security by obscurity라고 볼 수 있다.

 

Embedded 장비에서 쓰는 파일시스템 중 일부 파일시스템의 Meta data format을 조금 바꾸어서, 일반적인 binwalk와 같은 firmware extractor로 정상적으로 추출되지 않도록 하는 방식도 security by obscurity라고 볼 수 있다.

[코드엔진 2018년도 공유기 펌웨어 커스터마이징 관련 발표자료]

(https://github.com/codeengn/codeengn-conference/blob/master/15/2018%20CodeEngn%20Conference%2015%2C%20%EA%B3%B5%EC%9C%A0%EA%B8%B0%20%EC%BB%A4%EC%8A%A4%ED%85%80%20%ED%8E%8C%EC%9B%A8%EC%96%B4%20%EA%B0%9C%EB%B0%9C%EC%9D%98%20%EC%9D%B4%ED%95%B4%20%5B%EA%B9%80%EC%8A%B9%EC%A3%BC%5D.pdf)

 

Google CTF 2018 - Beginner's Quest (Security by obscurity)

https://ctftime.org/task/6260

 

CTFtime.org / Google Capture The Flag 2018 (Quals) / Beginner's Quest - Security by obscurity

 

ctftime.org

2018년도 Google CTF 문제 중, Beginner's Quest 문제 셋에보면, Security by obscurity 문제가 있다.

 

압축만 되어 있는데, 압축 포맷이 다양하게 되어 있어서 각각의 압축 포맷에 대한 압축 해제를 할 수 없다면 문제를 풀어낼 수 없는 식으로 되어 있다.

 

압축에 비밀 키에 보안 의존성이 있는 것이 아닌, 압축 포맷 자체에 보안 의존성이 있는 것이다.

역사

<wiki의 history 탭을 번역을 해 보았는데 좀 이상합니다. 불완전한 내용이므로 접은 글 처리합니다.>

더보기

Security by obscurity는 자물쇠공 알프래드 찰스 홉스라는 사람을 상대하기 위해 사용되었었다. 찰스 홉스는 1851년에 대중들에게 최첨단 자물쇠도 쉽게 따버릴 수 있다는것을 몸소 보여준 사람이다. "자물쇠 설계의 보안 결합을 노출하면 범죄자에게 더욱더 취약해질 수 있다"라는 우려에 대해서 그는, "도둑들은 해당 부분에 대해 매우 열심히며, 우리가 알고 있는 것 보다 이미 더 많은 것들을 알고 있다"라고 말했다.

 

Security through obscurity에 대한 공식적인 문헌은 매우 부족하다. 예를들어서 보안공학에 관한 책은 1883년 부터 kerckhoffs의 교리를 계속 인용하는데, 예를 들어서 핵 명령 통제를 비밀로 해야 할지 개방해야 할지에 대한 토론에서:

 

우발적인 전쟁의 가능성을 줄이는 것이 핵 명령 통제 기술을 비밀로 두는 것 보다 더 중요하다. 이는 Kerchkhoffs의 교리의 현대적인 재해석에 해당하며, 보안 시스템은 구조를 모호하게 두는 방식이 아닌 키에 의존해야 한다. 라고 말했다.

(의역을 해보자면, 핵 기술을 비밀로 두는 것 보다, 전쟁의 가능성이 더 중요하다는 것인데, 핵 기술을 공개를 하면 서로 핵을 갖기 때문에 서로 조심하게 되어 전쟁의 가능성이 줄어든다 그런 이야기를 하는 것 같아요)

 

법학분야에서 Peter Swire는 "모호함을 통한 보안은 환상", "느슨한 입술이 배를 가라 앉히는" 군사 개념과, 어떻게 경쟁이 인센티브를 공개하게 만드는지에 대한 상충관계에 대한 글을 썼다. (security by obscurity가 구현한 내용들을 비밀로 두는 것으로 보안을 성취하는 것인데, 공개 경쟁을 하기 위해서는 이러한 구현 내용들을 공개해야 한다는 것. 즉 security by obscurity에 반대하는 내용인 것 같습니다.)

비판

Security by obscurity만 가지고 보안성을 담보하는 것은 추천되지 않고, 표준정책에도 좋지 않습니다. 미국의 NIST에서는 이 방식의 보안에 대해 반대되는 의견을 내고 있으며 이는, "시스템 보안은 구현이나 컴포넌트의 비밀성에 의존하면 안됩니다."라는 문구로 대변됩니다.

이 방식의 보안은, security by design(설계에 의한 보안)과 open security(공개 보안)과 대조지만, 실제 프로젝트들은 이러한 전략들을 모두 사용하곤 합니다.

Reference

https://en.wikipedia.org/wiki/Security_through_obscurity

+ Recent posts