본문 바로가기

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

[54일차]20210531 WebSocket, 웹소켓 연결하기 connection, connect, send, call / Javascript , node.js

반응형

 

지난 주말 과제 코드리뷰 

 

crypto.js

1. createHmac부분

원본 

const crypto = require('crypto');

function createPW(userpw){  //createHmac 두번째 인자값 = any String like salt 암호화필요  
    const cryptoPassword = crypto.createHmac('sha256',Buffer.from(userpw).toString())
                            .digest('base64')
                            .replace('==','').replace('=','');                            

    return cryptoPassword;
}  

module.exports=createPW;

이렇게 하는게 더 좋다고 한다

수정ok

const crypto = require('crypto');

function createPW(userpw){  //createHmac 두번째 인자값 = any String like salt 암호화필요  
    const cryptoPassword = crypto.createHmac('sha256',Buffer.from(process.env.salt))
                            .update('userpw')
                            .digest('base64')
                            .replace('==','').replace('=','');                            
    return cryptoPassword;
}  

module.exports=createPW;

 

 

2. exports 함수 합치기 

 

수정ok 

require('dotenv').config();
const crypto = require('crypto');

function createToken(userid) {
    let header = { "tpy": "JWT", "alg": "HS256" }
    let exp = new Date().getTime() + (1000 * 60 * 60 * 2) //지금으로부터 2시간 뒤
    let payload = { userid, exp, }

    const encodingHeader = Buffer.from(JSON.stringify(header)).toString('base64')
                            .replace('==', '').replace('=', '');

    const encodingPayload = Buffer.from(JSON.stringify(payload)).toString('base64')
                            .replace('==', '').replace('=', '');

    const signature = crypto.createHmac('sha256', Buffer.from(process.env.salt))
                            .update(encodingHeader + '.' + encodingPayload)
                            .digest('base64').replace('==', '').replace('=', '');

    let jwt = `${encodingHeader}.${encodingPayload}.${signature}`;
    return jwt;
}


function createPW(userpw){  //createHmac 두번째 인자값 = any String like salt 암호화필요  
    const cryptoPassword = crypto.createHmac('sha256',Buffer.from(process.env.salt))
                            .update('userpw')
                            .digest('base64')
                            .replace('==','').replace('=','');                            
    return cryptoPassword;
}  

//let token = createToken('asdf');
module.exports={
    createToken,createPW,
} 

 

 

 

3. mysql2 비동기로 DB results 가져오기 ok

https://blckchainetc.tistory.com/208

 

[JavaScript] Mysql2 로 DB data 비동기로 가져오기 예제

mysql2 가 아닌 mysql 을 쓴 server.js 코드 const express = require('express'); const nunjucks = require('nunjucks'); const bodyParser = require('body-parser'); const tokenKey = require('./JWT'); con..

blckchainetc.tistory.com

 

 


 

 

HTTP 프로코톨 통신의 특징

Client 쪽에서만 요청(REQ) 가능 

한 번의 Client의 REQ 요청-----한번의 SERVER의 RES 응답만 가능

요청을 준 Client 에게만 SERVER 는 REQ를 보냄 - 그럼 채팅기능의 경우? 기본 http 로 구현이 안됨 => 웹소켓 탄생 

 

WebSocket, 웹소켓

요청을 한 사람 외에도 모든 사람에게 응답을 보낼 수 있게 만듬 

Server ---REQ---> Client  요청도ok -> 쌍방향 소통 (통신)이 가능해짐

server - 이벤트로 새글이 올라올 때 page load없이 clients 에게 바로 응답 가능 (요청없이도!) 

즉, 요청없이도 RES 응답 주기 가능, Server도 Client에게 요청이 가능해짐 

* 필요한 공간에서만 웹소켓 사용. 요청한 client에게 응답을하는건 기본 구조에 필수이기 떄문에 http 사용 

  남들에게도 다른사람에게도 응답이 필요하면 웹소켓 사용 

 

한번의 Client 요청으로 서로 연결 -> 그 뒤로 Client, Server 둘 다 요청 마음대로 ! 

 

 

https://blckchainetc.tistory.com/206

 

[http 프로토콜 vs 웹소켓 프로토콜] Websocket, 웹소켓이란?

채팅, 게임, 주식 차트 등의 실시간 통신이 필요한 서비스를 구현하려면 HTTP프로토콜이 아닌 웹소켓 프로토콜을 사용하는 것이 좋다. http는 요청한대로 응답을 보내주는 단순한 프로코톨로 문서

blckchainetc.tistory.com

 

 

 

 

웹 소켓 설정 전 express 세팅

$npm init

$npm i express nunjucks 

views 폴더 , index.html 생성

server.js 코드  +nunjucks + render

const express=require('express');
const app=express();
const nunjucks = require('nunjucks');

nunjucks.configure('views',{
    express:app,
});
app.set('view engine', 'html');

app.get('/',(req,res)=>{
    res.render('index.html');
})

app.listen(3000,()=>{   
    console.log('server start port: 3000')
})

 

웹소켓 사용 위한 라이브러리 설치 

$npm i socket.io

코드 추가 

const socket = require('socket.io');

 

//express 직접적으로 사용하는게 안됨 

//node.js 에서 자체적으로 나와있는 hpp 내장 모드를 활용/ 연결

 

http는 node.js 가 자체적으로 가지고 있음 

$npm i http 

이유 : socket과 연결하기 위해 . http문서를 읽기 위해 

코드 추가 

const http = require('http');

설정 / 연결 코드 추가

const express=require('express');
const app=express();
const nunjucks = require('nunjucks');
const socket = require('socket.io');
//http 가져오기 + 설정 / server, http 연결한 상태
const http = require('http');
const server = http.createServer(app);
//socket 과 server연결 (server측에서 웹소켓 사용위한 설정구간)
const io = socket(server); 

nunjucks.configure('views',{
    express:app,
});
app.set('view engine', 'html');

app.get('/',(req,res)=>{
    res.render('index.html');
})

server.listen(3000,()=>{
    console.log('server start port: 3000')
})

 

먼저 Client가 웹소켓 사용 먼저 요청

Client 소켓 사용할 수 있는 환경 만들어주기 

views -index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    hello
    <script type="text/javascript" src="./socket.io/socket.io.js"></script>
</body>
</html>

네트워크 - socket.io.js 가서 확인 

 

 

성공 안되어있음 

 

node_modules에서 아래 파일을 가져오면 됨 

 

 

 

server.js static 추가 

app.use(express.static('node_modules/socket.io/client-dist'));

index.html 수정 

    <script type="text/javascript" src="./socket.io.js"></script>

 

 

 

 

----server, client 측 모두 기본 세팅 끝 

 

 

소켓 연결하기 - 받아주는걸 먼저 작성 (요청하는거 작성하면 확인을 아직 못하기 때문) 

server.js

//소켓을 서버와 연결했던 -io 사용해서 받아주는 아이 만들기 
//event를 등록하는 거 =on =addEventListener 
//on 첫번째 인자값 : 이벤트 / 두번째 : 콜백 함수 - 지금은 익명함수 , 따로빼도됨
io.sockets.on('connection', (socket) => {
    //socket이 연결이 되었을 떄 connection을 받았을 때 콜백 실행
    //send라는 이벤트 발생했을 떄 ()=>{} 함수 실행    
    socket.on('send',()=>{
        console.log('hello');
    })
})

 

 

클라이언트 -> server 요청 

이제 io를 쓸 수 있음 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>hello socket</h1>
    <input type="text" id="msg">
    <input type="button" id ="btn" value="버튼">
    <script type="text/javascript" src="./socket.io.js"></script>  //얘가 있어서 io()사용가능
    <script type="text/javascript">
        io()
    </script>
</body>
</html>

-

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>hello socket</h1>
    <input type="text" id="msg">
    <input type="button" id ="btn" value="버튼">
    <script type="text/javascript" src="./socket.io.js"></script>
    <script type="text/javascript">
        let socket = io();

        socket.on('connect',()=>{
            let msg = document.querySelector('#msg');
            msg.value='socket 연결/접속완료'
        })
    </script>
</body>
</html>

 

server on -> check 

 

io 가 header 내용을 만들어서 요청 

여기까지 client 와 server 가 (client의 요청으로 인해) 서로 연결 되었어! 확인하는 부분 

 

 


 

 

 

connect -> connection 실행됨. 안쪽으로 들어옴 / 아직 socket.on('send')는 실행안된거

connect -요청한 순간 server 가 응답을 줌 -> 

 

 

이제 send 사용해보기 

client에서 send 라는 msg 를 

버튼을 클릭했을 때 send 를 보내보기 

버튼 클릭 2가지 방법 (onclick, addEvent) 

 

index.html

        const btn = document.querySelector('#btn');
        btn.addEventListener('click',()=>{
            let msg = document.querySelector('#msg');
            //emit() 첫번째 : 보낼 인자값
            //emit() 두번째 인자값 : 내보낼때 내가 어떤data를 보낼지(우리는 객체로 보내보자)
            //client쪽이 보낸다. 요청한다. (emit) by send라는 메세지로
            socket.emit('send', {msg:msg.value})
        })

server.js

'send'로 보내는 객체를 받을 인자값을 (아무거나) 적어주기

io.sockets.on('connection', (socket) => {  
    socket.on('send',(data)=>{
        console.log(`클라이언트에서 받은 메세지는  ${data.msg}`);
    })
})

 

 

messages에  버튼 누를때 마다 send 한 event 내용이 쌓임 

 

여기까지 

Client A ------REQ 계속 보내기 ------> SERVER  // (SERVER는 ClientA에게 응답을 보내지않음) 

 

이제 Client A가 보낸 요청을 받아서 다른 Clients에게 내용 보내기   

 

server.js

io.sockets.on('connection', (socket) => {
    //socket이 연결이 되었을 떄 connection을 받았을 때 콜백 실행
    //send라는 이벤트 발생했을 떄 ()=>{} 함수 실행    
    socket.on('send',(data)=>{ //내가 send라는 메세지를 받았다.
        console.log(`클라이언트에서 받은 메세지는  ${data.msg}`);
        // 내가 받은 data.msg를 요청준client제외 모둔clients에게 보내겟다.
        socket.broadcast.emit('call', data.msg)
    })
})

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>hello socket</h1>
    <input type="text" id="msg">
    <input type="button" id ="btn" value="버튼">
    <div id ="content">

    </div>
    <script type="text/javascript" src="./socket.io.js"></script>
    <script type="text/javascript">
        let socket = io('http://localhost:3000');

        socket.on('connect',()=>{
            const msg = document.querySelector('#msg');
            msg.value='socket 연결/접속완료';
        })

        const btn = document.querySelector('#btn');
        btn.addEventListener('click',()=>{
            const msg = document.querySelector('#msg');
            //emit() 첫번째 : 보낼 인자값
            //emit() 두번째 인자값 : 내보낼때 내가 어떤data를 보낼지(우리는 객체로 보내보자)
            //client쪽이 보낸다. 요청한다. (emit) by send라는 메세지로
            socket.emit('send', {msg:msg.value})
        })
        //받을 내용의 변수명 =data
        socket.on('call',(data)=>{
            const content = document.querySelector('#content');
            content.innerHTML += `ClientA가 보낸 요청send msg를 server가 broadcast로 방출. ${data} <br/>`;
        })
    </script>
</body>
</html>

.broadcast = 요청한 client를 제외하고 나머지 모든 Client에게 보내겠다. 

emit - 보내기 on - 받기 

왼쪽 : 나(원래 localhost:3000) 오른쪽: 새로 open한 브라우저 localhost:3000 에 나온다. 

 

 

 

내가 클릭했을 때 내가 쓴 글을 화면에 표출하기  

index.html

        btn.addEventListener('click',()=>{
            const msg = document.querySelector('#msg');
            socket.emit('send', {msg:msg.value})
            const content = document.querySelector('#content');
            content.innerHTML += `ClientA인 내가 쓴글 ${msg.value} <br/>`;
        })
        //받을 내용의 변수명 =data
        socket.on('call',(data)=>{
            const content = document.querySelector('#content');
            content.innerHTML += `ClientA가 보낸 요청send msg를 server가 broadcast로 방출. ${data} <br/>`;
        })

채팅같은 기능 구현됨. 

이 원리를 잘 응용하면 무궁무진함.

facebook notification 등등 / 화면 보고있는데 댓글, 좋아요 눌렀을 때 나에게 notification 뜰 때 (reload없이)

 

 

 

 

 

반응형