본문 바로가기

블록체인 기반 핀테크 및 응용 SW개발자 양성과정 일기

[119일차 복습] 블록체인 네트워크 웹소켓 http ws 웹서버 구축

반응형

 

1) Server - Client Server 구축하기 (Node.js / express) 

 

1) 기본 server 구축 

블록체인은 탈중앙화이지만 지금 구축하는 웹서버는 중앙 서버가 존재하는 하이브리드형 블록체인 p2p이다. 웹서버를 구축하는 이유 : 블록 가져오기 / peer / 간단한 기록 / 버전 / 중단 기능을 위함 ! 

 

p2p에 대한 자세한 포스팅

https://blckchainetc.tistory.com/333

 

[블록체인] P2P란? Peer-to-Peer Network

비트코인 처음 개발한 사토시 나카모토의 비트코인 논문에 보면 Peer to Peer 를 찾을 수 있다. P2P (Peer-to-Peer network) 란? = 동등 계층간 통신망으로도 불린다. 순수 P@P 파일 전송 네트워크는 Client or S.

blckchainetc.tistory.com

 

 

경로 src 에서 express 설치 

npm i express

어제 만든 폴더 > src 폴더 > server.js 파일 생성 + 기본 코드 작성

const express = require('express');
const app = express();
const port = process.env.PORT || 3000; 


app.listen(port, ()=>{
    console.log(`server start port ${port}`)
})

=> node server.js 서버 on => console.log 잘 나오는지 확인 

굳굳

 

 

 

 

 

** 윈도우에서의 환경변수 설정 

위의 코드에 process.env.[변수명]을 적어서 환경변수를 사용할 수 있다. 

 

환경변수 설정 / 확인 방법 on Windows

set [변수명]=값
set [변수명]

 

on Mac or Linux 

export [변수명]=값

 

 

 

2) blocks.js 가져오기  +  app.get '/blocks' 으로 Blocks 가져오기 

json으로 대화하므로 ! body-parser 설치 / 가져오기 / 사용하기 

npm i body-parser

server.js

const express = require('express');
const app = express();
const port = process.env.PORT || 3000; 
const bodyParser = require('body-parser');

app.use(bodyParser.json());

block.js - block.js module 화 하기 

module.exports = {
    getBlocks, getVersion, addBlock, getLastBlock,
}

server.js blocks 객체로 가져오기 + /blocks app.get 작성

const express = require('express');
const app = express();
const port = process.env.PORT || 3000; 
const bodyParser = require('body-parser');
const bc = require('./block');   // -> 요렇게 변수로 가지고만 와도 server.js실행 시 bc도 실행된다.

app.use(bodyParser.json());

app.get('/blocks', (req,res)=>{
    res.send(bc.getBlocks());
})

app.listen(port, ()=>{
    console.log(`server start port ${port}`)
})

 

=> bc 변수로 가져오기만 해도 server.js를 실행시키면 bc (block.js) 도 실행된다. 

 

 

 server on => window terminal Linux에서 응답 확인해보기 

curl -X GET http://localhost:3000/blocks

curl http://localhost:3000/blocks 

* json 형태로 나오도록 하려면 python 설치된 상태에서 아래 명령어 입력 
curl -X GET http://localhost:3000/blocks python -m json.tool

 

 

< Linux 명령어 >

curl         :  http 통신 할거야 
-            :  옵션이 있어
-X           :  request Method (ex. POST, GET,,,) 
-H           :  Header 
-D           :  Data 

 * -D data를 보낼 때 ↓↓
-d "{\"data\":[\"Helloooo\"]}"   => "{"data":["hello"]}" 
쌍따옴표로 감싸는 스트링 안에 쌍따옴표를 쓸 떄는 \" <- 요렇게 적어주기ㅣ 

 

 

 

 

 

3. Version 확인하기 

server.js - app.get('/version') 추가 

const express = require('express');
const app = express();
const port = process.env.PORT || 3000; 
const bodyParser = require('body-parser');
const bc = require('./block'); 

app.use(bodyParser.json());

app.get('/blocks', (req,res)=>{
    res.send(bc.getBlocks());
})

app.get('/version', (req,res)=>{
    res.send(bc.getVersion());
})

app.listen(port, ()=>{
    console.log(`server start port ${port}`)
})

Comman on Linux 

curl -X GET http://localhost:3000/version      //  or 
curl http://localhost:3000/version -X GET  

Comman on Window browser 

 

 

 

4. 방금 구축한 Client-Server 웹서버에서 '블록' 추가해보기 

 

src > server.js

// 블록 추가하기
app.post('/mineBlock', (req,res)=>{
    let {data} = req.body;
    const result = bc.addBlock(data);
    if(result==false){
        res.send('mineBlock(addBlock) failed')
    }else{
        res.send(result)
    }
})

req.body = POST 

리눅스에서 명령어를 입력할 때, data를 입력할 예정! 

bc(block.js)의 addBlock() 함수 에서 return하는 값이 없으므로 수정 

 

block.js 

// 새로운 block을 간단히 추가하는 함수 
function addBlock(data){
    const newBlock = nextBlock(data);
    
    if(isValidNewBlock(newBlock, getLastBlock()) && isValidBlocks(Blocks)){
        Blocks.push(newBlock);
        return Blocks;
    }
    return false;
}

Blocks에 성공적으로 추가가되면 return Blocks 블록이 담긴 배열을 돌려주기 

 

 

Server off => on 하고 Comman on Linux 

curl -X POST -H "Content-Type:application/json" -d "{\"data\":[\"hello\"]}" http://localhost:3000/mineblock

or python json tool 사용해서 

curl -X POST -H "Content-Type:application/json" -d "{\"data\":[\"hello\"]}" http://localhost:3000/mineblock | python3 -m json.tool

질문 : 오류가 남 !  

 

Block.js에서

// 새로운 block을 간단히 추가하는 함수 
function addBlock(data){
    const newBlock = nextBlock(data);
    console.log('newBlock=',newBlock)
    if(isValidNewBlock(newBlock, getLastBlock())){
    // if(isValidNewBlock(newBlock, getLastBlock()) && isValidBlocks(Blocks)){
        Blocks.push(newBlock);
        return Blocks;
    }
    return false;
}

isValidBlocks(Blocks) 를 조건에 같이 넣어주었는데 제네시스 블록 비교하는 두 개의 Timestamp가 달라서 false 가 뜨는 것 같다. => 일단 빼주기! 

 

다시 Linux 명령어 -> Data가 "Hello" 라는 블록체인이 추가됨 ! 

 

 

 

 

 

5. 프로세스 종료하기 on Linux 

vs terminal에서 Crtl + c 로 서버 끄지않고 Linux 명령으로 끄도록 만들기 

 

server.js 코드 추가 

// 서버 끄기 
app.get('/stop', (req,res)=>{
    res.send(`server's just stopped ! `)
    process.exit(0)
})

Command on Linux 

curl -X GET http://localhost:3000/stop

or

curl http://localhost:3000/stop

 

 

 

Server - Client 끝! 

 

 

 

 

 


 

 

 

 

2) Socket server 만들기 (with ws) 

1. ws 기본 세팅

- npm 설치 

npm i ws 

- src > network.js 파일 생성  +  코드 작성 

const WebSocket = require('ws');
const wsPORT = process.env.WS_PORT || 6005;

local server.js PORT = 3000

socket network PORT = 6005 

=> 한 컴퓨터에 두 개의 port 열기 

 

 

2. socket 만들기 

const WebSocket = require('ws');
const wsPORT = process.env.WS_PORT || 6005; 

// [전역변수 sockets] 소켓에 연결된 사용자(peer)들을 모아놓은 list 
let sockets=[];

function getSockets(){
    return sockets;
}

// 최초의 접속 
function wsInit(){
    const server = new WebSocket.Server({port:wsPORT});
    
    server.on('connection', (ws)=>{
        console.log('ws=',ws)
        init(ws)
    })
}

function init(ws){
    sockets.push(ws)
}

 

 

 

3. socket.io의 broadcast 기능 구현 

* socket.io는 body내용을 객체로 보내고 받는게 가능했다! (사용하기 편리하게 만들어 놓은 것) 

* ws는 정석대로, 원래 데이터를 string으로 주고 받음 -> parse해서 객체로 변환해서 사용해야함 

 

network.js

function write(ws,message){
    // message 객체를 -> string으로 바꿔서 보냄 
    ws.send(JSON.stringify(message));
}

function broadcast(message){
    sockets.forEach(socket=>{
        write(socket,message)
    })
}

 

 

4. connectionToPeer 함수 생성 

function connectionToPeers(newPeers){
    // peer -> string주소값 ex) ws://localhost:7001
    // ** 주의 ws는 프로토콜! http를 대체함 
    newPeers.forEach(peer=>{
        const ws = new WebSocket(peer)

        // WebSocket.Server는 직접 Open까지 해주는데 WebSocket 
        ws.on('open', ()=>{init(ws)})
        
        // ERROR 
        ws.on('error',()=>{console.log(`ConnectionToPeers failed`)})
    })
}

 

 

 

 

5. server.js 실행할 때 network.js도 시작되도록 만들기 

 

network.js 모듈화 

module.exports={
    wsInit, getSockets, broadcast, connectionToPeers,
}

server.js

const ws = require('./network');
.
.
.
ws.wsInit();
app.listen(port, ()=>{
    console.log(`server start port ${port}`)
})

=> server off -> on => 오류있는지 점검 

=> port 3000, 6005 둘 다 열림 ! 

 

 

 

network.js 전체 코드 

const WebSocket = require('ws');
const wsPORT = process.env.WS_PORT || 6005; 

// [전역변수 sockets] 소켓에 연결된 사용자(peer)들을 모아놓은 list 
let sockets=[];

function getSockets(){
    return sockets;
}

// 최초의 접속 
function wsInit(){
    const server = new WebSocket.Server({port:wsPORT});
    
    server.on('connection', (ws)=>{
        console.log('ws=',ws)
        init(ws)
    })
}

function write(ws,message){
    // message 객체를 -> string으로 바꿔서 보냄 
    ws.send(JSON.stringify(message));
}

function broadcast(message){
    sockets.forEach(socket=>{
        write(socket,message)
    })
}

function connectionToPeers(newPeers){
    // peer -> string주소값 ex) ws://localhost:7001
    // ** 주의 ws는 프로토콜! http를 대체함 
    newPeers.forEach(peer=>{
        const ws = new WebSocket(peer)

        // WebSocket.Server는 직접 Open까지 해주는데 WebSocket 
        ws.on('open', ()=>{init(ws)})
        
        // ERROR 
        ws.on('error',()=>{console.log(`ConnectionToPeers failed`)})
    })
}

function init(ws){
    console.log(`ws server start port ${wsPORT}`)
    sockets.push(ws)
}

module.exports={
    wsInit, getSockets, broadcast, connectionToPeers,
}

 

 

 

6. Block 모으기

server.js

app.get('/peers',(req,res)=>{
    res.send(ws.getSockets().map(socket=>{
        return `${socket._socket.remoteAddress}: ${socket._socket.remotePort}`
    }))
})

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

질문 : pure p2p 는 어떻게 하는건지 !? 

반응형