Executor 프레임워크를 사용하면 다음과 같은 일들을 처리할 수있습니다.



 - 스레드에서 실행되기를 기다리는 task 수를 제어하는 작업자 스레드 pool과 큐를 설정

- 비정상적으로 종료되는 스레드를 초래하는 에러 확인

- 완료되는 스레드를 기다리고 스레드로부터 결과를 가져온다.

- 스레드의 일괄처리를 실행하고, 고정된 순서로 결과를 가져온다.

- 사용자가 더 빨리 결과를 확인할 수 있도록 알맞은 시간에 백그라운드 스레드를 시작한다.




Excutor 프레임워크의 기본 구셩요소는 Executor 인터페이스다.


이것의 주요목표는 태스크의 생성을 분리하여(Runnnalbe) 앞에서 나열한 응용프로그램 동작들을 가능하게 하는 것이다.



이 인터페이스는 단하나의 메서드를 포함한다.

 public interface Executor{

void execute(Runnalbe command);
}




Executor 로 제어할 수 있는 동작으로는 다음과 같다.


- 태스크 큐잉

- 태스크 실행순서

- 태스크 실행 유형(직렬 또는 동시)




Executor 예제

AsyncTask에서 사용된 직렬 Task 실행자를 구현. SerialExecutor는 생산자-소비자 패턴으로 구현


Thread는 Runnable Task를 생성하고, 큐에 Task를 배치하며, 소비자 스레드는 큐에서 Task 를 제거하고 처리한다.



private static class SerialExecutor implemtents Executor{
final ArrayDeque mTasks = new ArrayDeque();
Runnable mActive;

public synchronized void execute(final Runnable r){

mTasks.offer(new Runnable(){
public void run{
try{
r.run();
}
finally{
scheduleNext();
}
}
});
if( mActive == null){
scheduleNext();
}
protected sysnchronized void scheduleNext(){
if((mActive=mTasks.poll())!= null){
THREAD_POOL_EXECUTOR.excute(mActive);
}
}

}
}





실행자 실행동작특징은 다음과 같다.


- 태스크 큐잉

ArrayDeque - 데큐, 양방향으로 꺼낼 수 있는 큐.

             스레드에 의해 처리될떄까지 삽입된 Task들을 보유한다.


- 태스크 실행순서

모든 태스크는 mTask.offer()를 통해 데큐의 끝에 넣어진다. 따라서

결과는 삽입된 태스크들 fifo 순서다.



- 태스크 실행 유형

Task는 직렬로 실행되지만, 같은 스레드에서 실행될 필요없다.

Task가 실행완료할떄 마다 r.run()이 완료할떄마다, scheduleNext()가 호출된다.

이것은 큐에서 다음 Task를 가져와서 스레드가 Task그를 실행할 수 있는 스레드 풀안의 다른 Executor로 보낸다.



요컨대 SerialExecutor는 각각 다른 스레드에서 Task를 처리할 수 있으며 Task들의 순차적인 실행을 보장하는 실행환경을 

구성한다.


<순차실행이지, 동시실행은 아님>




 body-parser 미들웨어


이번에는 post로 요청했을때 요청 파라미터를 확인할 수 있도록 만들어둔 body-parser 미들웨어에 대해 알아보겠습니다.



get방식으로 요청할떄는 주소 문자열에 요청파라미터가 들어갑니다.


하지만 이와달리 post방식으로 요청할떄는 본문인 본문영역에 요청 parameter

들어있게 되므로 요청 parameter를 파싱하는 방법이 get방식과 다르게 됩니다.



body-parser 미들웨어는 클라이언트가 post 방식으로 요청할때 본문 영역에 들어있는

요청 파라미터들을 파싱하여 요청 객체의 body속성에 넣어줍니다.



다음과 같이 클라이언트 단에서 post 형식으로 전송할 수 있는 form을 생성해보겠습니다.


먼저 클라이언트 단의 login 페이지를 만들어보겠습니다.


public/login.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인 테스트</title>
</head>

<body>
<h1>로그인</h1>
<br>
<form method="post">
<table>
<tr>
<td><label>아이디</label></td>
<td><input type="text" name="id"></td>
</tr>
<tr>
<td><label>비밀번호</label></td>
<td><input type="password" name="password"></td>
</tr>
</table>
<input type="submit" value="전송" name="">
</form>
</body>
</html>





body-parser 모듈을 새로 추가해야됩니다.


다음과 같이 명령 프롬프트에서 입력합니다.

> npm install body-parser --save


다음은 웹서버 입니다.



//Express 기본 모듈 불러오기.

var express = require('express');
var http = require('http');
var static = require('serve-static');
var bodyParser = require('body-parser');
var path = require('path');
//Express 객체 생성
var app = express();

//기본포트를 app 객체에 속성으로 설정
app.set('port', process.env.PORT || 3000);


//body-parser를 사용해 application/x-www-form-urlencoded 파싱
app.use(bodyParser.urlencoded({extended: false}));

//body-parser를 사용해 application/json 파싱
app.use(bodyParser.json());

app.use(static(path.join(__dirname, 'public')));




//미들웨어에서 파라미터 확인
app.use(function(req, res, next){
console.log('첫번째 미들웨어에서 요청을 처리함.');

var paramId = req.body.id || req.query.id;
var paramPassword = req.body.password || req.query.password;

res.writeHead('200',{'Content-type':'text/html;charset=utf8'});
res.write('<h1>express 서버에서 응답한 결과입니다.</h1>');
res.write('<div><p>param id: '+paramId+'</p></div>');
res.write('<div><p>param password: '+paramPassword+'</p></div>');
res.end();
});





//Express 서버 시작
http.createServer(app).listen(app.get('port'), function(){
console.log('Express 서버를 시작했습니다. : '+ app.get('port'));
});


클라이언트에서 요청할떄 get방식으로 요청할지, 아니면 POST방식으로요청할지 모르는 경우엔

어떻게 처리르해야할까요?

두가지 모두 고려하기위해서 다음처럼 두가지 요청 파라미터를 모두 검사합니다.


post 방식 vs get방식 모두 고려!
var paramId = req.body.id || req.query.id;


http://localhost:3000/login.html

아이디와 패스워드를 입력후 전송버튼을 누릅니다.



[결과화면] 


Express 역시 제공되는 middleware 가 있습니다.

대표적으로 static middleware가 있습니다.



static 미들웨어는먼저 static 미들웨어는 특정 폴더의 파일들을 특정path로 접근할 수 있도록 만들어 줍니다.


예시로, public 폴더에있는 모든 파일을 웹서버 root path로 접근할 수 있도록 만들고 싶다면 다음 코드를 추가하면됩니다.


static 미들웨어는 외장 모듈로 만들어져있으며 설치가 필요합니다. 명령프롬프트에서 아래 명령어를  사용해 설치합니다.

> npm install serve-static --save



이코드는 public 폴더안에있는 파일들을 클라이언트에서 바로 접근할 수있게합니다.


만약다음과같이
           /public/index.html 에 파일이있다면

 웹브라우져에서
   === > http://localhost:3000/index.html 처럼 접근할수있습니다.

app.use('/public, static(path.join(__dirname, 'public')));

 



./apps.js

//Express 기본 모듈 불러오기.

var express = require('express');
var http = require('http');
var static = require('serve-static');
var path = require('path');
//Express 객체 생성
var app = express();

//기본포트를 app 객체에 속성으로 설정
app.set('port', process.env.PORT || 3000);


app.use(static(path.join(__dirname, 'public')));


//Express 서버 시작
http.createServer(app).listen(app.get('port'), function(){
console.log('Express 서버를 시작했습니다. : '+ app.get('port'));
});





public/index.html



index.html 입니다.

명령 프롬프트에 다음과 같이명령합니다.
> node app.js

웹브라우져에서 localhost:3000/index.html 을치면 다음과 같은 페이지가 출력되게 됩니다.


Express 요청 객체에 추가한 header와 parameter 분석



[표] Express에서 추가로 사용할 수 있는 요청 객체의 속성들.

 추가한정보          

 설명

 query    

 클라이언트에서 get방식으로 전송한 요청 파라미터를 확인합니다. ex) req.query.name

 body 

 클라이언트에서 POST방식으로 전송한 요청 파라미터를 확인합니다.

단 body-parser와 같은 외장 모듈을 사용해야합니다.

ex) req.body.name

 header(name) 

 헤더를 확인합니다.



요청하는 파라미터는 query string 이라고 합니다. 

클라이언트에서 서버로 요청할떄 문자열로 데이터를 전달하는것을 지칭합니다.


req객체의 query 객체 안에 넣어두어 사용합니다.


client 가 요청할 때 전달되는 헤더값들은 header()메소드로 확인할 수 있습니다.




//Express 기본 모듈 불러오기.

var express = require('express');
var http = require('http');

//Express 객체 생성
var app = express();

//기본포트를 app 객체에 속성으로 설정
app.set('port', process.env.PORT || 3000);



app.use(function(req, res, next){
console.log('첫번째 미들웨어 요청 처리');

var userAgent = req.header('User-Agent');
var paramName = req.query.name;

res.writeHead('200', {'Content-Type': 'text/html; charset=utf8'});
res.write('<h1>Express 서버에서 응답한 결과</h1>');
res.write('<div><p>user-agnet: ' + userAgent + '</p></div>');
res.write('<div><p>Param name: ' + paramName + '</p></div>');
res.end();

});


//Express 서버 시작
http.createServer(app).listen(app.get('port'), function(){
console.log('Express 서버를 시작했습니다. : '+ app.get('port'));
});



웹사이트에서 다음과 같은 url을 입력해봅니다.  query 에 name=jinss값을 넣어서 요청을 합니다.


http://localhost:3000/?name=jinss


[결과화면]



Client가 주소 문자열에 포함시켜 전달하는 요청 parameter를 web server에서 받아 확인할때는 복잡하지만, Express를 사용하면 매우 편하게 확인할 수 있습니다.






Express 의 요청 객체와 응답객체 알아보기



Express에서 추가로 사용할수있는 응답 객체 메소드.


 메소드이름   

 설명

 send([body])

  클라이언트에 응답 데이터를 보냅니다. 전달할 수 있는 데이터는 html 문자열, Buffer 객체, json 객체, json 배열입니다.

 status(code)

 http 상태코드를 반환합니다. 상태코드는 end()나 send()같은 전송 메소드를 추가로 호출해야전송할 수 있습니다.

 sendStatus(statusCode)

 http 상태 코드를 반환합니다. 상태코드는 상태메세지와함꼐 전송됩니다.

 redirect([status,] path)

 웹페이지 경로를 강제로 이동시킵니다.

 render(view[,locals][,callback])

 뷰엔진을 사용해 문서를 반든 후 전송합니다.


다음 아래와 같이, response (응답) 객체를 사용해보았습니다.


response 객체의 send method 사용예제입니다.



//Express 기본 모듈 불러오기.

var express = require('express');
var http = require('http');

//Express 객체 생성
var app = express();

//기본포트를 app 객체에 속성으로 설정
app.set('port', process.env.PORT || 3000);

//첫번째 미들웨어
app.use(function(req, res, next){
console.log("첫번째 미들웨어에서 요청을 처리함.");
res.send({name:'소녀시대', age:20});
next();
});


//Express 서버 시작
http.createServer(app).listen(app.get('port'), function(){
console.log('Express 서버를 시작했습니다. : '+ app.get('port'));
});




response 객체의 redirect 사용예제입니다.


//Express 기본 모듈 불러오기.

var express = require('express');
var http = require('http');

//Express 객체 생성
var app = express();

//기본포트를 app 객체에 속성으로 설정
app.set('port', process.env.PORT || 3000);



app.use(function(req, res, next){
console.log("첫번째 미들웨어에서 요청을 처리함.");
res.redirect('http://google.co.kr');
});


//Express 서버 시작
http.createServer(app).listen(app.get('port'), function(){
console.log('Express 서버를 시작했습니다. : '+ app.get('port'));
});


노드 서버를 실행후, 127.0.0.1:3000 으로접속하면 google로 redirect되는것을 확인하실 수 있습니다.






node.js middleware 사용


Middleware란 Client의 요청이 들어왔을 때 매번 수행되어야할 행위들을  말합니다.


미들웨어를 전부통과하고나서 적절한 response를 client에게 주도록 설계합니다.



//Express 기본 모듈 불러오기.

var express = require('express');
var http = require('http');

//Express 객체 생성
var app = express();

//기본포트를 app 객체에 속성으로 설정
app.set('port', process.env.PORT || 3000);

//첫번째미들웨어 등록
app.use(function(req, res, next){
console.log('첫 번째 미들웨어에서 요청을 처리함.');
req.user ='jinss';
next();
});
//두번째 미들웨어 등록
app.use('/', function(req, res, next){
console.log('두 번째 미들웨어에서 요청을 처리함.');
res.writeHead('200', {'Content-Type': 'text/html; charset=utf8'});
res.end('<h1>Express 서버에서' +req.user+'가 응답한 결과</h1>');
});


//Express 서버 시작
http.createServer(app).listen(app.get('port'), function(){
console.log('Express 서버를 시작했습니다. : '+ app.get('port'));
});


[서버실행 화면]



[웹브라우저 접속시 웹브라우저 화면]


[서버 콘솔 응답]



middleware 는 위에서 아래로 등록한 순서대로 실행을 타게 됩니다.


첫번째 middleware 에서는 req객체에 user속성을 추가하고 그값으로 문자열을 하나 넣습니다.

두번째 middleware에서 req객체에 설정된 user속성을 확인하여 사용자 정보를 사용할 수 있습니다.



참고>>

middleware 안에서는 기본적으로 요청 객체인 req와 응답객체인 res 객체를 Parameter로 전달받아 사용할수있습니다.



그리고 이 middleware함수를 호출한 app객체도 참조할수있습니다.

req.app 코드를 사용하면 app 객체 참조가능합니다.



middleware함수를 보면 요청 객체와 응답 객체가 파라미터로 전달되며, 그다음 middleware로

넘길 수 있는 next 함수 객체도 전달됩니다. 따라서 next 함수 객체를

실행하면 다음middleware로 넘길 수 있습니다.



middleware를 사용하기 위해서 먼저 use() 메소드를 호출해야하며, middleware 2개를 등록했습니다.



익스프레스 (Express) 웹 서버 만들기


http모듈만 사용해서 웹서버를 만들기엔 직접만들어야할것들이 많습니다.

그렇기때문에 보통 노드로 웹서버를 구현할때는 Express를 이용하는 편입니다.



그리고 Express에서 제공하는  middlewarerouter를 사용하면 훨씬 편리하게 구성할수있게됩니다.



-새로운 Express(익스프레스) Server 만들기.


명령프롬프트에 다음과 같이 입력합니다.

> npm init

> npm install express --save                           //express 모듈을 설치하기 위한 명령어입니다

app.js 파일의 코드는 아래와 같습니다.


//Express 기본 모듈 불러오기.

var express = require('express');
var http = require('http');
// 참고로 expree와 http는 내장모듈입니다.
// 그리고 express 모듈은 웹서버를 위해 만들어진것으로 http 모듈 위에서 동작합니다.
// 따라서 express 모듈을 사용할때는 항상 http 모듈도 함꼐 불러들여야 합니다.



//Express 객체 생성
var app = express();

//기본포트를 app 객체에 속성으로 설정
app.set('port', process.env.PORT || 3000);

//Express 서버 시작
http.createServer(app).listen(app.get('port'), function(){
console.log('Express 서버를 시작했습니다. : '+ app.get('port'));
});


[결과화면]


app 객체는 express() 메소드를 호출로만들어지는 익스프레스 서버 객체입니다.



express() 메소드를 호출하여 만든 app 객체의 주요 method

 메소드 이름 

  설명

 set(name,vlaue)

 서버 설정을 위한 속성을 지정합니다. set() 메소드로 지정한 속성은 get()메소드로 꺼내어 확인할 수 있습니다.

 get(name)

 서버 설정을 위해 지정한 속성을 꺼내옵니다.

 use([path,] function[,function...])

 미들웨어 함수를 사용합니다.

 get([path,] function)

 특정패스로 요청된 정보를 처리합니다.




서버 설정을 위해 미리 정해진 app 객체의 주요 속성

 속성이름   

 설명

 env   

 server mode를 설정합니다.

 views

 view 들이 들어있는 폴더 또는 폴더 배열을 설정합니다.

 view engine

 default로 사용할 view engine을 설정합니다.


node.js (노드) get, post 요청 구현



http 모듈을 사용해 get 방식으로 다른 사이트 데이터를 요청하는 예제입니다.




var http = require('http');

var options ={
host: 'www.google.com',
port:80,
path: '/'
};

var req = http.get(options, function(res){
//응답처리
var resData = '';
res.on('data', function(chunk){
resData += chunk;
});

res.on('end', function(){
console.log(resData);
});

res.on('error', function(err){
console.log("오류발생: "+ err.message);
});

});



[결과화면]



http 객체 get() 메소드를 사용하면 다른 사이트에 요청을 보내고

응답을 받아 처리할 수 있습니다.


get()  메소드의 첫번째 파라미터는 다른 사이트의 정보를 담고있는 객체입니다. 그리고 두번째 parameter는 callback 함수 입니다.


응답 데이터를 받을떄는 data이벤트와 end 이벤트로 처리하면됩니다.


모두 resData 변수에 담아 두었고 event가 끝나는 시점에 console 창에 출력하게 됩니다.






post 방식

아래는 post방식입니다.



var http = require('http');

var opts = {
host: 'www.google.com',
port: 80,
method: 'POST',
path: '/',
header: {}
};


var resData = '';

var req = http.request(opts, function(res){
//응답처리
res.on('data', function(chunk){
resData += chunk;
});


res.on('end', function(){
console.log(resData);
});
});

opts.headers['Content-Type'] = 'application/x-www-form-urlencoded';
req.data = 'q=actor';
opts.headers['Content-Length'] = req.data.length;

req.on('error', function(err){
console.log("오류발생:"+ err.message);
})

//요청전송
req.write(req.data);
req.end();



웹 브라우저가 server에 요청을하면, 그때마다 서버에서 발생하는 이벤트를 정의해야합니다.

그럴때는 callback 함수를 등록하면 됩니다.


표는 서버객체에서 사용할 수 있는 이벤트들입니다.



node.js server 객체에서 사용할 수 있는 event 입니다.

 이벤트이름         

 설명

 connection

  클라이언트가 접속하여 연결이 만들어질 때 발생하는 이벤트입니다.

 request       

 클라이언트가 요청할 떄 발생하는 이벤트입니다.

 close         

  서버를 종료할때 발생하는 이벤트입니다.






var http = require('http');

//웹서버 객체 생성
var server = http.createServer();

//웹서버 시작하여 3000번 포트에서 대기 설정
var port = 3000;
server.listen(port, function(){
console.log('웹서버가 시작되었습니다.:% d', port);
});

//클라이언트 연결 이벤트 처리

server.on('connection', function(socket){
var addr = socket.address();
console.log('클라이언트가 접속했습니다.: %s, %d', addr.address, addr.port);
});
//클라이언트 요청 이벤트 처리
server.on('request', function(req, res){
console.log("클라이언트 요청이 들어왔습니다.");
console.dir(req);
res.writeHead(200, {"content-type":"text/html; charset=utf-8"});
res.write("<!DOCTYPE html>");
res.write("<html>");
res.write(" <head>");
res.write(" <title>응답페이지</title>");
res.write(" </head>");
res.write(" <body>");
res.write(" <h1>노드제이에스로부터 응답 페이지!</h1>");
res.write(" </body>");
res.end();
});
//서버종료 이벤트 처리
server.on('close', function(){
console.log('서버가 종료됩니다.');
});



서버 실행화면




웹브라우저와 클라이언트가 웹서버에 연결되면 connection 이벤트 발생! => server.on 에 등록한 콜백메소드가 호출되는것 확인가능합니다.



클라이언트가 특정path로 요청하면 request 이벤트가 발생합니다.

'request'라는 이름으로 콜백메소드를 등록했기에

"클라이언트 요청이들어왔습니다." 문구 확인가능합니다.



웹브라우져를 켜고, 127.0.0.1:3000 으로 접속합니다. 그러면 아래와같은 서버에서 응답, 그리고 웹브라우져에서 응답을 보실수있습니다.

서버(콘솔창) 응답.


웹페이지 응답.




또한, res객체에 writeHead(), write(), end() 메소드를 사용하면

클라이언트로 응답을 보낼 수 있음. end() 메소드는 응답을 보냈다는것을 의미합니다.




응답(response) 객체의 주요 메서드


  메소드 이름  

  설명

   writeHead(statusCode             

     [, statusMessage][,headers])


  응답으로 보낼 헤더를 만듭니다.

  write(chunk[, encoding][, callback]) 

 응답본문(body)데이터를 만듭니다. 여러번 호출될 수 있습니다.

 end([data][,encoding][,callback])

 클라이언트로 응답을 전송합니다. 파라미터에 데이터가 들어있다면 이 데이터를 포함시켜 응답을 전송합니다.

 클라이언트의 요청이 있을 때 한번은 호출되어야 응답을 보내며, 콜백함수가 지정되면 응답이 전송된후 

 콜백함수가 호출됩니다.



<<참고 

Content-Type에 설정할 수 있는 대표적인 MIME Type


 Content Type의 값

 설명

 text/plain

 일반 텍스트문서

 text/html 

 HTML문서

 text/css

 CSS문서

 text/xml

 XML 문서

 image/jpeg, image/png

 JPEG파일, PNG 파일

 video/mpeg, audio/mp3

 MPEG 비디오파일, MP3음악파일

 application/zip

 zip 압축파일








 노드 기본 http 모듈을 사용하면 웹서버기능을 담당하는 서버 객체를만들 수 있습니다.



var http = require('http');

//웹서버 객체 생성
var server = http.createServer();

//웹서버를 시작하여 3000번 포트에서 대기합니다.
var port = 3000;
server.listen(port, function(){
console.log('웹 서버가 시작되었습니다. : %d', port);
});





node.js server 객체의 메소드


Method 이름 

 설명 

 listen(port, [hostname], [backlog], [callback]) 

 서버를실행하여 대기시킵니다.

 close([callback])   

 서버를 종료합니다.




var http = require('http');

//웹서버 객체 생성
var server = http.createServer();

//웹 서버를 시작하여 127.0.0.1 ip와 3000번 포트에서 대기하도록 설정
var host = '127.0.0.1';
var port = 3000;
server.listen(port, host, '50000', function(){
console.log("웹서버가 시작되었습니다.: %s, %d",host, port);
});






+ Recent posts