멀티쓰레딩을 이용하여 여러 개의 클라이언트를 받을 수 있는 소켓 서버를 파이썬으로 구현해 보았습니다. 



server.py

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

import threading
import SocketServer
import socket
import sys


class CustomException(Exception):
    """
    Exception 클래스를 상속한 클래스를 만든다
    """
    def __init__(self, value):
        """
        생성할때 value 값을 입력 받음
        """
        self.value = value

    def __str__(self):
        """
        생성할때 받은 value 값을 확인
        """
        return self.value


def raise_exception(err_msg, ip_addr=None):
    """
    예외를 발생하는 함수
    """
    raise CustomException(err_msg)


def print_delimiter():
    print("="*20)


class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        """
        클라이언트와 연결될 때 호출되는 함수
        상위 클래스에는 handle() 메서드가 정의되어 있지 않기 때문에
        여기서 오버라이딩을 해야함
        """
        cur_thread = threading.current_thread()
        print("{} was started for {}"
              .format(cur_thread.getName(), self.client_address[0]))

        while True:
            try:
                self.recv_data = self.request.recv(1024).strip()

                # :/quit 를 입력하거나 데이터가 없다면 루프를 종료
                if self.recv_data == ":/quit" or not self.recv_data:
                    print_delimiter()
                    raise_exception("{} was gone".format(self.client_address[0]))

            except NameError as e:
                print "{0} got an error : {1}".format(self.client_address[0], e)
                self.request.send("Bye")
                break

            except CustomException as e:
                print e
                self.request.send("Bye")
                break

            print "{} wrote:".format(self.client_address[0]),
            print self.recv_data

            # 영어의 소문자 데이터를 receive 하면 대문자로 변환해 send
            self.request.sendall(self.recv_data.upper())

        print("{} was ended for {}"
              .format(cur_thread.getName(), self.client_address[0]))
        print_delimiter()


class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    pass


if __name__ == "__main__":
    # Port 0 means to select an arbitrary unused port
    HOST, PORT = "0.0.0.0", 3000

    # 소켓 객체 생성
    try:
        server = ThreadedTCPServer((socket.gethostbyname(HOST), PORT), ThreadedTCPRequestHandler)

    except socket.error, msg:
        print "Bind failed. Closing..."
        print "Error code: %s \nError Message: %s"\
          % (str(msg[0]), msg[1])
        sys.exit()

    print "Socket bound on {}".format(PORT)
    ip, port = server.server_address

    # Start a thread with the server -- that thread will then start one
    # more thread for each request
    server_thread = threading.Thread(target=server.serve_forever)
    # Exit the server thread when the main thread terminates
    server_thread.daemon = True
    server_thread.start()
    print "Server loop running in thread:", server_thread.name

    server.serve_forever()

    server.shutdown()
    server.server_close()



client.py

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

import socket
import sys

HOST, PORT = "192.168.228.128", 8080
# data = "This will be nickname"  # 실제 서비스에는 닉네임을 전송하자

try:
    # 소켓을 생성 (SOCK_STREAM 은 TCP 소켓을 의미)
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((HOST, PORT))

except socket.error, msg:
    print "Failed to create socket. Error code: %s \nError Message: %s"\
          % (str(msg[0]), msg[1])
    sys.exit(0)
print "Socket created"

# input 값이 :/quit 일 때까지 데이터 입력 및 전송 반복
# :/quit 를 입력하면 socket 종료
while True:

    try:
        data = raw_input("Input : ")

        if data == ":/quit" or not data:
            sock.close()
            break

        try:
            # 서버에 연결하고 데이터를 전송
            sock.sendall(data + "\n")

            # 데이터를 수신하고 소켓 연결을 닫음
            received = sock.recv(1024)

        finally:
            print "Sent:     {}".format(data)
            print "Received: {}".format(received)

    except KeyboardInterrupt as e:
        print e
        data = ":/quit"

sock.close()


블로그 이미지

NCookie

,

이번에는 클라이언트가 특정 단어를 입력하기 전까지 계속해서 데이터를 보낼 수 있는 코드를 짜보았습니다.



server.py


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

import SocketServer


def quit_server(client_addr):
    print("{} was gone".format(client_addr))


class MyTCPHandler(SocketServer.BaseRequestHandler):
    """
    The request handler class for our server.

    It is instantiated once per connection to the server, and must
    override the handle() method to implement communication to the
    client.
    """

    def handle(self):
        """
        클라이언트와 연결될 때 호출되는 함수
        상위 클래스에는 handle() 메서드가 정의되어 있지 않기 때문에
        여기서 오버라이딩을 해야함
        """
        self.recv_data = ''

        while True:
            try:
                self.recv_data = self.request.recv(1024).strip()

                # :/quit 를 입력하면 루프를 종료
                if self.recv_data == ":/quit":
                    quit_server(self.client_address[0])
                    break

            except NameError as e:
                print "{0} got an error : {1}".format(self.client_address[0], e)

            finally:
                print "{} wrote:".format(self.client_address[0]),
                print self.recv_data

                # 영어의 소문자 데이터를 receive 하면 대문자로 변환해 send
                self.request.sendall(self.recv_data.upper())


if __name__ == "__main__":
    HOST, PORT = "localhost", 3000

    # 서버를 생성합니다. 호스트는 localhost, 포트 번호는 3000
    server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)

    print("waiting for connection...")

    # Ctrl - C 로 종료하기 전까지는 서버는 멈추지 않고 작동
    server.serve_forever()



clinet.py


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

import socket

HOST, PORT = "localhost", 3000
# data = "This will be nickname"  # 실제 서비스에는 닉네임을 전송하자
data = ''

# 소켓을 생성 (SOCK_STREAM 은 TCP 소켓을 의미)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))

# input 값이 :/quit 일 때까지 데이터 입력 및 전송 반복
# :/quit 를 입력하면 socket 종료
while data != ":/quit":
    data = raw_input("Input : ")
    try:
        # 서버에 연결하고 데이터를 전송
        sock.sendall(data + "\n")

        # 데이터를 수신하고 소켓 연결을 닫음
        received = sock.recv(1024)
    finally:
        print "Sent:     {}".format(data)
        print "Received: {}".format(received)

sock.close()



다음에는 멀티쓰레드를 이용하여 한 서버에 여러 클라이언트가 접속할 수 있도록 하는 코드를 올리겠습니다.

블로그 이미지

NCookie

,

파이썬의 SocketServer 모듈은 네트워크 서버의 작성 작업을 간단하게 해줍니다.

(파이썬 3.x 버전에서는 socketserver로 사용할 수 있습니다.)



server.py


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

import SocketServer


class MyTCPHandler(SocketServer.BaseRequestHandler):
    """
    The request handler class for our server.

    It is instantiated once per connection to the server, and must
    override the handle() method to implement communication to the
    client.
    """

    def handle(self):
        """
        클라이언트와 연결될 때 호출되는 함수
        상위 클래스에는 handle() 메서드가 정의되어 있지 않기 때문에
        여기서 오버라이딩을 해야함
        """
        self.data = self.request.recv(1024).strip()
        print "{} wrote:".format(self.client_address[0]),
        print self.data
        # 영어의 소문자 데이터를 receive 하면 대문자로 변환해 send
        self.request.sendall(self.data.upper())

if __name__ == "__main__":
    HOST, PORT = "localhost", 3000

    # 서버를 생성합니다. 호스트는 localhost, 포트 번호는 3000
    server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)

    print("waiting for connection...")

    # Ctrl - C 로 종료하기 전까지는 서버는 멈추지 않고 작동
    server.serve_forever()



clinet.py


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

import socket
import sys

HOST, PORT = "localhost", 3000
data = " ".join(sys.argv[1:])

# 소켓을 생성 (SOCK_STREAM 은 TCP 소켓을 의미)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

try:
    # 서버에 연결하고 데이터를 전송
    sock.connect((HOST, PORT))
    sock.sendall(data + "\n")

    # 데이터를 수신하고 소켓 연결을 닫음
    received = sock.recv(1024)
finally:
    sock.close()

print "Sent:     {}".format(data)
print "Received: {}".format(received)



[Errno 10048] 에러는 이미 해당 포트가 사용 중이기 때문에 에러가 발생하는 것입니다. 사용 중인 포트 번호를 바꾸거나 사용 중인 프로세스를 중지해서 해결할 수 있습니다.



출처


https://docs.python.org/2.7/library/socketserver.html#socketserver-tcpserver-example

블로그 이미지

NCookie

,

[파이썬] 클로저

파이썬 2016. 11. 23. 22:16

중첩함수(nested function)

 

함수 안에 함수를 정의한 것을 말합니다.


중첩함수를 통해 default로 enclosing function local scope 변수를 참조할 수 있습니다.



내부 함수와 외부 함수


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


def outer_func(msg):

    def inner_func():
        print msg

    return inner_func


inner_func을 내부함수, outer_func를 외부함수라고 합니다.


inner_func 입장에서 outer_func 함수의 지역변수 영역을 enclosing function local scope(바깥 함수 지역 변수 영역) 라고 부릅니다.


 

클로저(closure)란


# -*- coding: utf-8 -*- def outer_func(msg): def inner_func(): print msg return inner_func my_func = outer_func("Megumin is so cute!!") my_func()

Megumin is so cute!!

내부함수가 외부함수의 맥락(context)에 접근할 수 있는 것을 가리킵니다.


inner_func가 outer_func의 지역변수인 msg를 참조하여 출력하는 것을 볼 수 있습니다.


함수를 변수에 저장할 수 있는 이유는 파이썬에서는 함수가 일급 객체(first-class object)이기 때문입니다.


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


def outer_func(msg):

    def inner_func():
        print msg

    return inner_func

first_func = outer_func("Megumin is so cute!!")
first_func()

second_func = outer_func("It's true")
second_func()

print
print "outer_func : ", id(outer_func), "\n"
del outer_func

first_func()
second_func()

print
print "first_func : ", id(first_func)
print "second_func : ", id(second_func)
Megumin is so cute!!
It's true

outer_func :  37766872 

Megumin is so cute!!
It's true

first_func :  37766984
second_func :  37767096


outer_func을 삭제해도 first_func가 정상적으로 호출됨을 알 수 있습니다.


이는 함수를 변수에 저장할 때마다 객체를 새롭게 생성하기 때문입니다.

(outer_func, first_func, second_func 모두 id 값이 다릅니다)


즉, first_func와 second_func는 서로 완전히 독립된 객체인 것입니다.



클로저 내에서 enclosing function local scope 변수 Read/Write



클로저에서 enclosing function local scope 변수에 접근할 수 있다면 modify 하는 것도 가능하지 않을까라고 생각할 수 있습니다. 


하지만 그것은 다음과 같은 오류를 보여줄 뿐입니다. 


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


def outer_func(msg):

    def inner_func():
        print msg
        msg = "Awesome!!"
        print msg

    return inner_func

first_func = outer_func("Megumin is so cute!!")
first_func()
UnboundLocalError: local variable 'msg' referenced before assignment


첫 번째 print문에서 inner_func 함수 내에서 msg라는 변수는 선언된 적이 없기 때문에 enclosing function local scope에서 찾게 됩니다. 하지만 이 변수는 전역 변수와 마찬가지로 함수 내에서 수정할 수 없습니다. (파이썬 네임스페이스 참고)


그래서 python 3.x 부터는 nonlocal 이라는 키워드를 통해 외부함수 영역의 변수를 modify할 수 있도록 합니다.(nonlocal은 global과 비슷한 개념이라 할 수 있습니다)


python 3.x

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

def outer_func(msg):

    def inner_func():
        print(msg)
        nonlocal msg
        msg = "Awesome!!"
        print(msg)

    return inner_func

first_func = outer_func("Megumin is so cute!!")
first_func()
Megumin is so cute!!
Awesome!!


다만, 별로 추천하지는 않다고 합니다.(보충 필요)



대신, python 2.x 에서는 내부 함수의 local variable에 enclosing scope의 변수를 저장하여 사용할 수 있습니다.

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


def outer_func(msg):

    def inner_func():
        _msg = msg
        print _msg
        _msg = "Awesome!!"
        print _msg

    return inner_func

first_func = outer_func("Megumin is so cute!!")
first_func()
Megumin is so cute!!
Awesome!!


또는 함수 속성에 변수를 대입해도 가능합니다.

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


def outer_func(msg):

    def inner_func():
        inner_func.msg = msg
        print inner_func.msg
        inner_func.msg = "Awesome!!"
        print inner_func.msg

    return inner_func

first_func = outer_func("Megumin is so cute!!")
first_func()
Megumin is so cute!!
Awesome!!



왜 사용할까


● 전역 변수의 사용을 피할 수 있음


● private 속성이 없는 파이썬에서 내부 데이터의 은닉을 할 수 있음


● 하나의 함수로 여러 가지의 함수를 간단히 만들어 낼 수 있도록 해줌


● 기존에 만들어진 함수나 모듈 등을 수정하지 않고도 wrapper 함수를 이용해 커스터마이징할 수 있게 해줌


(상세 설명 보충 필요)



요약



● 클로저란 내부 함수 영역에서 외부 함수 영역의 변수에 접근하는 것을 말함


● 파이썬에서 클로저가 구현 가능한 이유는 함수를 일급 객체로 취급하기 때문


● 클로저 내에서 외부 함수 영역 변수를 수정하기 위해서는 별도의 방법이 필요함


● 데이터 은닉 등의 목적을 위해 사용함



참고


[중첩함수]

https://www.programiz.com/python-programming/closure


[내부 함수와 외부 함수]

http://blog.naver.com/msyang59/220773717531


[클로저란]

https://slipp.net/questions/249

https://opentutorials.org/course/743/6544

http://jonnung.blogspot.kr/2014/09/python-easy-closure.html


[클로저 내에서 enclosing function local scope 변수 Read/Write]

[왜 사용할까]

http://schoolofweb.net/blog/posts/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%81%B4%EB%A1%9C%EC%A0%80-closure/


블로그 이미지

NCookie

,

[파이썬] 가변인자

파이썬 2016. 11. 17. 20:13

파이썬에서는 함수의 인자를 가변적으로 받을 수 있습니다.


만약 여러 개의 숫자를 함수의 인자로 받아 출력하려고 한다면 다음과 같이 코드를 작성할 수 있습니다. 


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


def print_num(*numbers):
    for number in numbers:
        print number,

print_num(1, 2, 3, 4)
1 2 3 4


그리고 가변인자는 뒤에 일반인자가 올 수 없으며 하나만 사용할 수 있습니다. 


가변인자를 * 한 개만 사용하여 받으면 튜플 형태로 전달되고 두 개면 딕셔너리 형태로 받아옵니다.


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


def print_num(*numbers, **name):
    for number in numbers:
        print number,

    print "\n{0}".format(name)

print_num(1, 2, 3, 4, name="Bob", name2="Julia")
1 2 3 4 
{'name2': 'Julia', 'name': 'Bob'}


블로그 이미지

NCookie

,

파이썬의 퍼스크 클래스 함수에 관한 글입니다. 


퍼스트 클래스 시민에 대한 글을 먼저 보고 오시면 좋을 듯 합니다.


In computer science, a programming language is said to have first-class functions if it treats functions as first-class citizens. Specifically, this means the language supports passing functions as arguments to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures.
- 위키피디아


퍼스트 클래스 함수(First Class Function)란 함수를 퍼스트 클래스 시민(first-class citizens)으로 다루는 것을 의미합니다. 


즉, 변수에 담을 수 있고, 함수의 인자로 전달하고 함수의 리턴 값(return value)로 전달할 수 있는 함수입니다.



함수를 퍼스트 클래스 객체로 다룰 수 있게 지원하는 것은 함수형 언어의 특징이라고 합니다. 그렇다면 객체지향 언어인 파이썬(Everything is An Object)에서는 어째서 퍼스트 클래스 함수를 지원할까요?


그래서 주변에 물어봤는데 대부분의 답변은 다양하고 기발한 코딩이 가능하기 때문이라고 합니다. 그에 대한 예시로는 데코레이터, 익명 함수 등이 있을 것입니다.



퍼스트 클래스 함수는 후의 클로저(closure)라는 개념을 공부할 때 이어집니다.



출처


https://en.wikipedia.org/wiki/First-class_function


http://bestalign.github.io/2015/10/18/first-class-object/


http://schoolofweb.net/blog/posts/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%8D%BC%EC%8A%A4%ED%8A%B8%ED%81%B4%EB%9E%98%EC%8A%A4-%ED%95%A8%EC%88%98-first-class-function/


http://blog.doortts.com/135


http://stackoverflow.com/questions/245192/what-are-first-class-objects

블로그 이미지

NCookie

,

네이버 음성 합성 API를 사용할 일이 있어서 문서를 찾아보게 되었습니다.


https://developers.naver.com/docs/labs/tts


음성 파일을 얻어오는 방식은 간단한데 지정된 포맷에 따라 http 통신을 POST 방식으로 Request하고 Response에 있는 파일을 로컬에 저장하면 됩니다.




curl 명령어를 통해서 API를 요청하는 방법은 다음과 같습니다.



curl "https://openapi.naver.com/v1/voice/tts.bin" \
	-d "speaker=mijin&speed=0&text=만나서 반갑습니다." \
	-H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" \
	-H "X-Naver-Client-Id: {애플리케이션 등록 시 발급받은 client id 값}" \
	-H "X-Naver-Client-Secret: {애플리케이션 등록 시 발급받은 client secret 값}" -v \
		> out.mp3




위의 명렁어를 쉘 스크립트에서 간단하게 작성했습니다. 

#!/bin/sh

argc=$#
argv0=$0
argv1=$1
argv2=$2

curl "https://openapi.naver.com/v1/voice/tts.bin" -d "speaker=mijin&speed=0&text=$argv0" -H "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" -H "X-Naver-Client-Id: $argv1" -H "X-Naver-Client-Secret: $argv2" -v > out.mp3

chmod 775 out.mp3


argv0=$0 이 부분은 스크립트를 실행할 때 인자를 받기 위해 변수를 저장하는 코드입니다. 


리다이렉션을 통해 out.mp3 파일에 음성이 저장되었고 파일 접근 권한을 rwxrwxr-x 로 변경하였습니다.




이를 파이썬에서 실행해봅시다.


파이썬에는 외부의 명렁어를 실행시킬 수 있는 subprocess라는 모듈이 있습니다. 이 글에서는 call 이라는 메소드만 사용하였습니다.


import subprocess
subprocess.call(['./tts.sh', "hello world", "{어플리케이션 clinet id}", "{어플리케이션 clinet secret}"])






블로그 이미지

NCookie

,

  아마 파이썬 스크립트를 실행할 때 커맨드 라인에서 인자를 전달하기 위해서 argparse 모듈을 사용해 본적이 있으실 것입니다. 그런데 python 2.7에서는 유니코드 문자열을 전달하려고 하면 자꾸 거부를 합니다. (파이썬 2.x 버전은 문자열 인코딩이 제일 짜증나는 것 같습니다.)


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


  이 때 해결할 수 있는 방법이 있습니다. 바로 sys.getfilesystemencoding() 이라는 함수를 이용하는 것입니다, 예제 코드를 보겠습니다.


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

import argparse
import unicodecsv as csv
import sys


def commandline_arg(byte_string):
unicode_string = byte_string.decode(sys.getfilesystemencoding())
return unicode_string

parser = argparse.ArgumentParser()
parser.add_argument("-i", dest="input_file_name", default=None,
help="input file name(s) for CSV data to get data")
parser.add_argument("-target", dest="target_name", default=None,
type=commandline_arg,
help="target name is data for parsing")
parser.add_argument("-o", dest="output_file_name", default="data_set.csv",
type=commandline_arg)

args = parser.parse_args()

with open('input_data_set.csv', 'r') as r:
reader = csv.reader(r) # Here your csv file
lines = [l for l in reader if l[3] == args.target_name]

with open(args.output_file_name, 'wb') as w:
writer = csv.writer(w)
writer.writerows(lines)


 위와 같이 comandline_arg(byte_string) 함수를 선언하고 args type에 함수 이름을 넣어주면 됩니다.

블로그 이미지

NCookie

,

  분명 규칙에 맞게 했는데 crontab이 정상적으로 실행되지 않는 경우가 있습니다. 그래서 인터넷으로 검색도 해보고 직접 실험도 해서 안 되는 이유를 찾아보았습니다.



원인


1. 환경변수 


  아마 대부분의 문제가 여기에 해당하지 않을까 생각합니다. cron은 별도로 쉘을 띄우기 때문에 프로그램을 실행하기 위해 관련된 환경변수들을 설정해야 한다고 합니다.


2. 권한 문제


  crontab을 설정하는 방법에는 크게 두 가지가 있는데 하나는 /etc/crontab에서 직접 수정하는 것이고 나머지 하나는 crontab -e 명령을 통해 하는 것입니다.


  이 중 vim /etc/crontab 에서 root 권한 명령어를 실행하기 위해서는 root 권한을 명시해줘야 합니다. 반면 crontab -e로 cron을 수정할 때에는 root 권한을 명시할 필요가 없습니다.


vim /etc/crontab        */30 * * * * root /home/hello/test.sh

crontab -e                */30 * * * * /home/hello/test.sh


3. 절대경로 / 상대경로 


   제가 이번에 프로젝트를 진행하면서 한 큰 실수가 있는데 바로 프로그램의 테스트와 config 파일을 상대경로로 해놓고 crontab 에서는 절대경로를 사용했었습니다. 그래서 테스트 할 때 절대경로로 했더니 오류가 뜨더군요;;


  그렇기 때문에 crontab 에 추가하기 전에 절대경로로 먼저 테스트 해보시는 것을 추천합니다.


4. 최소 반복 시간


  그리고 이건 거의 해당하는 일이 없으실거라 생각하는데 crontab의 최소 반복시간은 1분입니다. 따라서 그 보다 작은 시간으로 하려고 하면 당연히 안 되겠지요.






해결방법



  지금부터 위의 오류들을 해결할 수 있는 방법들에 대해서 소개하겠습니다. 언어는 파이썬을 사용할 것입니다.



  우선 환경 변수의 문제에 대해서 입니다. 위에서 언급했다시피 crontab은 별도의 쉘을 띄우기 때문에 별도의 환경변수 설정이 필요합니다. 자세한 내용은 여기에서 보시면 될 것 같습니다. 그리고 환경 변수를 설정하고 crontab 을 설정하는 방법은 아래와 같습니다.

SHELL=/bin/bash
*/10 * * * * source /path/to/virtualenv/bin/activate && /path/to/build/manage.py some_command

  쉘의 경로를 설정하고 10분마다 virtualenv를 activate 하고 manage.py 스크립트를 실행하는 코드입니다. 여기서 핵심은 첫 번째 줄의 SHELL=/bin/bash 이겠지요.


  만약 프로젝트가 virtualenv 내에 있다면 파이썬의 경로를 명시해 줘야 할 수도 있을 것입니다.



  위의 방법들로도 해결이 되지 않는다면 파이썬 스크립트의 맨 위에

#!/home/my/virtual/bin/python
코드를 넣어 보세요. 인터프리터에게 어떤 경로의 파이썬을 사용할 것인지 알려주는 부분입니다.  관련 내용은 이 링크 에서 보실 수 있습니다.
/home/my/virtual/bin/python
  위와 같이 말이죠. 그리고 스크립트를 실행하다가 오류가 발생한 것을 로그로 남기고 싶다면 다음과 같이 하면 됩니다.
python /home/my/project/manage.py > /path/to/cronlog.log 2 > &1
  위의 내용은 이 링크의 내용 기반으로 작성하였습니다.

  그리고 가장 중요한 것이 있는데 crontab -e 또는 vim /etc/crontab 를 통해 저장하고 난 이후 service crond restart 를 해야하는 것입니다. 새로운 작업을 등록해 놓고 서비스를 다시 시작하지 않으면 적용이 되지 않기 때문입니다.


PS.

  이건 제가 직접 해보지 않아서 확실하지 않은 방법입니다만, 명령어들을 crontab에 직접 입력하는 것이 아닌 쉘 파일에서 작성한 후 crontab에서 그 쉘을 실행시키는 것입니다. 이렇게 하면 제대로 실행된다고 하는데 제 생각으로는 저 방법이 자동으로 SHELL=/bin/bash 를 자동으로 해주기 때문인 것 같습니다.

  위 내용의 출처는 여기입니다. 



+ 추가  (2016. 10. 30)

저 같은 경우에는 /etc/crontab 파일을 수정하여 프로세스를 등록하였고 환경변수를


SHELL=/bin/sh

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin


와 같이 설정하였습니다.



'리눅스' 카테고리의 다른 글

[우분투] apt / apt-get 차이  (2) 2016.12.25
우분투 16.04 Octave 설치  (0) 2016.12.09
[리눅스] ds, df  (0) 2016.12.02
[우분투] 멀티부팅 되지 않을 때 해결법  (0) 2016.11.02
[리눅스] 반복 예약작업 crontab  (0) 2016.10.20
블로그 이미지

NCookie

,