Network2017. 8. 4. 04:14

RaspberryPi를 이용한 Web/FTP 서버 구축

 

RaspberryPi를 이용해 Web/FTP 서버를 구축하여 웹 개발 환경을 구축해본다.

 

RaspberryPi Raspbian 설치하기

https://www.raspberrypi.org/downloads/raspbian/에 들어가서 Raspbian을 다운로드 받는다. Raspbian은 라즈베리파이용으로 개발된 데비안 계열 OS, GUI raspbian에서 제공하는 다른 선택 요소들이 필요하면 with desktop 버전을, 필수적인 요소만 필요한 경우에는 lite 버전을 설치하면 된다.



Raspberry Pi의 저장장치는 유일하게 Micro SD카드로 한정되어 있다. , SD카드에 Raspbian Flashing 하고 Raspberry PiSD카드를 삽입해 부팅해야 한다. Micro SD카드에 Flashing 하기 위한 툴로 ‘Etcher’를 사용하겠다.

https://etcher.io/



다운로드 받은 Raspbian 이미지를 선택하고 설치할 Storage를 선택하고 Flash를 누르면 위와 같이 SD카드에 Flashing 되는 것을 볼 수 있다.

LITE 버전은 GUI를 제공하지 않아 Terminal에서 조작해야 하므로, SSH raspberry pi를 조작하도록 하겠다.


여기서 주의할 점이 있다. Raspbian Flashing하고 바로 Raspberry Pi에 삽입해 SSH 툴로 접근하려고 하면 연결이 거부된다. 구 버전에서는 SSH 연결 허용 여부의 기본값이 허용이었던 것에 반해, 최신 버전은 SSH 연결 허용 여부가 보안상 문제로 허용하지 않는 것으로 바뀌었다. 이를 해결하기 위해서는 Flashing 작업이 끝난 다음에 해당 Storage에 들어가서 SSH라는 이름의 확장자 없는 파일을 생성해줘야 한다.


 

SSH로 접속하기 위해서 Raspberry Pi Local Address를 알아야 한다. 라즈베리파이로 부팅해 ifconfig를 실행해 확인하는 방법도 있고, 공유기 설정에서 연결된 장치를 확인해 주소를 알아낼 수도 있다. 이 과정은 간단하므로 사진을 생략한다.

 

Update FTP 설정

먼저 apt-get을 업데이트 해준다.


sudo apt-get update



Raspbian 구 버전은 일정 용량이 넘어서는 storage 같은 경우 storage의 용량 전체 중 일부만 인식해 따로 확장하는 과정이 필요했지만, 최신 버전은 storage의 원 용량 그대로 사용할 수 있다.




이제 ftp 모듈을 설치한다.

sudo apt-get install vsftpd


설치 후 vsftpd의 설정을 수정한다.


sudo vi /etc/vsftpd.conf



listen = YES

anonymous_enable=NO

local_enable=YES

write_enable=YES

해당하는 것을 찾아서 위와 같은 옵션으로 바꾸어주고 저장한다. 바꾼 옵션을 적용하기 위해서 vsftpd를 재시작한다.


sudo service vsftpd restart



이제 정상적으로 작동하는지 ftp 클라이언트를 이용해 로그인해본다. 널리 쓰이는 ftp 클라이언트로는 filezilla가 있다.



호스트에 Raspberry Pi Local Address, 사용자명에 pi, 비밀번호에 pi의 비밀번호를 입력하고 빠른 연결을 클릭하면 정상적으로 연결되는 것을 확인할 수 있다.



 

APM 설정

APM Apache + PHP + MySQL을 뜻한다. APM을 사용하는 웹서버를 구성해보겠다.


sudo apt-get install apache2

sudo service apache2 start


설치 후, apache가 잘 실행되고 있는지 확인해본다.


ps –ef|grep apache



잘 실행되고 있는 것을 볼 수 있다. Raspberry PiLocal Address를 브라우저의 URL 입력란에 입력해서 접속해보면 다음과 같은 페이지를 볼 수 있다.



Apache가 설치되었을 때 웹 페이지 구성 파일의 기본 참조 경로는 /var/www/html이다. 필자는 이것을 ftp 서버와 연동해서 사용하고 싶기 때문에 /home/pi/kiwi/www로 경로를 변경하고 싶다.



기본 참조 경로를 변경하기 위해서는 /etc/apache2/apache2.conf 파일과 /etc/apache2/sites-available/000-default.conf 파일을 수정해야 한다.



apache2.conf 파일에서 세번째 <Directory [dir]>에서 dir 부분을 원하는 경로로 수정한다. 앞서 말했듯, 기본값은 /var/www이다.



000-default.conf에서는 빨간 네모친 부분만 위와 같이 수정해주면 된다. 당연히 서버 이름과 allias, admin은 마음대로 작성해도 되고, DocumentRoot 항목만 원하는 경로로 수정하면 된다.

정상적으로 참조 경로가 바뀌었는지 확인하기 위해, 해당 경로로 이동해 index.html을 대충 작성한다.





 

이제 PHP를 설치한다.


sudo apt-get install php

sudo apt-get install libapache2-mod-php


설치 후 test.php를 다음과 같이 작성하고 [Raspberry Pi Local Address]/test.php를 입력해 정상적으로 출력되는지 확인한다. 당연히 test.phpapache2의 참조 경로에 위치하고 있어야 한다.


<?php

phpinfo();

?>



결과는 다음과 같다.



 

마지막으로 mysql을 설치한다.


sudo apt-get install mysql


php와 연동하기 위해서 php-mysql 패키지를 설치한다.


sudo apt-get install php-mysql


실제로 사용할 생각은 없지만 php와 연동해 DB를 관리할 수 있게 도와주는 phpmyadmin도 설치해본다.


sudo apt-get install phpmyadmin


설치 후 URL에 경로를 입력하는 것 만으로 사용하고 싶다면 phpmyadmin 폴더를 변경한 참조 경로로 옮겨줘야 한다.



 

외부에서의 접근 허용

지금까지 설정한 것이 공유기가 아닌 직접 WAN에 연결했다면 Raspberry Pi가 단순히 위에서 했던 작업들만 거치면 아이피를 입력했을 때 외부에서 이미 접근이 허용되었을 것이다. 하지만 대부분의 경우 WAN을 공유기에 연결하고 공유기에 데스크톱, Raspberry Pi 등을 연결해 사용하기 때문에, 공유기에서 포트포워딩 설정을 해주는 과정을 거쳐야한다.

먼저 Raspberry Pi가 공유기에 접속할 때 마다 다른 Local Address를 가지게 되면 굉장히 귀찮아지기 때문에 주소를 고정시켜준다. (공유기는 DHCP 방식으로 Local IP를 접속한 순서대로 할당해주기 때문에 주소가 바뀔 수 있다.)



그 후 포트포워딩 설정에 들어가서 Raspberry Pi 80번 포트로 포워딩 시켜준다.



위와 같이 80번 포트 뿐 아니라 22번 포트도 포워딩 시켜주게 되면 Local Network가 아니더라도 언제든지 putty를 이용해 Raspberry Pi SSH 접속을 할 수 있다.

또한 FTP 서버는 20~21번 포트를 사용하기 때문에 외부에 열린 포트를 20~21번 포트에 포워딩 시키면 외부 네트워크에서 FTP 서버를 사용할 수 있다.

Posted by BinZIP
Programming/Web Programming2017. 7. 22. 14:31

JavaScript #7 – Object-Oriented (객체지향)

Prototype

객체의 원형. 객체는 property를 가질 수 있는 것은 그 동안 계속 봐왔던 사실임. 그 중 prototype이라는 property는 용도가 약속되어 있음.

Prototype에 저장된 속성들은 생성자를 통해서 객체가 만들어질 때 그 객체에 연결됨.


function Ultra(){}

Ultra.prototype.ultraProp = true;

 

function Super(){}

Super.prototype = new Ultra();

 

function Sub(){}

Sub.prototype = new Super();

 

var o = new Sub();

console.log(o.ultraProp);



생성자 Sub를 통해 만들어진 객체 o에서 ultraProp을 찾을 때 실제로는 o, Sub.prototype, Super.prototype, Ultra.prototype에서 ultraProp을 차례로 찾게 됨. , prototype은 객체와 객체를 연결하는 연결고리 역할을 함. 그래서 이러한 관계를 ‘Prototype Chain’ 이라고 함.

 

Standard Built-in Object (표준 내장 객체)

JavaScript가 기본적으로 가지고 있는 객체. 프로그래밍을 하는데 기본적으로 필요한 도구들.

내장 객체에는 object, function, array, string, Boolean, number, math, date, RegExp가 있음.


var arr = new Array('seoul','new york','ladarkh','pusan', 'Tsukuba');

function getRandomValueFromArray(haystack){

    var index = Math.floor(haystack.length*Math.random());

    return haystack[index];

}

alert(getRandomValueFromArray(arr));

 

위 코드는 배열에서 랜덤한 요소 하나를 가지고 오는 코드임. 그런데 저 코드를 array라는 표준내장 객체에 포함시키면, 모든 array가 마치 원래 array 객체의 메소드인 것처럼 위의 기능을 사용할 수 있음.


Array.prototype.rand = function(){

    var index = Math.floor(this.length*Math.random());

    return this[index];

}

var arr = new Array('seoul','new york','ladarkh','pusan', 'Tsukuba');

alert(arr.rand());

 

Object

Object 객체는 객체의 가장 기본적인 형태를 가지고 있는 객체. 아무것도 상속받지 않는 객체임.

JavaScript의 모든 객체는 Object 객체를 상속받기 때문에 모든 객체는 Object 객체의 Property를 가지고 있음. 또한 Object 객체를 확장해 모든 객체가 접근할 수 있는 API를 만들 수 있음.

 


Object.prototype.contain = function(neddle) {

    for(var name in this){

        if(this[name] === neddle){

            return true;

        }

    }

    return false;

}

var o = {'name':'BinZIP', 'city':'seoul'}

alert(o.contain('BinZIP'));

var a = ['BinZIP','supernice','bin'];

alert(a.contain('supernice'));

 


두 번의 alert 모두 True라고 출력되는 것을 확인할 수 있음.

하지만 Object 객체는 확장하지 않는 것이 좋음. 모든 객체에 영향을 주기 때문에 객체가 기본적으로 가지고 있을 것으로 예상하고 있는 객체 외에 다른 객체를 가지고 있는 것은 혼란스러울 수 있기 때문.


for(var name in o){

    console.log(name); 

}

 


이런 문제를 회피하기 위해서는 해당 객체의 소속인지 확인할 수 있는 hasOwnProperty를 사용할 수 있음.


for(var name in o){

    if(o.hasOwnProperty(name))

        document.write(name+'<br/>'); 

}



 

Data Type

데이터 타입이란 데이터의 형태를 의미함. 데이터 타입은 크게 객체와 객체가 아닌 것, 이 두 가지로 구분할 수 있음.

객체가 아닌 것에는 숫자, 문자열, Boolean(True/False), null, undefined가 있다. 이런 객체가 아닌 데이터 타입을 Primitive Type(원시 데이터 타입)이라고 함. 그 외 모든 데이터 타입들은 객체임.

그런데 아래 코드를 보자.


var str='hello';

document.write(str.length);

document.write('<br/>');

document.write(str.charAt(0));




문자열에 property와 메소드가 있음. 그렇다면 객체라는 의미인데, 문자열은 객체가 아니라고 했음. 이는 내부적으로는 문자열이 Primitive Type이고 문자열 관련 어떤 작업을 하려고 할 때 JavaScript가 임시로 문자열 객체를 만들어 사용하고, 사용이 끝나면 제거하기 때문임.


문자열이 Primitive Type이지만 이와 관련해 필요한 기능성을 객체지향적으로 제공해야 하는 필요 또한 있기 때문에, Primitive Type을 객체처럼 다룰 수 있도록 제공하는 객체가 있음. 이를 Wrapper Object(레퍼객체)라고 부름. Wrapper Object에는 String, Number, Boolean이 있음.

 

참조

다음 코드를 보자.


var a = {'id':1};

var b = a;

alert(b.id);



1이라는 것을 당연히 예상할 수 있음. 그렇다면 다음 코드의 결과를 예측해보자.


var a = {'id':1};

var b = a;

b.id=2;

alert(a.id);




결과는 2. B id의 값을 2로 변경했는데 aid의 값도 2가 되었음. 이는 변수 b a에 담긴 객체가 서로 같음을 의미함.

이는 b에 새로운 객체가 복제되어 생성되는 것이 아니라, a의 객체를 참조하고 있다는 의미임.

그런데, 아래 코드를 보자.


var a = 1;

var b = a;

b = 2;

alert(a+' '+b);




여기서는 a의 값이 바뀌지 않았음. , Primitive Type은 복제되어 들어가고, 객체는 참조함을 확인할 수 있음.


그렇다면 함수에 참조 데이터 타입을 넘겨주면 어떻게 될까? 다음 코드를 보자.


var a = {'id':1};

function func(b){

    b = {'id':2};

}

func(a);

alert(a.id);




함수 func의 파라미터 b로 전달된 값은 객체 a. B를 새로운 객체로 대체하는 것은 b가 가지고 있는 객체를 변형하는 것이기 때문에 객체 a에 영향을 주지 않음. 하지만 아래는 다름.


var a = {'id':1};

function func(b){

    b.id = 2;

}

func(a);

alert(a.id);



이는 b에 새로운 객체를 만들어 적용하는 것이 아닌 참조된 a에 있는 reference의 속성을 바꾸고 있으므로, 그 속성이 소속된 객체를 대상으로 수정한 것임. 그렇기 때문에, aid의 값이 변경됨.

'Programming > Web Programming' 카테고리의 다른 글

[PHP] 카카오톡 자동 응답 봇 구현  (0) 2018.01.07
JavaScript Basic #6  (0) 2017.07.21
JavaScript Basic #5  (0) 2017.07.18
JavaScript Basic #4  (0) 2017.07.18
JavaScript Basic #3  (0) 2017.07.16
Posted by BinZIP
Programming/Web Programming2017. 7. 21. 16:40

JavaScript #6 – Object-Oriented (객체지향)

 

Object-Oriented Programming

객체지향프로그래밍(OOP): 로직을 상태와 행동(변수와 메소드)로 나누고 연관된 것들끼리 그룹핑한 것을 객체라 하고 이를 조립해 프로그래밍을 하는 것.

객체지향의 여러 가지 특성

1.     부품화: 프로그램의 로직들을 기능별로 나눠 부품화하는 것

2.     은닉화, 캡슐화: 로직을 온전히 부품화하기 위해 내부동작법은 숨기고 사용법만 노출하는 것

3.     인터페이스: 부품들간의 접점에서의 규칙, 약속

4.     객체지향은 코드의 재활용성을 높임.

 

객체

객체: 서로 연관된 변수와 함수를 묶은 것

메소드: 객체를 구성하는 함수

생성자: 객체를 만드는 역할을 하는 함수. JavaScript에서 함수는 재사용 가능한 로직의 묶음이 아니라 객체를 만드는 창조자임.


function Person(name){

    this.name = name;

    this.introduce = function(){

        return 'My name is '+this.name;

    }  

}

var p1 = new Person('BinZIP');

document.write(p1.introduce()+"<br />");

 

var p2 = new Person('supernice');

document.write(p2.introduce());



생성자 내에서 객체의 Properties를 정의하는 작업을 초기화라고 함.

생성자 함수는 일반 함수와 구분하기 위해 첫 글자를 대문자로 표시.

 

전역객체

모든 객체는 전역객체의 Property. 그리고 모든 전역변수와 함수는 window 객체의 Properties. 객체를 명시하지 않으면 임시적으로 window property로 간주됨.


var o = {'func':function(){

    alert('Hello?');

}}

o.func();

window.o.func();



Hello?가 두 번 alert 되는 것을 확인할 수 있음. 이에 따라 모든 객체가 기본적으로 전역객체의 property임을 알 수 있음.

 

This

This는 함수 내에서 Context of Calling Function(함수 호출 맥락)을 의미함. 맥락이라는 의미에 따라서, 함수를 어떻게 호출하느냐에 따라 this가 가리키는 대상이 달라짐.

함수를 호출했을 때 this는 전역객체인 window와 같음.


function func(){

    if(window === this){

        document.write("window === this");

    }

}

func();




참고로, 웹브라우저 JavaScript의 전역객체는 window이지만, node.js의 전역객체는 global. 이들의 구성 메소드는 차이가 있기 때문에 알고 있어야 함.

 

객체 소속의 메소드의 this는 그 객체를 가리킴.

 

var o = {

    func : function(){

        if(o === this){

            document.write("o === this");

        }

    }

}

o.func();



 

아래 코드는 함수를 호출했을 때와 new를 이용해서 생성자를 호출했을 때의 차이임


var funcThis = null;

 

function Func(){

    funcThis = this;

}

var o1 = Func();

if(funcThis === window){

    document.write('window <br />');

}

 

var o2 = new Func();

if(funcThis === o2){

    document.write('o2 <br />');

}



생성자는 빈 객체를 만듬. 그리고 이 객체 안에서 this는 만들어진 객체를 가리킴.

생성자가 실행되기 전까지는 객체는 변수에도 할당될 수 없기 때문에 this가 아니면 객체에 대한 어떠한 작업을 할 수 없음.

Apply, call 함수 메소드를 사용하면 this의 값을 제어할 수 있음


var o = {}

var p = {}

function func(){

    switch(this){

        case o:

            document.write('o<br />');

            break;

        case p:

            document.write('p<br />');

            break;

        case window:

            document.write('window<br />');

            break;         

    }

}

func();

func.apply(o);

func.apply(p);



 

상속

객체의 로직을 그대로 물려 받는 또 다른 객체를 만들 수 있는 기능. 하지만 단순히 물려받는 것이라면 의미가 없음. 기존의 로직을 수정하고 변경해서 파생된 새로운 객체를 만들 수 있게 해줌.


function Person(name){

    this.name = name;

    this.introduce = function(){

        return 'My name is '+this.name;

    }  

}

var p1 = new Person('BinZIP');

document.write(p1.introduce()+"<br />");

 


이 코드는 위에서 다뤘던 코드임. 이 코드를 다음과 같이 수정함.


function Person(name){

    this.name = name;

}

Person.prototype.name=null;

Person.prototype.introduce = function(){

    return 'My name is '+this.name;

}

var p1 = new Person('egoing');

document.write(p1.introduce()+"<br />");

 

수정한 코드에 새로운 Programmer라는 생성자를 만들고 이 생성자의 prototype Person 객체를 연결해봄.


function Person(name){

    this.name = name;

}

Person.prototype.name=null;

Person.prototype.introduce = function(){

    return 'My name is '+this.name;

}

 

function Programmer(name){

    this.name = name;

}

Programmer.prototype = new Person();

 

var p1 = new Programmer('BinZIP');

document.write(p1.introduce()+"<br />");



Person 객체의 메소드 introduce Programmer 객체도 사용할 수 있음을 확인함. Programmer Person의 기능을 상속하고 있는 것. 하지만 단순히 똑같은 기능을 갖게 되는 것이 아니라, 부모의 기승을 계승 발전할 수 있는 것이 상속의 가치임.

 

function Person(name){

    this.name = name;

}

Person.prototype.name=null;

Person.prototype.introduce = function(){

    return 'My name is '+this.name;

}

 

function Programmer(name){

    this.name = name;

}

Programmer.prototype = new Person();

Programmer.prototype.job = function(){

    return "Job : Programmer";

}

 

var p1 = new Programmer('BinZIP');

document.write(p1.introduce()+"<br />");

document.write(p1.job()+"<br />");



ProgrammerPerson의 기능을 가지면서 job이란 메소드를 부가적으로 가지고 있음을 확인할 수 있음.

 

 

'Programming > Web Programming' 카테고리의 다른 글

[PHP] 카카오톡 자동 응답 봇 구현  (0) 2018.01.07
JavaScript Basic #7  (0) 2017.07.22
JavaScript Basic #5  (0) 2017.07.18
JavaScript Basic #4  (0) 2017.07.18
JavaScript Basic #3  (0) 2017.07.16
Posted by BinZIP