Processing math: 100%
728x90

RGB 대신 BGR을 쓰는 이유

1: 사진, 영상에서는 당연히 RGB 순서로 사용하는데 CV에서는 왜 BGR을 사용할까?

 

구글링을 했더니  사타야 말릭 박사(Dr. Satya Mallick) 의 글을 찾을 수 있었습니다. 
본문을 요약하면 사타야 말릭 박사는 한 컨퍼런스에서 OpenCV의 창시자인 그레이 브라드스키 박사(Dr. Gray Bradski)를 만났고 그에게 왜 RGB가 아닌 BGR을 쓰냐고 물었고 그에 대한 대답은 “왜 미국 철도 표준이 4피트 8.5 인치 인가?”라는 질문으로 되돌아 왔다고 합니다. 
이게 무슨 말이냐면 미국이 철도 표준을 정할때 무슨 대단한 이유가 있어서 4피트 8.5인치로 정한것이 아니라 열차 이전에 주로 사용했던 마차의 폭에 마춰서 정했다는 겁니다. 결국, 브라드스키 박사도 BGR로 정한데는 별다른 이유가 있던게 아니라 그걸 정하던 시절 초창기 카메라 산업 개발자들이 BGR을 많이 썼기 때문에 그 자신도 그냥 아무 생각없이 BGR을 선택했다는 거죠.
 

2: 그럼 왜  영상 기기 개발자들 사이에서는 RGB보다 BGR을 많이 사용했을까?

 
이는 엔디안(Endianness)와 관련이 있습니다.
CPU에 따라서 값을 메모리에 저장하고 읽을 때,  MSB 즉 큰 값을 먼저 쓰는 빅엔디안과 LSB 즉 작은 값을 먼저 쓰는 리틀엔디언 방식이 있는데, 인텔에서 만든 x86계열의 CPU는 리틀엔디언을 따릅니다.
(OpenCV는 인텔에서 시작)
 
예를 들어 0x123456이라는 값을 빅엔디언으로 저장하면 0x123456 순으로 저장되지만 리틀엔디언으로 저장하면 0x563412순으로 저장되게 됩니다.
BGR 포맷으로 이루어진 색상 정보는 각 채널당 8비트로 이루어 지고 3개의 채널을 사용하므로 24비트 즉, 0xBBGGRR가 필요합니다.  24비트 단위의 입출력은 효과적이지 않으니 메모리에 저장할때 unsigned 32비트를 사용하는것이 일반적인데 이렇게 되면 0x00BBGGRR 가 됩니다. 이 값을 x86 계열의 CPU 처럼 리틀엔디언을 사용해서 저장하면 메로리에는  0xRRGGBB00가 저장됩니다.

 

이렇게 저장된 값을 메모리에 직접 접근해서 읽어 들이는 디스플레이 장치, 카메라 등의 영상 하드웨어에서는 CPU와 무관하게 지정된 엔디안으로 앞에서 부터 읽어 들이면 자연스럽게 RGB로 읽히기 때문에 BGR 포맷이 초창기 영상 기기 관련 하드웨어 개발자들에게 자연스레 널리 사용되었다고 볼 수 있습니다.
BGR 포맷과 엔디안과의 관계에 대한 추가적인 의견은 아래의 스택오버플로우 링크에서도 보 실 수 있습니다.
 
728x90
728x90

 

파이썬 + 셀레니움을 활용한 크롤링 (나사이미지)

https://eol.jsc.nasa.gov/SearchPhotos/photo.pl?mission=ISS068&roll=E&frame=41445 

 

 

Astronaut Photo ISS068-E-41445

Spacecraft nadir point: 17.8° S, 71.2° W Photo center point: Photo center point by machine learning: Nadir to Photo Center: Spacecraft Altitude: 226 nautical miles (419km)

eol.jsc.nasa.gov

 

 

0) Selenium 간단 설명

https://selenium-python.readthedocs.io/getting-started.html

 

 

 

1) 준비물

1 :  크롬드라이버

자신에 맞는 드라이버 다운로드 : https://chromedriver.chromium.org/downloads

내가 쓰는 크롬 버전 확인 : 크롬 우측 상단 점3개 > 설정 > 크롬정보

 

 2 :  작업용 폴더

바탕화면에 작업용 폴더 만들고 드라이버를 그 폴더에다가 넣어준다.

 

3: 셀레니움 설치

pip install selenium

 

 

2) 코드작성

1: 임포트하기 

from selenium import webdriver # 웹열때
from selenium.webdriver.common.keys import Keys # 키 가져오기용
from selenium.webdriver.common.by import By # Xpath이용
import time # 슬립걸때 사용
import urllib # 다운로드

 

 

2: 코드 생각해보기 

 

# 41445 번부터 41558번 까지 다운받고싶음 
# https://eol.jsc.nasa.gov/SearchPhotos/photo.pl?mission=ISS068&roll=E&frame=41445 여기에 들어가서
# 큰 화소수 다운 받아야함   => class="btn btn-light" 버튼 눌러서 모달창 띄우기 
# 모달창에서 이미지주소 긁어서 urllib으로 다운로드함 

# 다운받았으면 페이지 번호 1올려야함 => num += num을 반복 -> while문 써야함

 

 

눌러야하는 부분 xpath 확인하기

 

# 41445번째 xpath : //*[@id="wrap"]/div/div/div[4]/div[1]/a[1]

# 41446번째 xpath : //*[@id="wrap"]/div/div/div[4]/div[1]/a[1]

각 페이지별 고화소 픽셀 위치선택하는 xpath는 동일함

 

# 41445번째 xpath : //*[@id="myModal1"]/div/div/div[2]/img
# 41446번째 Xpath : //*[@id="myModal1"]/div/div/div[2]/img   

각 페이지 모달창에 뜬 사진의 xpath가 동일함

=> Xpath 고정값으로 두고 페이지의 num만 바꾸면 됨

 

 

 

 

3: 코드 작성해보기

# 41445 번부터 41558번 까지 다운받고싶음 
# https://eol.jsc.nasa.gov/SearchPhotos/photo.pl?mission=ISS068&roll=E&frame=41445 여기에 들어가서
# class="btn btn-light" 버튼 눌러서 모달창 띄우기 
# 모달창에서 이미지주소 긁어서 urllib으로 다운로드하기 
# 41445번째 xpath : //*[@id="myModal1"]/div/div/div[2]/img
# 41446번째 Xpath : //*[@id="myModal1"]/div/div/div[2]/img   xpath는 동일하니 num만 바꾸면 되겠네?
# 다운받았으면 num += num을 반복 -> while문 써야함


# 초기번호 페이지번호설정 

num = 41445  # 명시적으로 page_num으로 하는게 좋으나 간단하게 num으로 설정해둠

#화면열기
driver = webdriver.Chrome() # while 안에 넣어버리면 계속 새창이 뜸


while num < 41559 :
    print(num)

    # 다운받을 화면
    driver.get('https://eol.jsc.nasa.gov/SearchPhotos/photo.pl?mission=ISS068&roll=E&frame={0}'.format(num))
    time.sleep(2.1)
    print("화면열기 성공", num)

    # 화소선택버튼 찾기
    search = driver.find_element(By.XPATH, '//*[@id="wrap"]/div/div/div[4]/div[1]/a[1]')
    search.click()
    print("화소선택 버튼 누리기 성공", num)

    # image 주소 가져오기
    img_url = driver.find_element(By.XPATH, '//*[@id="myModal1"]/div/div/div[2]/img' ).get_attribute('src')
    print("주소 가져오기 성공", num)

    # image 다운로드
    urllib.request.urlretrieve(img_url, str(num)+'.png')
    print("다운로드 성공", num)
    time.sleep(5) #다운받는 시간 확보
    num = num + 1
 
    print(num)

 

 

다음에는 24장 모아서 1초짜리 영상으로 자동화 해봐야겠다

24fps 영상 자동화

 

728x90
728x90

원리:
인터넷이 가능한 블랙박스로 자동신고

조건 :
1. 차량안에 네트워크 구축
2. 국민신문고 DB접근 api 필요
3. 자동신고 어플
4. 관련 처벌법안 필요
5. 80km/h 이상 주행 가능시 해당 조건 유효

실행:
1차로 주행시 정속주행 차량이 있다면:
- 일정 거리를 두고 왼쪽 깜빡이
- 녹화실행
- 1분이상 비키지 않는다면 녹화저장
- API를 통해 국민신문고 DB로 쏘기





728x90
728x90

https://missing-semester-kr.github.io/2020/version-control/

1. Untracked :  인지는 했지만 관리는 안함  or 관리 목록에서 내림

2. Tracked 

  • Unmodified (수정된 상태가 아닌)
  • Modified (수정된 상태)
  • Staged 

 

 

 

 

첫 상태 : 인지는 했지만 관리는 안함  [U]

 

 

 

 

Readme.md -> "add . readme.md" -> staged 상태로 [A]

 

 

 

 

 

 

commit -> unmodified 상태 [흰색상태]

 

 

파일 수정-> modified 상태 [M]

 

git commit 다시하면 다시 unmodified 

 

 

 

git log 깃로그 (자주 쓰는 옵션 --oneline -- graph)

 

 

 

 

터미널 편하게 쓰기 + 

 

1. terminal > cnt + r > i search  + 검색어 :  썻던 코드중 에서 검색 찾아줌

 

 

2. 단축키 설정 : 

  • 1. profile 폴더생성
    • (win) touch ~/.bash_profile 
    • (mac) touch ~/.zsh_profile 
  • 2. profile 열기 
    • (win) code ~/.bash_profile
    • (mac) open ~/.zsh_profile 
  • 3. 단축키 등록 ( 맥 oh-my-zsh 이미 설치했다면 아마 등록 되있음)
    • alias gl = 'git log --oneline --graph'
    • alias jn = 'jupyter notebook'

 

 

 

 

 

 

728x90

'협업툴 > [GIT]' 카테고리의 다른 글

[GIT] .gitignore 활용법  (0) 2023.01.17
728x90

 

1.  1:1 관계

결혼관계테이블 : 남자 1 , 여자 1

사원증테이블 : 사원번호 1, 사원 1

주민등록번호테이블 : 번호 1, 사람 1 

  • 하나의 레코드가 다른 테이블의 레코드 한 개와 연결된 경우이다.

 

 

 

2.  1:N 관계

 

: (나의)게시글 테이블

유저 1명, 게시글 N개

 

: (나의)강의테이블

학생 1명, 강의 N개 

 

: (카트속) 아이템

 

: (게시글에) 댓글

 

: 나라의 정부기관

 

 

 

이런식으로 테이블 2개를 활용해서 표현 가능함

 

 

 

 

 

 

3.  N: M 관계

https://docs.djangoproject.com/en/4.1/topics/db/examples/many_to_many/ 

 

https://cloudstudying.kr/lectures/501

Q: 수강신청 테이블을 만들려고 한다 어떻게 하면 좋을까?

과목에는 성과 사랑, 통계물리 수업이 있고, 5명이 수업을 들을려고 한다.

  성과 사랑 통계물리
홍길동 V --
김철수 -- V
손흥민 -- V
리처드파인만 -- V
아인슈타인 -- V

라고 만들면 -- 빈칸이 생기게 된다 -> 무결성 위배 (유저와, 과목테이블을 관계활용한 수강신청이라는 테이블을 하나 더 생성해야함)

 

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

N:M 관계 예시

 

: 좋아요 테이블(게시글 테이블과 비교)

좋아요는 여러명이 누름, 한 사람은 여러개의 좋아요 가능

하트는 여러개의 게시글에 들어간다,  

어떤 게시글인지, 어떤 유저 눌렀는지

 

: 대여테이블

책은 여러명에게 대여가능, 한 사람은 여러개 책 예약가능

어떤 책인지, 어떤 사람인지

 

: 수강신청테이블 (강의 테이블과 비교)

수강은 여러명에게 등록가능, 한 사람은 여러개 강의 등록가능

어떤 강의인지,  어떤학생이 듣는지 

 

 

: 좋아요 버튼 

 

: 투표

 

728x90
728x90

 

.gitignore 왜 필요한가?

git에 올라가면 안될 중 DB 정보나 KEY 등과 같은 중요한 정보나 , 깃관리가 필요없는 데이터를 사전에 무시하기 위해사용함 

 

 

1. .gitignore 파일 생성

touch .gitignore  # 보통 프로젝트 만들때 가장 먼저 만듬

 

 

2.  .gitignore 작성 (중요파일)

만든 .gitignore을 열어서 무시할 파일 이름을 넣으면 끝

중요한 정보가 secret.txt에 있다.
.gitignore에서 파일이름을 넣으면 끝

 

 

2-1.  .gitignore 작성 (중요폴더)

만약에 폴더 전체를 ignore 하고싶다면?!

**/Directory명/ 을 적어주면 끝

 

 

3. .gitignore 작성 (불필요파일)

 

gitignore.io

자신이 쓰는 운영체제, 개발환경, 프로그래밍언어를 넣어주면 알아서 만들어줌

 

 

 

 

 

이렇게 나오면 ctrl + A , ctrl + C 해서 .gitignore 폴더에 붙여넣기 

 

 

 

 

 

 

728x90

'협업툴 > [GIT]' 카테고리의 다른 글

[GIT] 버전관리 + 터미널 편하게 쓰기  (0) 2023.01.19
728x90

http://raccoonyy.github.io/django-annotate-and-aggregate-like-as-excel/

 

(엑셀만큼 쉬운) Django Annotation/Aggregation

Django ORM을 강력하게 만들어주는 기능 중 하나는 바로 애너테이션(annotate)과 애그리게이션(aggregate)입니다. 이 두 기능이 명쾌하게 와닿지 않아서 사용하지 못하다가, 엑셀에 빗대어 이해해보니

blog.raccoony.dev

 

 

https://docs.djangoproject.com/en/4.1/ref/models/querysets/

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

1:1

1:N  (=N:1)

N:N 구분해서 공부하기

728x90
728x90

 

이전 Signup에는 Default User를 사용함 이번 버젼은 User를 커스텀하겠음

 

 

결과적으로 이것만 추가됨

 

from django import forms
drom django.contrib.auth.forms. import UserCreationForm
from django.contrib.auth import get_user_model # user 정보 알아서 빼주는 함수

# models.py 에서 Foreignkry가 user 일때만 세팅스.어스_유저_모델
# accounts/urls.py
from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    mbti = models.CharField(max_length=4)
    # 아무값 채워넣으면 됨
    # 아무값 채워넣으면 됨



# Settings 맨밑에다 이거 추가
AUTH_USER_MODEL = 'accounts.User'

 

https://docs.djangoproject.com/en/4.1/topics/auth/default/ 

 

 

 

 

 

 

1:N 관계

User-table 하나에서 여러개의 Question-table, 여러개의 reply-table 생성가능

User-table : Question-table = 1 : N

User-table : reply-table.      = 1 : N

 

Question-table : reply-table = 1:N

 

 

<User-table>

id(seq) username password mb

  ti
1 홍길동 1234  
2 민수 123  
3 민아 1234  

<Question-table>

id(seq) Question user_id
1 오늘의 메뉴는? 1
2 오늘 날씨는? 2
3 내일 뭐하지? 3

<reply-table>

id 내용 Que_id user_id
1 햄버거 1(오늘메뉴는?) 3 (민아)
2 맑음 2 1 (홍길동

 

 

 

 

 

 

728x90
728x90

https://itcreator.tistory.com/129

이어서 하기

 

이전버전은 USER는 DB를 만들지 않아도 따로 생성되었음 (물론 커스터마이징 가능하지만 그건 나중에)

이번은 이전설정과 거의 비슷하게 한번 더 앱을 만들어 보고 게시판/댓글 DB 까지 다뤄보기

 

1.  기초설계

1. ctrl + shift + ~ 터미널 창 열어주기

2. board 앱 폴더 생성 및 등록

# root 기준  터미널 명령어

python manage.py startapp <app 이름>

mkdir -p <app 이름>/templates/<app 이름>  # 템플릿 생성

cd  <app 이름>/templates/<app 이름>  # 최하단 까지 이동

touch detail.html form.html index.html

#detail 게시판글 자세히보기  
#form 게시판 작성 폼
#index 게시글 리스트

 

3. urls.py 및 forms.py 생성

# 다시 최상단 으로 돌아와서( 보통 cd .. 3번 하면됨)

Touch <app이름>/urls.py    # (..../<app이름> 으로 들어오는 통로 열어주기)

Touch <app이름>/forms.py   

# Form 이 친구는 왜만드는거임?
   # 1. 유효성 체크 (validation check)
   # 2. HTML 안에 인풋태그 만들기 귀찮 
   # 3. 저장할 때 request.POST에서 일일이 꺼내기 귀찮아서
   # 이런 작업을 Form 하게 만들려고 미리 폴더 생성

 

2.  board  > urls.py 세팅해주기    (앱이름을 board 로 할 경우)

from django.urls import path
from . import views

app_name = 'board'
urlpatterns = [
    # articles/create/
    path('create/', views.create_article, name='create_article'),    # url에 articles/create/으로 접근이 온다면 => views 에 있는 create_article 함수 실행 / 그리고 이 과정을 create_article 이 라고 칭하겠다. 
    # articles/
    path('', views.article_index, name='article_index'),
    # articles/1/
    path('<int:article_pk>/', views.article_detail, name='article_detail'),
    # articles/1/update/
    path('<int:article_pk>/update/', views.update_article, name='update_article'),
    # articles/1/delete/
    path('<int:article_pk>/delete/', views.delete_article, name='delete_article'),

 

 

3. Model 단 (board > models.py)

from django.db import models
from django.conf import settings

class Article(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) # settings.AUTH_USER_MODEL 파이썬이 이렇게 써달래
    title = models.CharField(max_length=100)									# on_delete=models.CASCADE 이게 지워지면 안에 다른것도 다 지워달라 
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

class Comment(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    content = models.CharField(max_length=200)
    # foreign key 쓰면 필드명에 _id 붙이지 않기.
    # migrate 하면 알아서 뒤에 _id가 붙음
    article = models.ForeignKey(Article, on_delete=models.CASCADE)
    Created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

 

 

3-1 . Form 단 (board > forms.py)

from django import forms
from .models import Article, Comment
class ArticleForm(forms.ModelForm):
    
    class Meta:
        model = Article
        #fields= '__all__'
        exclude = ('user',) # user는 Article의 FK라 article테이블의 user의 키가 
        					# User테이블의 pk값이 없는걸 넣을려고 하면 DB에서 막음 (무결성)
       
class CommentForm(forms.ModelForm):
    content = forms.CharField(min_length=2, max_length=200,
    widget=forms.TextInput(attrs={'autofocus': True})
    )
    class Meta:
        model = Comment
        # fields = ('content',)
        exclude = ('article', 'user')

model. form 끝냈으면 마이그레이트 시작

python manage.py makemigrations board

python manage.py migrate board

 

 

4. Control 단 (board > views.py)

1. 쉬운 버전용 필요한 클래스 import 하기

# 화면구성, 화면이동, 객체를 받거나 없으면 404에러를 터트려줌 (이거 없으면 서버 문제가 아닌데도 500 서버단 에러를 터트림)
from django.shortcuts import render, redirect, get_object_or_404

# get, post등 url 접근 방식에 따라 분류해서 허용하겠다
from django.views.decorators.http import (require_http_methods, require_POST, require_safe, )

# 로그인 상태에만 해당 함수 실행가능
from django.contrib.auth.decorators import login_required

# DB 불러오기
from .models import Article, Comment

# 앞서 만듬 form 불러오기
from .forms import ArticleForm, CommentForm

 

2. create_article 작성

@login_required  # 로그인이 되어야 이 작업가능
@require_http_methods(['GET', 'POST'])  # GET, POST로 들어오는 경우
def create_article(request):   #request 요청 받은 정보 전부 인수로 전달한뒤 함수 실행
    
    if request.method == 'POST': # POST라면(게시글 등록버튼 누를때)
        form = ArticleForm(request.POST) # POST로 쏘는 내용물 채워서 form에 저장
        if form.is_valid():  # 값이 유효하다면
            article = form.save(commit=False) # 잠깐 저장은 하지말아봐  # article부터 만들어야하는데 save를 하면 오류터짐
            article.user = request.user  # 페이징 요청자의 정보를 글작성자의 정보로 넣어줌
            article.save()  # 게시글 저장(내장함수)
            return redirect('board:article_detail', article.pk)   # 글번호와 함께 detail() 함수실행

    else:   # GET으로 왔다면(페이지를 요청할때)
        
        form = ArticleForm()   # form.py에서 만든걸 form으로
    context = {'form': form }    # context에 담아서 
   
    return render(request, 'board/form.html', context)  # form.html로 넘겨줌

 

3. read

@require_safe # get, head 요청만 허용하겠다.
def article_index(request):
    articles = Article.objects.all()   # DB의 article의 모든 값을 articles에 넣어줌
    context = {'articles': articles, }   # 그걸 context에 담아서
    return render(request, 'board/index.html', context)   # index.html로 넘겨줌

@require_safe
def article_detail(request, article_pk):   # 몇번째 게시글인지 알 수 있게 article_pk 받아야함
    article = get_object_or_404(Article, pk=article_pk)  # db에서 객체를 받던가 404를 띄워라! why? DB에 없는걸 요청한다면 니 잘못
    form = CommentForm() # 댓글보여줄려고-> detail.html에 board/_comment_form.html에 form 쓸려고
    context = {     # 게시글 정보와 댓글을 context에 담아서
        'article': article,
        'form': form
    }
    return render(request, 'board/detail.html', context)   # detail.html로 보냄

 

4. update

@login_required  # 로그인 필요
@require_http_methods(['GET', 'POST'])   # GET, POST로 오는 경우
def update_article(request, article_pk):
    article = get_object_or_404(Article, pk=article_pk)   # 받은 번호의 게시글 정보를 DB에서 찾아 article에 넣어줌
   
    if request.user != article.user:			 # 작성자 아니면
        return redirect('board:article_detail', article.pk)    # 게시글 번호와함께 detail.html로 보내버림

    if request.method == 'POST':   # POST인 경우(게시글 수정 버튼을 누를때)
        form = ArticleForm(request.POST, instance=article)  # instance=student 가 없으면 수정이 아니라 새 값으로 저장되어버림 + 이전정보 넣어주기
        if form.is_valid():  # form이 유효하다면
            # 기존에 저장된 user_id 갱신할 필요가 없기때문에 commit=False 필요 X
            article = form.save()   # 저장해서 article에 넣어주기
            return redirect('board:article_detail', article.pk)   # 게시글 번호 주면서 detail() 함수실행
    else:   # get방식이라면 (이 페이지를 요청할때)
        form = ArticleForm(instance=article)   # # instance=student => form에다가 이전 정보 넣기
    context = {'form': form}   # context에 담아서
    return render(request, 'board/form.html', context)   # form.html로 보냄

 

5. Delete

@login_required   # 로그인 필요
@require_POST   # POST인 경우(url로 들어오는거 막겠다/ 제출버튼으로 토큰 던지면서 와라)
def delete_article(request, article_pk):  # 요청받은 정보와 게시글 번호를 주면서
    article = get_object_or_404(Article, pk=article_pk)  # 번호에 맞는 Article DB에서 객체를 꺼내서 article에 주던가 404로 
    if request.user == article.user:   # 요청자와 글쓴이가 같다면 
        article.delete()   	# 게시글 삭제(내장함수) 
        return redirect('board:article_index')   # index로 보내주기
    else:     # 요청자와 글쓴이가 같지않다면
        return redirect('board:article_detail', article.pk)  # 게시글 번호와함께 detail.html로 보냄

 

6. 댓글 (간단하게 CRD만)

@require_POST
def create_comment(request, article_pk):  # 요청 정보와 게시글 번호를 받음
    form = CommentForm(request.POST) # 댓글 제출 버튼시 값들을 form에 넣어줌 
    article = get_object_or_404(Article, pk=article_pk) # 받은 번호의 게시글 정보를 DB에서 찾아 article에 넣어줌

    if form.is_valid():  # form이 유효하다면
       
        comment = form.save(commit=False)    # 완전 저장시 NOT NULL 에러 뜨니까, 직전에 멈춰 주세요.
        comment.article = article       # 여기선 알아서 값 넣어줌
        comment.user = article			 # 여기선 알아서 값 넣어줌
        comment.save()		# 값 저장(내장함수)
    return redirect('board:article_detail', article.pk)  # 게시글 번호 받아서 detail() 함수 실행 
    # comment.article.pk 게시글 번호임

@require_safe # get, head 요청만 허용하겠다.
def article_index(request):   # 요청한값 받음
    articles = Article.objects.all()  Article DB 값 받아서 articles에 넣어줌
    context = {'articles': articles, }   # 그 값을 context 넣고
    return render(request, 'board/index.html', context)  # index.html로 보내줌

@require_safe
def article_detail(request, article_pk):   # 요청정보와 게시글 번호 받음
    article = get_object_or_404(Article, pk=article_pk)  # 받은 번호의 게시글 정보를 DB에서 찾아 article에 넣어줌
    form = CommentForm() # 댓글보여줄려고-> detail.html에 board/_comment_form.html에 form 쓸려고
    context = {
        'article': article,
        'form': form
    }
    return render(request, 'board/detail.html', context)


@login_required
@require_POST
def delete_comment(request, article_pk, comment_pk):
    comment = get_object_or_404(Comment, pk=comment_pk)
    article = get_object_or_404(Article, pk=article_pk) # article.pk 를 쓰기위해서 만듬
    
    if request.user == comment.user:
        comment.delete()
    return redirect('board:article_detail', article.pk)
    
    # article_pk 안쓰는 이유는 사용자를 믿을수없어서.
    # 사용자가 보낸거 _pk 구분한다음  내부적으로 확인해서 믿을하면 .pk 써도 무방

 

 

총정리

@login_required
@require_http_methods(['GET', 'POST'])
def create_article(request):
    
    if request.method == 'POST': 
        form = ArticleForm(request.POST) 
        if form.is_valid():
            article = form.save(commit=False)
            article.user = request.user 
            article.save()
            return redirect('board:article_detail', article.pk)

    else: 
        form = ArticleForm()
    context = {'form': form }
    return render(request, 'board/form.html', context)

@login_required
@require_http_methods(['GET', 'POST'])
def update_article(request, article_pk):
    article = get_object_or_404(Article, pk=article_pk)
    
    if request.user != article.user:
        return redirect('board:article_detail', article.pk)

    if request.method == 'POST':
        form = ArticleForm(request.POST, instance=article)        
        if form.is_valid():
           
            article = form.save()
            return redirect('board:article_detail', article.pk)
    else:
        form = ArticleForm(instance=article)
    context = {'form': form}
    return render(request, 'board/form.html', context)

@login_required
@require_POST
def delete_article(request, article_pk):
    article = get_object_or_404(Article, pk=article_pk)
    if request.user == article.user:
        article.delete()
        return redirect('board:article_index')
    else:
        return redirect('board:article_detail', article.pk)



@require_POST
def create_comment(request, article_pk):
    form = CommentForm(request.POST)
    article = get_object_or_404(Article, pk=article_pk)

    if form.is_valid():
      
        comment = form.save(commit=False) 
       
        comment.article = article
        comment.user = article
        comment.save()
    return redirect('board:article_detail', article.pk)
  

@require_safe 
def article_index(request):
    articles = Article.objects.all()
    context = {'articles': articles, }
    return render(request, 'board/index.html', context)

@require_safe
def article_detail(request, article_pk):
    article = get_object_or_404(Article, pk=article_pk)
    form = CommentForm() 
    context = {
        'article': article,
        'form': form
    }
    return render(request, 'board/detail.html', context)



@login_required
@require_POST
def delete_comment(request, article_pk, comment_pk):
    comment = get_object_or_404(Comment, pk=comment_pk)
    article = get_object_or_404(Article, pk=article_pk)
    
    if request.user == comment.user:
        comment.delete()
    return redirect('board:article_detail', article.pk)

 

728x90
728x90

 https://itcreator.tistory.com/125 를 보고 이 글을 진행하는게 이해가 쉬움 

 

시작하기전에 협업할때 편한 가상화 작업

 

1. ctrl + shift + ~ 터미널 창 열어주고 가상환경설정하기

 

python -m venv <env name> # 가상환경
# Venv 안뜨면 ctrl/command + shift + p 로 인터프리터 열어서 <env이름> 직접 선택

# 수동
(Mac) source venv/bin/activate
(Win) source vent/Scripts/activate
pip install django==3.2.16 django_extensions

pip list  # 상태확인

touch README.md .gitignore # READ, gitignore 사전작업

pip freeze > requirements.txt  # 협업 세팅환경용


# 3.2.16버전이 롱텀이라 안전성높음

 

 

1. 회원가입에 필요한 기초설계

1. account 앱 폴더 생성 및 등록

# root 기준  터미널 명령어

python manage.py startapp <app 이름>

mkdir -p account/templates/account  # 템플릿 생성

cd  account/templates/account  # 최하단 까지 이동

touch login.html signup.html     # html 생성

 

2. urls.py 생성 (..../<app이름> 으로 들어오는 통로 열어주기)

# 다시 최상단 으로 돌아와서( 보통 cd .. 3번 하면됨)

Touch <app이름>/urls.py    # url 이동 잡아주기

 

2.  accounts  > urls.py 세팅해주기    (앱이름을 accounts로 할 경우)

from django.urls import path
from . import views

app_name = 'accounts'

urlpatterns = [
    # accounts/signup/
    path('signup/', views.signup, name='signup'),   # url에 accounts/signup/으로 접근이 온다면 => views 에 있는 signup 함수 실행 / 그리고 이 과정을 signup 이 라고 칭하겠다. 
    # accounts/login/
    path('login/', views.login, name='login'),
    # accounts/logout/
    path('logout/', views.logout, name='logout'),

]

 

3. Control 단 (accounts > Views.py)

1. 쉬운 버전용 필요한 클래스 import 하기

# 화면구성, 화면이동, 객체를 받거나 없으면 404에러를 터트려줌 (이거 없으면 서버 문제가 아닌데도 500 서버단 에러를 터트림)
from django.shortcuts import render, redirect, get_object_or_404 

# DB 생성없이도 account에 필요한 컬럼을 만들어줌, 인증에 필요한 옵션
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm

# 세션을 부여하거나 수거함 (출입증)
from django.contrib.auth import login as auth_login, logout as auth_logout

# get, post에 따른 
from django.views.decorators.http import require_http_methods

 

2. 가장 먼저 signup 함수채우기 

@require_http_methods(['GET', 'POST'])   #GET, POST 요청만 받겠다
def signup(request):   #request 요청 받은 정보 전부 인수로 전달한뒤 함수 실행
    if request.method == 'POST':  # 회원가입 신청서 제출시 작동
        form = UserCreationForm(request.POST)  # user 의 경우 Model괴 Form도 자동으로 해줌 /import만 잘하면됨
        if form.is_valid():   # 내장 검증함수실행 / False 시 13번부터 실행
            user = form.save()   # 유저가 입력한 정보 DB에 저장
            auth_login(request, user) # 회원가입하고 바로 세션부여 채워줌 
            return redirect('board:article_index')   # 바로 게시글 볼 수 있게 리다이렉트해줌
    
    else:   # get으로 온 경우 
        form = UserCreationForm()   # 회원가입 폼
        
    context = {'form': form }  # 폼을 context에 담아서 
    return render(request, 'accounts/signup.html', context)   #받은 정보들을 바탕으로 signup.HTML 화면 구성

3. login 함수 채우기

@require_http_methods(['GET', 'POST'])  # get과 포스트만 받겠다
def login(request):
    if request.method == 'POST':  # POST인 상황 즉 아이디 / 비번 넣고 로그인 버튼 눌렀을때 실행
        form = AuthenticationForm(request, request.POST) # 인증폼은 다른 폼과 인자 구성이 다름 / 지금은 request 인수를 던지는 이유에 대해선 넘어가기로.. 
        if form.is_valid():
            user = form.get_user()  # 이 유저가 누군지 알려줌
            auth_login(request, user ) # 받은 유저정보를 주면 입장 팔찌를 채워줌 파이썬에서 제공해주는 함수 (임포트해야함) 
           #  None/ URL string 들어가있음
            next = request.GET.get('next') # 다른곳에서 튕겨서 온 사람들 /? 이후 URL을 request.GET으로 받음 .get은 값이 없더라도 none으로 받음  
            return redirect(next or 'board:article_index') # next 가 false 면 index로 보내고/ next가 true 면 next 값으로 이동  
    else:  #  GET인 상황 로그인 페이지를 들어오는 상태라면
        form = AuthenticationForm()   # 내장함수를 form으로 받고
    context = {'form': form}   # 내장함수에 받은 내용을 context에 담아 보냄
    return render(request, 'accounts/login.html', context)

4. logout 함수채우기

def logout(request):
    auth_logout(request) # 세션을 지움
    return redirect('board:article_index')  # 게시글 있는곳으로 다시 리다이렉트

 

 

 

 

< 총 정리하자면 >

from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import login as auth_login, logout as auth_logout
from django.views.decorators.http import require_http_methods

@require_http_methods(['GET', 'POST'])
def signup(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)  
        if form.is_valid():
            user = form.save()
            auth_login(request, user) 
            return redirect('board:article_index')
    else:
        form = UserCreationForm()

    context = {'form': form }
    return render(request, 'accounts/signup.html', context)


@require_http_methods(['GET', 'POST'])
def login(request):
    if request.method == 'POST':
        form = AuthenticationForm(request, request.POST) 
        if form.is_valid():
            user = form.get_user()  
            auth_login(request, user ) 
           
            next = request.GET.get('next')
            return redirect(next or 'board:article_index') 
    else:
        form = AuthenticationForm()
    context = {'form': form}
    return render(request, 'accounts/login.html', context)

def logout(request):
    auth_logout(request)
    return redirect('board:article_index')

 

 

https://itcreator.tistory.com/130

2탄 게시판 및 댓글 쉬운버젼 (DB가 추가됨)

 

[Django] Board/comment 게시판/댓글 쉬운버젼

https://itcreator.tistory.com/129 이어서 하기 이전버전은 USER는 DB를 만들지 않아도 따로 생성되었음 (물론 커스터마이징 가능하지만 그건 나중에) 이번은 이전설정과 거의 비슷하게 한번 더 앱을 만들

itcreator.tistory.com

 

728x90
728x90

1.  Project 폴더 / 앱 설정

 

1. 프로젝트 폴더 생성 과 동시에 manage.py 파일을 만듬.

django-admin startproject  <project 이름> . (뒤에 . 찍어야 현재 폴더 위치에서 생성됨)

2. 그 프로젝트 안에 구성할 앱들 만들기

python manage.py startapp <app 이름>

 

 

2.  가상환경 설정 

메인폴더에서 

python -m venv <env name> # 가상환경



(Mac) source venv/bin/activate

(Win) source vent/Scripts/activate

 

Command + Shift + p > 인터프리터 선택 > 가상환경 선택

venv 가 안떠있으면 터미널 껏다 켜기

READ.md , .gitignore, requirements 생성

pip install django==3.2.16 django_extensions

pip list  # 상태확인

touch README.md .gitignore # READ, gitignore 사전작업

pip freeze > requirements.txt  # 협업 세팅환경용


# 3.2.16버전이 롱텀이라 안전성높음

 

 

3. 뼈대잡기 

사용할 html의 뼈대를 잡음

 

1. 공통적으로 활용할 html 생성

Project > templates > base.html or navbar.html 등등 (include용 메인 html)

install -Dv /dev/null template/base.html

#   (mkdir templates >  touch templates/base.html을 한번에)

 

2. 앱에서 사용할 html 생성

Mkdir -p <app이름>/templates/<app이름>  # -p 는 templates 라는 상위폴더가 없어도 상위폴더까지 같이 생성해줌

cd <app이름>/templates/<app이름>  # cd로 최하단까지이동

touch **.html **2.html **3.html (사용할 html 쭉 나열하면 여러개 생성)

 

 

 

3. 기타 .py 파일 생성

# 다시 최상단 으로 돌아와서( 보통 cd .. 3번 하면됨)

Touch <app이름>/urls.py, forms.py 생성

4. 초기세팅

1. Project>settings에서 해야할 일

 Project > settings > app등록  

*

'django_extensions', # 추가해두면 나중에 python manage.py shell_plus 사용가능

 

 

 

 

 

 

Templates / dirs 등록 >  BASE_DIR / ‘templates’

 

 

(Project) > (App) > views.py > 함수생성

 

base.html > block > tab

 

2. Master urls.py 내용추가

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('<app이름>/', include('<app이름>.urls')),
]

 

3. app이름 >  urls.py

from django.urls import path
from . import views

app_name = '<앱이름>'

urlpatterns = [
    # <앱이름>/create/
    path('create/', views.create, name='create'),
    # <앱이름>/
    path('', views.index, name='index'),
    # <앱이름>/1/
    path('<int:student_pk>/', views.detail, name='detail'),
    # <앱이름>/1/update/
    path('<int:student_pk>/update/', views.update, name='update'),
    # <앱이름>/1/delete/
    path('<int:student_pk>/delete/', views.delete, name='delete'),
]

 

4. app이름 > views.py 세팅

함수정의 하기 

 

from django.shortcuts import render, redirect, get_object_or_404
from django.views.decorators.http import require_http_methods, require_safe, require_POST
from .models import Student
from .forms import StudentForm

@require_http_methods(['GET', 'POST'])
def create(request):
    pass
    
# CRUD에 맞는 필요함수 적기

 

 

4. 서버실행

Manage.py 있는 루트위치에서

python manage.py runserver 

# 나가기 Ctrl + C

 

5. DB 세팅

1. Model.py 작성

app > models.py  / 자바로 치면 DAO

from django.db import models

class Student(models.Model):
    name = forms.CharField(min_length=2, max_length=10)
    title = forms.CharField(min_length=2, max_length=20)

 

2. Forms.py 작성

app > forms.py

# 1. 유효성 체크 (validation check)
# 2. HTML 안에 인풋태그 만들기 귀찮
# 3. 저장할 때 request.POST에서 일일이 꺼내기 귀찮아서 forms.py 만들어서 관리
from django import forms
from .models import Student

class StudentForm(forms.ModelForm):
    name = forms.CharField(min_length=2, max_length=10)
    title = forms.CharField(min_length=2, max_length=20)
    
    class Meta:  # 이 클래스의 메타 데이터 저장용 
        model = Student
        # fields = ('name', 'title')
        fields = '__all__'

 

3. 서버시작

서버실행 (혹시 값이 바뀔면 다시 실행)

python manage.py makemigrations <app이름>

python manage.py migrate <app이름>

# 잘안되면
rm db.sqlite3 <앱이름>/migrations/0*
rm db.sqlite3 accounts/migrations/0* board/migrations/0*  
# 다 지우고다시

 

 

6. 꾸미기

pip install django-bootstrap-v5

# 장고 부트스트랩 추가
pip install django-bootstrap-v5

설명서

https://django-bootstrap-v5.readthedocs.io/en/latest/installation.html

 

728x90
728x90

What is Telemetry

Remote Measure

Third Party Monitoring

Not a new concept

 

But Doing it new way

Docker, KVM, AWS, Azure

 

 

Service Visibility is the key in cloud

  • Visibility is often accomplished via post facto application of agent-based monitoring tools
  • Agent-based monitoring tool don’t understand business value (not dynamic)
  • Determining an application’s health often requires complex logic
  • Traceability of an application is difficult( or impossible) to accomplish with OTS solutions

 

 

< 구조 >

 

텔레메트리 분류

ingest(데이터 받기) > Store(저장) > Analysis(분석) > Present(보여줌)

 

 

1. ingest 

: Prometheus for Metric

 

: fluentd for logging (또는 Apache Flume)

 

 

 

2. Store

  :  TSDB for Metric

Prometheus

  • simple
  • has its own SQL (PROMQL) : easy for use
  • no clustering or high availability

 

 

 

OpenTSDB • powerful

  • clustering and high availability
  • complicated ( based on hbase, Hadoop)

 

: key/value for logging

Elastic Search (많이 씀)

  • simple, support scale-out
  • support GUI (kibana)
  • fast, realtime support
  • DSL based search

 

3. Analysis : it’s not quite simple

 

 

Message queue: kafka

- 관리 부분을 발신/수신자에게 부담해버림

- 카프카 내부에선 큐만 관리 -> 빠를 수 밖에 없음

 

 

 

 

 

<여러 회사들의 예시>

Metric integration: kakao’s kemi stats

 

logging integration case: kemi log

 

 

Kakao’s case

728x90
728x90

여태 배운 네트워크개념 + synology nas로 뽕 뽑기

2만원짜리 알리발 카메라 20만원 짜리 CCTV 환경 만들기!

 

필요준비물 : NAS, ONVIF 카메라, 공유기

 

ONVIF 카메라는 대부분 2 - 4만원

https://s.click.aliexpress.com/e/_DknmiZz

https://s.click.aliexpress.com/e/_Dkpioll

 

* 참고로 플러그는 EU 형으로 사야 우리가 쓰는 220-230v 로 받음

또는 아답터 줌

 

 

배송 기다리기 싫다면

 

TP-link c210도 추천!
https://link.coupang.com/a/ITDsd

 

 

 

 

 

1.  시놀로지에서 패키지에서 Surveilance Station 다운로드 

2. 구글 스토어에서 smart life 어플설치 /or Tapo (TP-link의 경우)

 

3. 카메라 전원 연결하고 smart life/ Tapo 연결

(장치추가 - 카메라 및 잠금 - 스마트카메라 - 2.4GHz 입력 및 암호 - QR 코드 cctv에 비추기)

5GHz는 연결안됨 2.4로 해야함!

 

4. 공유기 게이트로 이동 172.30.1.254 또는 192.168.0.1 (iptime)

혹시 아이디 비번을 설정한 적이없다면

kt유저-> ktuser / homehub    

skt유저 -> admin / 공유기 밑에 MAC주소 뒤 6자리_admin

lg유저 -> 공유기 뒤에 적혀있음

iptime -> admin/admin

 

5. CCTV 맥주소로 내부 ip주소 찾기  

 

6. 고정 ip 할당 고정 (장치설정 - 네트워크 관리 - LAN 연결설정 ) - 장비가 재부팅 될 경우 ip가 변하는걸 방지

7. Synology - Surveilance Station 으로 들어가서 카메라 - 인터넷 - 시놀로지 연결하기

최대 2대 까지 연결 지원함! 엄청나다!

 

7- 1 TP-Link 같은경우 : 사용자 이름 / 패스워드를 설정해야함

tapo 어플 홈 화면 >> 연결된 CCTV >> 오른쪽 상단 바퀴>> 고급 설정 >> 카메라 계정 입력 후 저장 >> 시놀로지 사용자 이름/ 패스워드

 

 

 

8. Surveilance Station 녹화설정 또는 알림 설정하기

녹화설정
이벤트 감지 위치

9. 구글스토어에서 dscam 깔기 

휴대폰으로 감시 및 모션 알림 바로 받을 수 있음 / 개별 cctv 어플 모션알림은 끄는게 좋음

728x90
728x90

개발 공부를 시작하게 된 이유
1. 물리학을 공부할 때 제일 재미있던 개념은 '시간'이었다.
그놈의 t가 가지는 무서움. 어떻게 하면 시간 정복할 수 있을까? 어떤 수를 써도 시간을 제어할 수 없었고 그저 시간을 붙잡기 위해 하루를 기록하고, 시간을 아끼기 위해 단순 반복적인 일은 자동화하고 싶었다.


2. 이런 성향은 나를  어떻게든 시간을 붙잡게 만들었고, 그 결과 학창 시절부터 카메라에 빠지게 만들었다.
카메라로 찍은 사진과 영상을 보면 그때의 그 감정이 고스란히 담겨 있어 시간 여행을 하는 느낌이었고,  한번 카메라 세팅만 해주면 추운 밤 알아서 별촬영을 해주고 타임랩스로 알아서 결과물을 뽑아내주는 자동함이 주는 그 자유함은 이로 말할 수 없었다. 
작은 카메라 하나였지만 나에게 자극이 되길 충분했다.

3. 지금 생각해보니 영상 콘텐츠를 제작을 업으로 삼게 된 거는 자연스러운 일이기도 하다.
하루에 몇 번씩 카메라를 들고나가 여기저기 찍고 다니다 수 없이 저장공간을 백업하고, 보관하는 일들이 또 다른 나의 숙제로 다가왔다.
4k 422로 몇 분 남짓 찍기만 했는데 이미 몇백 기가바이트라니..
몇 장 안 되는 사진을 옮기는 게 그리 귀찮을 수 없었다. "하 백업을 자동으로 할 수 있는 방법은 없을까?"

이러한 작은 생각들이 나를 IT세상으로 가게 하였다.
인터넷만 있다면 사진을 찍자마자 내가 원하는 디렉토리로 사진, 영상을 옮기는 FTP 통신, SDcard를 꽂기만 하면 바로 백업이 되는 usb-copy, 내부망 안에서 바로 미디어 편집을 가능케 한 SMB.. NAS를 사고 나서 삶이 질이 달라졌다.
마치 한 사람을 고용한 느낌이랄까?

4. 내 나이 20 후반 이제는 경제력을 필요로 하고 조금 더 전문성을 가져야 할 필요성을 느낀다.
친형이 방송국에서 정보통신 쪽으로 일하고 있는데, 내가 보기에 방송국도 좋아 보여서 방송국 견학부터 시작해서 3개월간 방송국을 가서 업무를 익히는데.. 방송국과 나는 성향이 맞지 않다는 걸 금세 깨달았다. 그 보수적이다라는 교육직 공무원보다 더 보수적이었고, 혁신을 찾아보기 어려웠다. 보면 볼수록 점점 방송국의 미래는 어두워지는 것 같았다.

이러한 경험이 내 인생의 방향을 정하는데 큰 지표가 된 것 같다.


개발 공부를 해야 하는 이유
1. 우선 나의 경제관념에 관해 먼저 말하고 싶다. 어릴 적에 봤던 가난한 아빠와 부자 아빠 책을 보면서 자본에 대한 생각이 많이 바뀌었다.
나는 저축보다는 투자를, 특히 유동성에 투자하려는 편이다. 자본은 결국 가치이다. 누군가에게 가치로 1원을 받는다면 그건 굉장히 쉬운 일일 테다. 좀 더 나아가 60억 인구에게 1원씩 받는다면? 60억을 손에 쥐게 된다. 더 나아가 한번 일해서 한 번의 가치를 얻는 게 아니라 가치 생산의 자동화 즉 시스템화를 통한 패시브 인컴을 만들어야 한다. 개발은 이런 패시브 인컴을 만드는데 최적화되어 있다!


2. 자 이제 나는 어떻게 가치를 줄 것인가?
사진 찍기를 좋아했던 나는 만약 누군가 20년 전 나의 과거 사진을 100원에 판다고 하면 기꺼이 구매할 것이다.
다시는 시간에 나로 갈 순 없지만 그때의 나를 회상하면 충분히 100원 이상의 가치를 할 것이기 때문이다.
당근마켓, 카카오톡을 보면 참으로 간단한 서비스이지만 엄청난 편의성을 누릴 수 있다. 한번 쓰기 시작하면 그 관성은 쉽게 바뀌지 않는다. 이게 바로 기술을 먼저 알아야 하는 것 과 같다. 어떤 가치를 주는 것 : 시간을 아끼게 해 준다거나,
노동력을 줄여주는 서비스! 개발은 이러한 가치를 주기에 정말 적합하다고 생각한다.


3. 개발자는 레드오션이며 블루오션이다. 그러나 세상이 너무나 빠르게 변화하고 있다. 2011년에 처음으로 스마트폰을 써본 것 같은데, 10년이 지나니 스마트폰이 모든 것을 대신하고 있다. 그 시대에 이런 세상을 생각이나 했을까? 다시 말해 기회는 온다.
네트워크 개발이 되더니 빅데이터가 가능해졌고,  딥 러닝에 이어 머신러닝에 인공지능이라니... 게다가 하나 같이 삶에 굉장히 임팩트를 남기는 분야를 만들어 낸다. OpenAI의 혁신으로 ChatGPT, Dalle2를 보면서 새로운 형태의 콘텐츠가 등장하기 시작하였고, 콘텐츠 개발 방향 또한 이전과는 전혀 달라진 방향이 되었다.  개발은 콘텐츠의 방향 다양하게 만든다.

4. 개발 분야는 다양하지만 같은 마인드를 배운다.
개발에는 셀 수 없을 정도로 다양한 개발자가 있다. 웹 개발, 앱 개발, 네트워크 개발자, os마다 sw개발자가 다 있을 거고 세부로 들어가면 더 다양한 분야가 있다.
개발을 위해 다 전부를 알 필요는 없지만, 대부분 지식을 공유하고 있는 데다가 하나의 언어만 제대로 안다면 다른 언어로 넘어가는 크게 문제 되지 않는다. 다시 말해 드론 코딩이나, IOT 코딩, 프론트단 코딩이나 분야 자체는 완전히 다르지만, 원리 자체는 크게 다르지 않다는 것이다.(원시안적 관점에서 보자면)
인터렉티브 미디어아트를 공부하려고 C++, JS를 공부했을 때나, 백엔드 웹 개발을 위해 자바, 파이썬을 배울 때나 그 언어의 특징도 다 다르고, 라이브러리 or 프레임워크가 지향하는 바가 다 다르지만 개발자적 마인드는 거의 같았다.
이러한 개발자 마인드는 이전 것에 대한 의문과 새로운 것에 대한 니즈를 만들어 새로운 것을 기획하고, 논의하고, 부딪히며 "왜?"라는 질문을 끊임없이 하게 만든다.

개발은 작은 일상에 의문을 던지게 만들고 정말 그 이름 그대로 Develop 하게 한다.

5. 아무튼 나는 스스로 내가 왜 개발을 하고 있는지, 어디로 가야 하는지 묻고 또 묻고 물어서 내가 만들고 싶은 것들을 하나하나 만들어서 가치 있는 일에 쓰고 싶다. 혹시나 내가 밟은 순서가 궁금할까 봐 몇 글자 더 적자면
개발 입문에는 웹 개발이 제일 좋은 것 같다. 데이터의 움직임을 쉽게 이해할 수 있고, 나중에 백단을 배우면 쿼리문이나 네트워크(devOps 쪽이긴 하지만), 등 개발 기본을 배우기엔 좋은 것 같다. 우선 openCV를 배우고 이를 접목한 인터렉티브 미디어아트도 생각 중인데, 하고 싶은 게 너무 많아서 큰일이다.. 드론 코딩도 재밌어 보이더라.. 나중엔 코딩하고 싶어 하는 학생들 모아서 자기가 만들고 싶은 거 같이 만들 수 있는 그런 특수학교를 만들고 싶다. 배워서 남 주자.







728x90

'글적글적 > 방향성' 카테고리의 다른 글

[창업하기전에 알아야할 PM 지식]  (1) 2023.12.06
취업 방향  (0) 2023.02.20
728x90

 

brew로 

https://gist.github.com/jungbin-kim/d0c8a41d3c72ebdace3c4d5acaa017e4

 

 

도커 설치법

도커허브에서 이미지 검색하는방법

Docker search — 

Ex) docker search centos

 

 

도커허브에서 이미지를 다운로드하는 방법

Docker pull —

Ex) docker pull centos (:lastest)

 

도커 이미지 목록 모기

Docker images 

 

도커에 태그 달기 (하드링크랑 같음)

Docker tag [이미지A: 이전 tag] [이미지A: 바꿀tag]

Docker tag centos:latest centos:ver7

 

도커 이미지 삭제

Docker rmi 이미지이름:태그

 

 

이미지 업로드 할려면

이미지 이르은 “아아디/리포지토리:태그” 형식으로 사용해야함

e) docker pull

 

@도커 실행하기 (run은 이미지 안만

Docker run —name

docker run --name hello hello-world

 

@현재 도커 상태보기 

Docker ps 

(-a) 종료된 리스트도 보여줌

 

@도커 오브젝트(이미지/컨테이너/네트워크/ 볼륨) 를 더 자세하게봄

Docker inspect 이름

 

 

<— 잘몰라도됨—> 차피 docker run으로 끝남

@docker create (-it 입출력 가능하게 하는 옵션) --name 이미지 이름

Docker create 이름 : 이름 지정해줘라/ 안하면 랜덤으로 생겨버림

@create start/stop

Docker start -ia 컨테이너이름  (create -it로 만들었으면 -ia 붙이기)

 

Ctrl + p + q 컨테이너 안에서 빠져나오기

 

 

@컨테이너 만들고 시작하기 / 이미지가 없으면 해당이미지를 다운까지 받음

Docker run (=pull + create + start)

Docker run (-it 입출력이 필요하면)— name [컨테이너이름] [이미지이름]

 

(-d) 백그라운드 

Ex) docker run -itd —name c1 centos 

 

@컨테이너 삭제

Docker rm

(-f) 강제삭제 : 실행중이어도 삭제가능

 

@컨테이너 접근 (백그라운드에 있는 경우에 효력이 발생)

Docker attach [컨테이너이름]

 

@컨테이너에서 어플리케이션 실행 - 실행하고 바로 빠져나와버림

Docker exec [컨테이너이름] [명령어]

Ex) ddocker exec c1 ip addr

 

@컨테이너내의 실행중인 프로세스 확인

Docker top [컨테이너이름]

 

@컨테이너 새이름

Docker rename 이름 새이름 

 

@컨테이너 일시정지/ 다시시작

Docker pause/unpause [컨테이너이름]

 

@컨테이너 복사 

Docker cp [option][컨테이너이름]:

 

@컨테이너 변경사항 추적

Docker diff c1

 

@컨테이너  이미지 커밋저장

Docker commit [컨테이너이름] [적당한이름]

 

@컨테이너 이미지 아카이브 파일로 저장

Docker save [옵션] [

 

@컨테이너 복원/로드

Docker load

728x90

'Network > [Cloud]' 카테고리의 다른 글

[Cloud] Telemetry  (1) 2022.12.10
[Cloud] 도커란?  (0) 2022.12.05
[Cloud] 2. 클라우드 서버 가상화 (Server virtualizations)  (1) 2022.11.26
[Cloud] 1. 클라우드 컴퓨팅이란?  (0) 2022.11.25
728x90

출처 얄팍한 코딩사전

작업공간을 나누기 위해 일반적인 가상화를 진행하게 되면

자원 낭비가 심하다.

운영체가 필요해서 작업공간 분리를 위해 집안에 집을 만드는 꼴이 됨

 

 

 

 

 

 

https://www.youtube.com/watch?v=hWPv9LMlme8

도커의 같은 경우 

1. 운영체제를 따로 만들필요가 없다 - 자원을 아낄 수 있다.

 

2. 이식성이 좋다 - 각 컨테이너끼리 독립된 동작 환경을 구성한다

 

3. 상호운용성 - On-Premise 환경뿐 아니라 구글, 아마존, IBM등 다양한 벤더의 시세틈 및 클라우드 환경을 지원한다. ->

다양한 DevOps 오픈소스 SW와 연계가 가능하다.

 

 

도커의 주요 기능

1. 이미지 생성 및 관리

- 이미지는 컨테이너를 구동하기 위한 데이터

- 도커 명령어로 이미지 관리 가능

 

2. 이미지 공유

- 이미지 저장소 (레지스트리)에서 검색, 다운로드, 업로드 가능

- git으로 이미지 버전관리 가능

 

3. 컨테이너 동작

- 컨테이너 단위의 서버를 구동

- 운영체제 없이 구동

- 속도와 효율이 좋음

 

도커 동작을 위하여 사용되는 기술

1. 네임 스페이스

- 컨테이너라는 독립된 환경을 만들고

네임스페이스 설명
PID -PID와 프로세스를 분리
- 네임스페이스가 서로 다른 프로세스는 서로 접근 불가
Network - Namespace 별로 네트워크 장치, IP 주소, 포트 번호, 라우팅 테이블, 필터링 테이블 사용
UID - Namespace에 따라 독립적인 UID, GID 사용
Mount - Namespace에 따라 독립적인 마운트 포인트 사용

UTS - Namespace에 따라 독립적인 호스트네임 사용
IPC - Namespace에 따라 독립적인 IPC 오브젝트 사용

 

2. 그룹제어

- 도커의 각 컨테이너는 호스트의 리소스를 공유하여 사용된다. 이에 따라 자원이 불균형하게 할당되거나, 필요한 자원을 할당받지 못할 경우

Cgroup은 프로세스 또는 쓰레드를 그룹화하여 관리함.

이를 통해서 서로 다른 컨테이너에 영향을 막아주는 역할도 가능

 

3. 가상 브릿지와 가상 NIC (랜카드)

- 도커에서 생성한 컨테이너는 각각 가상의 NIC(Network Interface Card) 가 할당.

컨테이너의 네트워크를 Brigde로 기본설정을 할 경우 NIC는 docker0라는 가상 브릿지에 연결되어 컨테이너 끼리, 또는 호스트를 통해 외부 네트워크로 연결.

위의 호스트의 eth0는 물리적은 NIC를 말하며, docker0는 eth0와 연결된 가상의 브릿지 네트워크.

veth* (Virtual Ethernet은 컨테이너 별로 생성된 호스트의 가상의 NIC이며, 이는 컨테이너 eth0와 연결굄

 

4. 계층 파일 시스템

- 도커에서 기존 이미지에 추가작업을 하는 경우 변경된 부분만 복제 (COW방식 : Copy on Write)

- 도커의 이미지에는 운영체제와 미들웨어를 포함하고 있어서 생성할때 마다 기존 방식이라면 복사할때마다 자원 낭비가 발생하기 때문에  

그래서 변경된 것만 복제

 

- 도커 이미지 관리에 사용되는 파일 시스템 또는 라이브러리

Btrfs(B-Tree File System)

AUFS(Advanced multi-layered Unification File System)

Device Mappaer

OverlaysFS

 

728x90
728x90

리눅스 시스템의 부팅 과정

 

바이오스 단계

  • PC의 전원 스위치를 켜서 부팅하면 제일 먼저 바이오스(BIOS, basic input/output system)가 동작
  • 바이오스는 PC에 장착된 기본적인 하드웨어(키보드, 디스크 등)의 상태를 확인한 후 부팅 장치를 선택하여 부팅 디스크의 첫 섹터에서 512바이트를 로딩
  • 이 512바이트가 마스터 부트 레코드(master boot record, MBR): 2차 부팅 프로그램(부트 로더)의 위치 저장

 

 

< systemd 서비스 >

init 프로세스와 런레벨 (중요)

 

  • init 프로세스에서 사용하던 런레벨(Run Level)의 개념에 대한 이해 필요
  • init는 시스템의 단계를 일곱 개로 정의하여 구분하고 각 단계에 따라 셸 스크립트를 실행하는데, 이 단계들을 런레벨이라고 함

 

systemd 유닛 (데몬 = 서비스)

  •  systemd는 전체 시스템을 시작하고 관리하는 데 유닛(units)이라 부르는 구성 요소를 사용
  •  systemd는 관리 대상의 이름을 ‘서비스 이름.유닛 종류’의 형태로 관리 
  •  각 유닛은 같은 이름과 종류로 구성된 설정 파일과 동일한 이름을 사용

 

systemd의 기본 개념

systemd는 Centos7부터 본격적으로 기존의init 스크립트를 대체하기 시작

거의 대부분의 서비스가systemd기반 변경

systemd는 init 방식에 비해 가진 장점

  • •소켓 기반으로 동작하여inetd 와 호환성을 유지한다.
  • •셸과 독립적으로 부팅이 가능하다.
  • •마운트 제어가 가능하다.
  • •fsck 제어가 가능하다.
  • •시스템 상태에 대한 스냅숏을 유지한다.
  • •SELinux와 통합이 가능하다.
  • •서비스에 시그널을 전달할 수 있다.
  • •셧다운 전에 사용자 세션의 안전한 종료가 가능하다.

맥북의 경우

https://devlog.jwgo.kr/2019/07/03/how-do-i-check-if-a-service-is-running-in-mac/

 

 

 

728x90

'P-Language > [Linux]' 카테고리의 다른 글

[Linux] 프로세스의 개념  (0) 2022.12.01
[Linux] 특수 접근 권한  (0) 2022.12.01
728x90

프로세스: 현재 시스템에서 실행 중인 프로그램

프로세스의 부모-자식 관계

  • 프로세스는 부모-자식 관계를 가지고 있음
  • 필요에 따라 부모 프로세스(parent process)는 자식 프로세스(child process)를 생성하고, 자식 프로세스는 또 다른 자식 프로세스 생성 가능
  • 부팅할 때 스케줄러가 실행한 프로세스인systemd와 kthreadd프로세스를 제외하면 모든 프로세스는 부모 프로세스를 가지고 있음
  • 자식 프로세스는 할 일이 끝나면 부모 프로세스에 결과를 돌려주고 종료

 

프로세스의 번호 : 각 프로세스는 고유한 번호(PID)

 

프로세스의 종류

  • 데몬 프로세스(HTTP, SSH)
    • 특정 서비스를 제공하기 위해 존재하며 리눅스 커널에 의해 실행
  • 고아 프로세스(systemd - 보통 1번 프로세스)
    • 자식 프로세스가 아직 실행 중인데 부모 프로세스가 먼저 종료된 자식 프로세스는 고아(orphan)프로세스
    • 1번 프로세스가 고아 프로세스의 새로운 부모 프로세스가 되어 고아 프로세스의 작업 종료 지원
  • 좀비 프로세스
    • 자식 프로세스가 실행을 종료했는데도 프로세스 테이블 목록에 남아 있는 경우
    • 좀비 프로세스는 프로세스 목록에defunct프로세스라고 나오기도함
    • 좀비 프로세스가 증가하면 프로세스 테이블의 용량이 부족해서 일반 프로세스가 실행되지 않을 수도 있음

 

SID 

UUID : 장치의 고유번호

 

 

프로세스 목록 보기

현재 실행 중인 프로세스의 목록을 보는 명령: ps

  • 유닉스 (SVR4)옵션 : 묶어서 사용할 수 있고, 붙임표로 시작한다(예 : -ef).
  • BSD 옵션 : 묶어서 사용할 수 있고, 붙임표로 시작하지 않는다(예 : aux).
  • GNU 옵션 : 붙임표 두 개로 시작한다(예 : --pid).

 

포그라운드 작업

  • 포그라운드 프로세스: 사용자가 입력한 명령이 실행되어 결과가 출력될 때까지 기다려야 하는 포그라운드 방식으로 처리되는 프로세스
  • 이를 작업 제어에서는 포그라운드 작업이라고 함
  •  
sleep 100 -> 포그라운드 작업 / sleep 명령이 끝날 때까지 기다려야 한다.

백그라운드 작업

  • 백그라운드 프로세스: 명령을 실행하면 명령의 처리가 끝나는 것과 관계없이 곧바로 프롬프트가 출력되어 사용자가 다른 작업을 계속할 수 있음
  • 작업 제어에서는 백그라운드 작업이라고 함
sleep 100 & -> 백그라운드 작업 
바로프롬프트 나옴			/ 프롬프트가 바로 나와 다른 명령을 실행할 수 있다.

다른 작업하는 동안 그 작업을 연산중 (병렬처리와 비슷)
이전 백그라운드 작업 결과가 언제나올지 모르니 리다이렉트 해주는게 좋음

 

<포그라운드, 백그라운드 프로세스와 작업 제어>

작업 제어

  • 작업 제어는 작업 전환과 작업 일시 중지, 작업 종료를 의미
  • 작업 전환: 포그라운드 작업-> 백그라운드 작업  // 백그라운드 작업->포그라운드 작업으로 전환
  • 작업 일시 중지: 작업을 잠시 중단
  • 작업 종료: 프로세스를 종료하는 것처럼 작업을 종료

 

@ jobs

- 기능 : 백그라운드 작업을 모두 보여줌, 특정 작업 번호를 지정하면 해당 작업의 정보만 보여줌

- 형식 : jobs %작업번호

 

ctrl + c 강제종료 인터럽트

ctrl + d 정상종료

ctrl + z 또는 stop %작업 번호 포그라운드 작업을 일시 중지함

bg %작업 번호 : 백그라운드로 작업시작

fg %작업 번호 : 포그라운드로 작업시작

 

 

작업 예약 

특정한 시간에 작업을 수행하도록 예약할 수 있는 두 가지 방법

  • 정해진 시간에 한 번만 수행 at
  • 정해진 시간에 반복 수행 crontab

at [옵션][시간]

  • - l 실행대기 중 명령의 전체 목록을 출력 (atq 명령과 동일)
  • -r 작업번호
  • -m 메일로알려줌
  • -f 실행할 명령을 파일로 지정

crontab [-u USERID][옵션][파일명]

  •  -e 로그인한 사용자로 예약.
  • -l crontab 파일의 목록을 출력한다.
  • -r crontab 파일을 삭제한다.

728x90

'P-Language > [Linux]' 카테고리의 다른 글

[Linux] 리눅스 시스템의 부팅  (0) 2022.12.01
[Linux] 특수 접근 권한  (0) 2022.12.01
728x90

 

특수 접근 권한

  • 접근 권한은 원래 4자리
  • 생략된 맨 앞자리는 특수 접근 권한 의미
  • 맨 앞자리 숫자가 0이면 일반적인 접근 권한이지만 이 숫자가 1, 2, 4이면 특수 접근 권한이 설정

 

  • SetUID : 맨 앞자리가 4
  • SetGID : 맨 앞자리가 2
  • 스티키 비트(sticky bit) : 맨 앞자리가 1

SetUID : 해당 프로그램을 실행하는 사용자가 프로그램을 실행하는 동안 임시로 파일의 소유자의 권한으로 프로그램을 수행

 

SetGID : 해당 프로그램을 실행하는 사용자가 프로그램을 실행하는 동안 임시로 파일의 소속 그룹의 권한으로 프로그램을 수행

 

777 ->  rwx/rwx/rwx

-> setuid : rws/rwx/rwx (소유자쪽에 s라 표시)

-> setgid : rwx/rws/rwx  (그룹쪽에 s라 표시)

 

특수 접근 권한 왜 필요해?

 

root 계정이 아니라 / 다른 계정일 경우 rwx/- /- 는 실행할 수 없다.

하지만 Setuid rws/-/-  인 경우 임시로 실행가능

 

설정하는 방법

<기호방식> (심볼릭방식)

setuid  : chmod u+s 파일이름

setgid : chmod g+s 파일이름

 

<숫자모드> (8진수방식)

setuid  : chmod 4755 파일이름

setgid : chmod 2755 파일이름

 

setuid/setgid는 보안에 취약하다 파일관리가 필요하다 / 메인관리자가 아닌 일반 

 

 

 

sticky bit(파일에 설정 못함, 디렉토리에만 설정가능) : 해당 특수 권한이 설정된 디렉토리 내에 생성된 파일들은 소유자와 root외 다른 사용자는 삭제하지 못한다.

디렉토리에 쓰기 권한이 있는 경우 디렉토리에서 파일을 만들고 삭제하고 수정할 수 있다.

: 게시판이라 생각하면 쉬움 / A가 쓴글을 B가 못지움

 

setuid 파일 찾기 : find / -perm -4000 

setgid 파일 찾기 : find / -perm -2000

sticky bit 파일 찾기 : find / -perm -1000

setuid and setguid 파일 찾기 : find / perm4000operm2000 -ls

 

 

728x90

'P-Language > [Linux]' 카테고리의 다른 글

[Linux] 리눅스 시스템의 부팅  (0) 2022.12.01
[Linux] 프로세스의 개념  (0) 2022.12.01
728x90

< 네트워크란 ? > 

연결하는것

 

LAN (Local Area Network)

 - 근거리 (사무실, 강의실 내)

 - 초기 비용이 높지만, 유지보수 비용 낮음

 - 네트워크 관리자가 관리를 담당

 - 스위치, 허브 등의 장비

 

 

WAN (Wide Area Network)

 - 원거리 (미국 - 한국)

 - 원거리에서 LAN-LAN

 - 초기비용은 낮으나, 지속적 유지비 발생

 - Internet Service Provider 가 관리를 담당 (kt)

 - Router

 

인터넷

 - 전세계 LAN과 WAN이 함께 연결된 거대한 네트워크

 

- 통신방식 

 유니케스트 

  : 서버와 클라이언트간 1:1 통신

 

브로드 캐스트

 :  1 서버 다수의 클라이언트

 

멀티 캐스트

 : 데이터를 전송하려는 특정 그룹에게 데이터를 전송하는 통신 방식

 

 

< IP 주소 (논리적 주소) 변경가능  4바이트>

IPv4 주소 : 주로 이걸 씀

IPv6 차세대 ip 주소

 

물리적 주소 vs 논리적 주소

 

서브넷마스크 - 2진법

네트워크주소 호스트주소 

 

사설 IP 대역대 :

- Class A 규모 : 10.0.0.0 ~ 10.255.255.255 (10.0.0.0/8)

- Class B 규모 : 172.16.0.0 ~ 172.31.255.255 (172.16.0.0/12)

- Class C 규모 : 192.168.0.0 ~ 192.168.255.255 (192.168.0.0/16)

 

공인 ip 대역대 : 인터넷 공인망에서는 ip 대역

사설 ip 대역대 : 사설망 내부에서 쓰는 ip 대역

 

공인 ip와 사설ip를 전환하여 인터넷을 가능케 하는 기술   -> NAT

 

 

게이트웨이 :

- 네트워크의 출입문

- 다른 네트워크라면 게이트웨이 주소로 보내야함

 

< MAC주소 (물리적 주소) : 장치 고유의 주소 > 

 

 ex) 00-05-C5-F0-53-FE (6바이트)

 - 근거리 통신할때는 무조건 MAC주소로 통신 함

 - 기계는 mac 주소를 알아야 통신가능

 - 사람은 ip 주소를 알아야 통신가능

 

ip 주소를 이용해서 mac 을 알아오는 프로토콜 : arp <-> rarp

 

- 근거리 통신을 하기 위해선 mac 주소를 알아야함

- 원거리 통신을 하기 위해선 ip 주소를 알아야함 

 

 

 

 

< DNS : Domain Name Service >

naver.com  = 223.130.195.200

인터넷 주소창에 223.130.195.200 넣으면 네이버로 감

< terminal / cmd >

nslookup  로 dns 확인가능

nslookup naver.com

netstat -a : 사용중인 포트 정보

nslookup : dns 서버 정보

arp -a : arp 캐시 보는 명령어 / arp 테이블

Ctrl + c: 강제종료 (작업하던거 날라감)

C + d : 정상종료

C + z : 일시정지 (가끔 일부명령어로 사용)

Hostname : 네트워크상에서 내컴터 이름

tracert / netstat -r (중요) 라우팅 정보를 알려줌 / 네트워크 경로를 확인 경유지들의 ip를 확인 가능

 

<DHCP service>

우리 컴퓨터의 네트워크를 자동으로 설정해주는 서비스 

 

포트 통신 프로토콜 : TCP / UDP

TCP : 신뢰성있는 통신이 필요 / 상대방과 세션을 연결 

UDP : 간단한 통신이나 빠른 대용량 통신 (동영상 재생) DNS, DHCP / 세션은 맺질 않음

 

 

 

 

 

라우팅테이블 : 통신하기위해선 목적지로 갈수 있는 경로가 적혀있어야 한다.

-> 네트워크 엔지니어, 인프라 엔지니어의 역할

 

매트릭 : 우선순위  윈도우 매트릭 높을수록 우선높은우선 

 

 

 

728x90

+ Recent posts