레이블이 python인 게시물을 표시합니다. 모든 게시물 표시
레이블이 python인 게시물을 표시합니다. 모든 게시물 표시

2014년 12월 18일 목요일

Python으로 좀비 프로세스 만들어보기

오후 4:40 Posted by jonnung No comments
원래는 좀비/고아 프로세스만 찾아서 kill 하는 것만 하려고 했으나, 조사를 좀 해보니까 좀비프로세스가 시스템 자원을 그렇게 대놓고 차지하는 것은 아니더라..
프로세스 제어블록을 차지하는 것이기 때문에 엄청나게 폭발적으로 생기는 좀비가 아니고서야 큰 영향은 없다고 싶었다. 

좀비 프로세스가 생기는 원인은 부모 프로세스가 자식 프로세스의 종료 코드를 받지 않고, 무한히 대기하는 상태이다. 한마디로 자식이 좀비가 되도 부모는 종료된 상황이 아닌 것이라는 말이지!
(고아 프로세스는 자식이 끝나지도 않았는데 부모가 끝나버려서 자식이 고아가 된 경우를 말함)

아무튼 확인을 해보기 위해서 좀비프로세스 발생시키는 스크립트를 하나 만들어 보았다.

subprocess 모듈의 Popen() 함수로 자식 프로세스를 하나 띄우고, 자식 프로세스가 끝나는걸 기다리지 않고 부모가 계속 무한루프를 돌도록 했다.

이 상태에서 "ps aux | grep ' Z' | grep -v grep" 를 실행해보면  상태값이 'Z'인 프로세스를 하나 발견할 수 있는데 이게 좀비 프로세스이다. 

부모를 죽이면 이 좀비프로세스도 사라진다. 

2014년 10월 12일 일요일

파이썬 소켓(socket) 모듈을 사용한 네트워크 프로그래밍 - Python 도서 리뷰

오전 1:49 Posted by jonnung , 8 comments


네트워크 프로그래밍(2/2)

 이전 포스트에서 '클라이언트/서버 아키텍처와 소켓 (socket)' 부분에 대해 정리했다. 이번에는 이 개념을 파이썬에 도입해서 프로그램을 작성 해보자.

일단 책에 나오는 TCP 서버/클라이언트, UDP 서버/클라이언트를 예제를 통해서 주로 사용하는 socket 모듈에 대한 구조를 파악해봤고, 이번에는 연습문제 중에 하나인 '전이중(full-duplex) 채팅 프로그램'을 만들어 보겠다.

책에는 나오지 않지만 검색을 해보던 중에 소켓 프로그램의 주요 이슈중 하나인 블럭킹(Blocking)에 대해 알게 되었는데 블럭킹을 해결하기 위한 방법중에 하나인 select 모듈을 채팅 프로그램에 적용해 보았다.

소스코드를 살펴 보기 전에 당연히 이 블럭킹(Blocking) 이라는 녀석이 무엇인지 살펴 보는 것이 순서겠다.


블럭킹(Blocking)

 어떤 일이 일어나기를 기다리면서 멍하니 있는 상태를 말한다. 예를 들어 소켓 서버에서 recv() 를 호출해 놓고, 클라이언트가 보내는 데이터를 기다리는 경우, 소켓 서버는 읽기 상태에서 블럭킹 되어 있다고 말한다고 한다.
 서버나 클라이언트나 차례대로 서로 데이터를 주고 받으면 이것은 크게 문제가 되지 않는다. 하지만 만약 서로가 데이터를 주기를 기다리는 상태가 된다면 어떻게 될까?

 이런 블럭킹 상태를 피하는것이 가장 좋겠지만, 그렇지 못할 수도 있기 때문에 일정 시간 이후 타임아웃이 걸려서 이 상태를 벗어나는 것도 좋은 방법이 될 수 있다.

그래서 채팅 프로그램 예제에서는 이 블럭킹 문제를 해결하기 위해 select 모듈을 사용한 것이다.
현재 수준에서 select 모듈을 더 파보는 것은 조금 무리가 있기 때문에 간단한 사용법만 익혀서 바로 적용했다. 하하;;


TCP 서버/클라이언트 채팅 프로그램

일단 전체 소스코드는 아래와 같다. 

상대적으로 클라이언트(tcpChatClient.py)가 쉽다(?)고 느껴지기 때문에 공을 더 들인 부분은 서버측 스크립트(tcpChatServer.py) 이다.

select 모 듈의 select 메소드는 양쪽 모두에서 사용되었다. 네번째 인자로 전달된 값이 '블럭킹' 단락에서 언급한 그 타임아웃 시간이다. 
10초라는 의미의 값을 전달 했기 때문에 읽어 들일 객체(첫번째 인자에 리스트 형태로 전달한 소켓들)가 없으면 비어있는 리스트를 반환한다.

38 ~39번 라인의 # 새로운 접속 부분에서 select() 가 반환한 read_socket 리스트의 값중에 서버소켓(serverSocket)과  같은 객체를 체크해서 새로운 접속인지를 판단한다.
하지만 아직 서버는 클라이언트의 연결이 받아들여진 상태는 아니다. listen() 메소드에서 일단 클라이언트의 접속이 되면, accept() 를 호출해서 별도의 소켓에 넘겨주고 통신을 진행하는 방식이 TCP 통신의 특징이고 UDP 와의 큰 차이인 것이다.

프로그램을 종료 하려면 강제로 종료시키는 방법 밖에 없는데 이때 KeyboardInterrupt 예외가 발생한다.
연습 삼아 만든 프로그램이지만 보기 안좋은 부분을 보완하기 위해서 try ~ except로 예외를 잡아 소켓을 닫고, 프로그램을 종료 시켰다. (책에서는 이 부분에 대한 코드는 없지만 '부드럽게 종료하기' 라는 참고사항으로 권장하고 있다.)


참 고

클라이언트/서버 아키텍처와 소켓(Socket) - Python 도서 리뷰

오전 12:46 Posted by jonnung , No comments




네트워크 프로그래밍(1/2)



'코어 파이썬 애플리케이션 프로그래밍' 의 두번째 챕터 '네트워크 프로그래밍'에 대한 리뷰 형식의 포스트 이다.
이번 챕터에서는 네트워크 프로그래밍의 배경 지식과 파이썬에서의 소켓(Socket)을 사용하는 방법을 설명하고 있다.


클라이언트/서버 아키텍처

  • 클라이언트/서버 아키텍처의 전제는 하드웨어일 수도, 소프트웨어일 수도 있는 서버가 하나 이상의 클라이언트(사용자)에게 '서비스'를 제공한다는 점
  • 서버의 존재 목적은 (클라이언트의) 요청을 기다리다가 클라이언트의 요청에 응답 후 다시 다른 요청을 기다리는 것
  • 2가지 형태의 클라이언트/서버 아키텍처를 소개하고 있다.
    1. 하드웨어 클라이언트/서버 아키텍처
    2. 소프트웨어 클라이언트/서버 아키텍처
  • 네트워크 프로그래밍은 서버가 클라이언트의 요청에 응답하려면 설정 과정이 필요하고, 통신 종단점(communication endpoint)은 서버가 요청을 리슨(listen)하기 위해 만들어지고 무한 루프에 들어가서 연결해 오는 클라이언트를 기다린다.
    그리고 클라이언트는 자신의 통신 종단점을 만든 후 서버에 연결해야 한다.

소켓

소켓은 '통신 종단점'이라는 개념을 구체화한 컴퓨터 네트워크 데이터 구조이다.
네트워크를 사용하는 애플리케이션은 통신을 시작하기 전에 항상 소켓을 만들어야 한다.
소켓 없이는 통신을 시작할 수 없기 때문이다.
원래 소켓은 실행중인 프로그램(프로세스)이 같은 호스트안에 실행 중인 다른 프로그램과 통신하기 위해 깨발 되었다고 한다.

소켓의 유형

  1. 유닉스 소켓
    • AF_UNIX 라는 '패밀리 이름' 을 가진다. AF는 주소 패밀리(Address family)를 의미.
    • 쉽게 클라이언트와 서버가 유닉스 환경의 동일한 컴퓨터에 존재해야 한다는 뜻.
    • 이 소켓은 파일 기반이다. 소켓의 기반 구조가 파일 시스템을 통해 지원된다는 것이다.
    • 파일 시스템은 같은 호스트에서 실행 중인 프로세스 사이에 지속적으로 공유되므로, 합리적인 방법이라고 할 수 있다.
  2. 네트워크 기반
    • 패밀리 이름은 AF_INET 이다.
    • 클라이언트와 서버가 인터넷 어디서든 존재할 수 있다는 의미를 갖는다.
파이썬은 AF_UNIX, AF_NETLINK, AF_TIPC, AF_INET{,6} 패밀리를 지원한다.

연결 방식에 따른 소켓의 종류

  1. 연결 지향 소켓(connection oriented)
    • 통신을 하기 전에 반드시 연결 돼 있어야 한다(전화를 거는 것과 유사)
    • 레코드 경계 없이 데이터를 순서대로 신뢰성 있게 중복없이 전달. 각 메세지는 여러 조각으로 나뉘어서 반대편에 확실히 전달된 다음에 다시 순서대로 한데 묶인 후 기다리는 애플리케이션에 전달
    • 연결 지향 소켓을 구현한 프로토콜(protocol)로는 전송 제어 프로토콜(TCP, Trasmission Control Protocol) 이 있으며, 이 소켓을 만드려면 소켓 유형으로 SOCK_STREAM(스트림 소켓)을 지정
    • 이 소켓은 네트워크상에서 IP를 호스트를 찾기 위해 사용하기 때문에 두 프로토콜의 이름을 붙여 TCP/IP 라고 함.
  2. 비연결형 소켓(connectionless)
    • 스트림 소켓과 대비되는 데이터그램(Datagram) 유형의 비연결 소켓
    • 통신 시 최초 연결하는 과정이 필요 없음
    • 데이터 전달 과정에서 순서나 신뢰성 이나 중복 방지를 보장할 수 없음. 이는 메세지가 연결 지향 소켓처럼 조각으로 나뉘지 않고 통째로 송신된다는 것을 의미(우편 서비스에 비유)
    • 연결 지향 소켓은 가상 회선을 맨 처음 만들고 유지하기 위해 상당한 부가 비용이 드는데 비연결 지향 소켓은 이런 부담이 덜하고 성능면에서 더 좋다.
    • 데이터그램 소켓을 구현한 프로토콜로는 데이터그램 프로토콜(UDP, User Datagram Protocol)이 있고, UPD 소켓을 만들려면 SOCK_DGRAM을 소켓 유형으로 지정.
    • 이 소켓도 IP를 네트워크상에서 호스트를 찾기 위해 사용하므로, UPD/IP라고도 부름





2014년 9월 21일 일요일

파이썬의 정규식(re) - Python 도서 리뷰

오전 9:02 Posted by jonnung , 1 comment

추석전에 연휴기간에 볼 책을 빌리러 도서관에 갔다가 신간으로 들어온 책을 1빠로 득했다. 
최초 번역판일 것 같아서 빌리지말까 하다가 읽어보니까 번역이 상당히 잘 되어 있는 것 같은 느낌이다. 아 그리고 이미 예전에 '코어 파이썬 프로그래밍' 이라는 책에서 '응용' 부분만 좀 더 확장했다는 것 같다.

그런데 반납일까지 1주일 남았는데 1챕터밖에 못봤다. ㅠ_ㅠ  어짜피 사려고 했으니까 뭐;;;
(페이지랑 가격이 좀 후덜덜;;; 하긴 함)

아무래도 파이썬에 대한 책이고, 실습(실행 > 확인) 위주로 공부를 하다보니까 IPython notebook 이 딱 일것 같다.

첫번째 정규식 챕터, 리뷰 보러가기


Python - 클로저(Closure) 쉽게 생각하기

오전 8:28 Posted by jonnung 1 comment


함수 안에 다른 함수가 정의된 함수를 중첩 함수(Nested Function) 이라고 한다.
중첩 함수는 자신을 감싸고 있는 함수가 가진 변수에 접근 할 수 있다. 이건 자바스크립트(Javascript)도 동일한 특성이다. 

일단 간단한 예제 코드를 살펴보자.
#-*- coding: utf-8 -*-
 
def print_hello(msg):
    def inner_print():
         # nonlocal msg  # python3.x에만 있는 키워드
        print('Hello %s' % msg)
    return inner_print
 
printer = print_hello('jonnung')

printer()  # Hello jonnung

print_hello() 함수는 'jonnung'을 전달 받아 호출 되었고, 반환된 inner_print함수는 printer 변수에 할당 되었다.
printer() 함수의 실행 결과로 출력되는 값으로 알 수 있는 사실은 print_hello()의 실행이 종료 되었더라도 전달된 값(msg)이 기억되고 있는 것을 알 수 있다.

이러한 코드를 파이썬에서는 클로저(Closure)라고 한다.
그리고 감싸는 함수 안에 변수는 현재 네임스페이스상에서 함수가 삭제되더라도 사라지지 않는다.
del print_hello
 
printer()  # Hello jonnung

결국 중첩 함수가 감싸진 영역안에 변수를 참조할때 클로저를 갖는다고 할 수 있다.

그럼 이제 파이썬에서 클로저를 만들기 위한 조건을 정리해보자.
  • 중첩 함수(Nested Function)를 갖는다.
  • 중첩 함수는 자신을 감싸고 있는 함수 영역(부모함수)의 변수를 참조하고 있다.
  • 부모함수는 중첩 함수(자식 함수)를 반환한다.
여기서 한가지 물음이 생길 수 있겠다. 그렇다면 클로저는 언제 사용해야 할까?
클로저는 전역 변수를 사용하지 않기 위함과 내부 데이터에 대한 은닉을 위해서 활용할 수 있겠다.
그리고 객체지향에 대한 문제점의 해결책이 될 수 있다. 적은 메소드(대부분 1개?)를 갖는 클래스에 대한 대체로 클로저를 활용한 코드는 좀 더 우아한 방법이 될 수도 있다고 한다. 

위 샘플 코드의 실행 결과와 추가적인 예제는 아래 IPython Notebook에서 자세히 확인 할 수 있다.



2014년 9월 16일 화요일

gae-init (약간) 사용 후기, 구글 앱 엔진(Google App Engine) 웹 어플리케이션 빠르게 시작하기

오전 6:53 Posted by jonnung , , , , , No comments

gae-init 은 Google App Engine에 웹 어플리케이션을 좀 더 쉽게 시작하기 위한 프로젝트 이다. 
일반적인 웹 어플리케이션 개발에서 수행하는 공통적인 작업들(파일 구조를 잡고, 최신 라이브러리를 다운로드 받고, 이전 프로젝트에서 개발한 코드 조각들을 모으는 등)을 자동으로 세팅 할 수 있도록 도와준다.
개발자는 더이상 시간 낭비 하지 않고, 좀 더 어렵고 중요한 작업에 집중할 수 있는 것이다.

공식 문서에서 제공하는 튜토리얼(Tutorial) 에서는 gae-init을 사용해서 개발, 빌드, 실행 그리고 배포까지 다루는 phonebook 예제(데모 보기)를 다루고 있다.

gae-init을 사용하기 위해서는 당연히 python이 있어야 한다.(GAE는 아직 python2.7만 지원함)
그리고 Node.js / Git / pip, virtualenv가 필수적으로 있어야 한다.
설치는 gae-init git 저장소를 clone 받으면 간단하게 시작 할 수 있다. 그리고  run.py -s  를 실행하면 venv(python 가상 환경)과 bower_components, node_modules을 자동으로 세팅하고, Flask로 만든 간단한 구조의 어플리케이션이 GAE SDK에서 제공하는 개발 서버를 통해 실행된다.

튜토리얼의 대부분의 내용은 기본적인 gae-init 세팅 구조에 phonebook 앱의 연락처 기능을 만드는 방법을 자세하게 다루고 있다. 

일단 난 튜토리얼을 다 따라해보지는 않았다. (이미 해 본 내용이기도 하고..)
사실 gae-init 이 세팅하는 구조가 내 입맛에 딱 맞지는 않았다.
그리고 난 거의 pycharm으로 개발을 하니까 개발 서버 실행을 위해 run.py 을 실행 할 일은 없겠지만, 그래도 run.py 파일을 보니까 나중에 참고해 볼만한 코드가 상당히 많았다.
Flask 어플리케이션 코드가 위치한 main 디렉토리도 커스터마이징해서 사용하면 될 것 같다.


(와아~ 어디서 run.py를 실행했는지도 수집하네ㅋㅋㅋ)

2014년 7월 10일 목요일

Python - 파이썬2.x Unicode와 UTF-8 인코딩 감잡기

오후 8:47 Posted by jonnung 3 comments
 파이썬2.x의 기본 인코딩은 ascii 이다. 파이썬 스크립트에서 한글을 사용하게 될 때 파이썬은 ascii 인코딩일 것으로 예상하고 해석하려고 하지만 한글을 ascii로 해석이 불가능 하기 때문에 SyntaxError가 발생 한다.

 이 문제를 해결하기 위해 파이썬 파일의 최상단에는 아래와 같은 주석을 추가하면 조금 도움이 된다.

#-*- coding: utf-8 -*-

 이 주석이 있으면 해당 파이썬 스크립트는 utf-8로 인코딩 되어 있다는 것을 미리 알려주는 역할을 한다.

 여기서 잠깐 유니코드(unicode)와 utf-8에 대한 설명을 간단하게 하자면 utf-8은 유니코드를 위한 문자 인코딩 방식 중에 하나이다. utf-8 인코딩은 유니코드 한 문자를 나타내기 위해 1바이트에서 4바이트까지 사용한다고 한다.

 다시 파이썬의 인코딩에 대한 부분으로 돌아가서 간단한 예제를 하나 보도록 하자.

# -*- coding: utf8 -*-

print(type('한글').__name__)  # str
print(type(u'한글').__name__)  # unicode
print(type('한글').__name__)
print(type(u'한글').__name__)

SyntaxError: Non-ASCII character '\xed' in file…블라블라~

 위 예제 코드의 결과를 보면 쉽게 감을 잡을 수 있다.

 첫번째 에제코드에서 상단에 내부 문자에 대한 인코딩을 utf-8로 하겠다는 미리 알려줬기 때문에(누구에게?? print에게!!) ‘한글’이라는 문자열의 타입은 확인해보면 string 이다. 그리고 u’한글’으로 하게 되면 유니코드로 잘 변환해서 출력 시켜주는 것을 알 수 있다.

 두번째 예제에서는 상단에 선언한 부분을 제거하고 스크립트를 실행 시켜봤는데 역시나 문법에러(SyntaxError)가 발생 하는 것을 확인 할 수 있었다. ‘한글’을 기본적으로 ascii로 해석하려 하기 때문에 type을 알 수도 없고, 유니코드로 변환도 할 수 없는 것이다.

# -*- coding: utf8 -*-

print str(unicode('한글'))
print str(unicode(‘한글', ‘utf-8'))

 ‘한글’을 유니코드로 변환하고, 그 유니코드를 다시 문자열로 바꿔서 출력하려고 한다.
이 코드는 결과는 무엇일까?
unicode() 기본적으로 전달된 인자값을 ascii로 해석하려고 하기 때문에 위 예제는 아래와 같은 에러가 발생한다.

UnicodeDecodeError: 'ascii' codec can't decode byte 0xed in position 0: ordinal not in range(128)

 결국 상단에 utf-8을 사용할 것이라고 선언했어도 unicode() 함수를 사용할때는 소용없다는 것을 알게 되었다.

이 코드를 정상적으로 동작하도록 해보자.

# -*- coding: utf8 -*-

# 유니코드로 다루기 예제1
hoo = unicode('한글', 'utf-8')
print str(hoo.encode('utf-8'))

# 유니코드로 다루기 예제2
bar = '한글'.decode('utf-8')
print bar.encode('utf-8')

# 유니코드로 다루기 예제3
foo = u'한글'
print str(foo.encode('utf-8'))

정신 건강을 위해서라도 파이썬 스크립트 내부에서 사용하는 모든 문자열은 유니코드로 다루는 것이 좋겠다.
그리고 파일이나 DB에 저장하거나 네트워크로 전송하기 직전에는 string으로 변환해서 넘겨주는 방식으로 개발하는 것이 좋다…

아! 그리고  ‘유니코드가 아닌 상태로 CJK(Chinese. Japanese, Korean) 비교할 때 주의할 점’(https://gist.github.com/kimdwkimdw/a2ea13848167984adc8f)도 참고하고 숙지해서 개발시에 엉뚱한 삽질은 안하도록 하자!


참고 자료



2014년 4월 4일 금요일

Python 기초 팁과 트릭

오전 3:38 Posted by jonnung No comments

객체 진위

  • 객체의 길이가 0인지, 값이 비어 있는지 체크할 필요가 없다. 파이썬의 객체는 비어있으면 거짓(False)이다. 숫자 0도 거짓이다.

삼중 따옴표를 사용한 문자열 선언

  • 삼중 홑따옴표든 쌍따옴표든 내부에 인용구 표현처럼 또 다른 삼중따옴표를 쓸 수 있다. 이스케이프가 필요 없어진다.

문자열안에 부분 문자열 찾기

  • 부분 문자열을 찾기위해 find 메소드를 사용할 필요가 없다. 리스트, 튜플, 사전을 다루듯이 in을 사용하면 같은 효과를 볼 수 있다.

람다함수

  • 람다함수는 단 하나의 표현식의 결과를 돌려주는 미니 함수 이다.
  • 람다함수는 그 자체가 표현식이다. 다른 서술문 안에 사용 될 수 있다.
  • 함수를 인자로 넘겨여 할때나, 복잡한 연산을 여러번 하고 싶을때 람다함수를 활용할 수 있다.