Louie NRT Story

[웹소켓] 동작 원리 및 기본용어 본문

전기차충전기

[웹소켓] 동작 원리 및 기본용어

hyeok0724.kim@gmail.com 2021. 8. 9. 11:48
반응형

작성일: 8월16일

PS. 전기차 충전기 OCPP 통신이 웹소켓으로 이루어져 있는데 펌웨어에서 구현을 해야 했음.

     그래서 웹소켓에 대해서 공부를 하게 대해서 공부를 하였음.

 

Index

1. 웹소켓

2. 파이썬 웹소켓 서버 만들기

3. 웹소켓 패킷 분석

 

1. 웹소켓

1) 생겨난 배경

 - 기존에는 HTTP 를 통하여 서버와의 통신을 하였음. 그래서 간단한 내용도 HTTP를 전문을 통해서 주고 받아야 했지만Google에서 AJAX를 만들고 DOM을 변경하는 방식으로 변경된 내용만 주고 받음으로 속도가 빨라지고 간편해짐.

 여기서 또 문제점은 무엇이 변경되었는지 알 수 없기 때문에 클라이언트는 계속 주기적으로 서버로 부터 변경사항에 대해서 물어봐야함. 그래서 양방향 통신을 위해서 웹소켓이라는 것이 나왔으며 클라이언트가 물어보지 않아도 서버는 변경된 내용에 대해서 클라이언트에게 알려줌

 

2. 파이썬 웹소켓 서버 만들기

1) Basic Example

 - 파이썬 서버 코드

#!/usr/bin/env python

# WS server that sends messages at random intervals

import asyncio
import datetime
import random
import websockets

async def time(websocket, path):
    while True:
        now = datetime.datetime.utcnow().isoformat() + "Z"
        await websocket.send(now)
        await asyncio.sleep(random.random() * 3)

start_server = websockets.serve(time, "127.0.0.1", 5678)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

 - 클라이언트 코드

<!DOCTYPE html>
<html>
    <head>
        <title>WebSocket demo</title>
    </head>
    <body>
        <script>
            var ws = new WebSocket("ws://127.0.0.1:5678/"),
                messages = document.createElement('ul');
            ws.onmessage = function (event) {
                var messages = document.getElementsByTagName('ul')[0],
                    message = document.createElement('li'),
                    content = document.createTextNode(event.data);
                message.appendChild(content);
                messages.appendChild(message);
            };
            document.body.appendChild(messages);
        </script>
    </body>
</html>

 - 실행 결과

 - Chrome 에서 서버로 웹소켓 연결하여 1초 간격으로 시간 데이터를 받고 있음

 

2) 웹소켓 동기화 서버

 - 파이썬 웹소켓 서버 코드

#!/usr/bin/env python

# WS server example that synchronizes state across clients

import asyncio
import json
import logging
import websockets

logging.basicConfig()

STATE = {"value": 0}

USERS = set()


def state_event():
    return json.dumps({"type": "state", **STATE})


def users_event():
    return json.dumps({"type": "users", "count": len(USERS)})


async def notify_state():
    if USERS:  # asyncio.wait doesn't accept an empty list
        message = state_event()
        await asyncio.wait([user.send(message) for user in USERS])


async def notify_users():
    if USERS:  # asyncio.wait doesn't accept an empty list
        message = users_event()
        await asyncio.wait([user.send(message) for user in USERS])


async def register(websocket):
    USERS.add(websocket)
    await notify_users()


async def unregister(websocket):
    USERS.remove(websocket)
    await notify_users()


async def counter(websocket, path):
    # register(websocket) sends user_event() to websocket
    await register(websocket)
    try:
        await websocket.send(state_event())
        async for message in websocket:
            data = json.loads(message)
            if data["action"] == "minus":
                STATE["value"] -= 1
                await notify_state()
            elif data["action"] == "plus":
                STATE["value"] += 1
                await notify_state()
            else:
                logging.error("unsupported event: %s", data)
    finally:
        await unregister(websocket)


start_server = websockets.serve(counter, "localhost", 6789)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

- 클라이언트 코드

<!DOCTYPE html>
<html>
    <head>
        <title>WebSocket demo</title>
        <style type="text/css">
            body {
                font-family: "Courier New", sans-serif;
                text-align: center;
            }
            .buttons {
                font-size: 4em;
                display: flex;
                justify-content: center;
            }
            .button, .value {
                line-height: 1;
                padding: 2rem;
                margin: 2rem;
                border: medium solid;
                min-height: 1em;
                min-width: 1em;
            }
            .button {
                cursor: pointer;
                user-select: none;
            }
            .minus {
                color: red;
            }
            .plus {
                color: green;
            }
            .value {
                min-width: 2em;
            }
            .state {
                font-size: 2em;
            }
        </style>
    </head>
    <body>
        <div class="buttons">
            <div class="minus button">-</div>
            <div class="value">?</div>
            <div class="plus button">+</div>
        </div>
        <div class="state">
            <span class="users">?</span> online
        </div>
        <script>
            var minus = document.querySelector('.minus'),
                plus = document.querySelector('.plus'),
                value = document.querySelector('.value'),
                users = document.querySelector('.users'),
                websocket = new WebSocket("ws://127.0.0.1:6789/");
            minus.onclick = function (event) {
                websocket.send(JSON.stringify({action: 'minus'}));
            }
            plus.onclick = function (event) {
                websocket.send(JSON.stringify({action: 'plus'}));
            }
            websocket.onmessage = function (event) {
                data = JSON.parse(event.data);
                switch (data.type) {
                    case 'state':
                        value.textContent = data.value;
                        break;
                    case 'users':
                        users.textContent = (
                            data.count.toString() + " user" +
                            (data.count == 1 ? "" : "s"));
                        break;
                    default:
                        console.error(
                            "unsupported event", data);
                }
            };
        </script>
    </body>
</html>

 - 실행결과

 - "+" 버튼 또는 "-" 버튼을 누르면 이벤트가 발생하면서 숫자가 변경됨

 - 접속자가 변경되면 user의 숫자가 변경됨

 - 값이 변경되면 서버로 부터 이벤트 메시지가 전달됨.

 

 

3. 웹소켓 패킷 분석

1) 클라이언트 웹소켓 key 전달

 

2) 서버 키 수신

 

3) 서버로 부터 데이터 수신

- 버튼 눌렀을떄의 데이터

- 데이터가 Mask 하였으며 Mask Key도 전달하였음

 

Referece:

https://websockets.readthedocs.io/en/stable/intro.html#basic-example

 

Getting started — websockets 9.1 documentation

You will usually want to process several messages during the lifetime of a connection. Therefore you must write a loop. Here are the basic patterns for building a WebSocket server. Registration As shown in the synchronization example above, if you need to

websockets.readthedocs.io

https://naldo627.github.io/2019/04/08/http-analyze/

 

HTTP 분석 실습 - 날도의 잡다한 기술 블로그 | NaLDo's IT Blog

개요 데이터 통신 과제로 wireshark를 사용한 HTTP 분석 과제 레포트를 작성하게 되었다. WebSocket Client 제작 PPT의 내용을 참고, Javascript로 온라인 에코서버 (ws://echo.websocket.org)로 요청하는 테스트 WebSo

naldo627.github.io

https://not-to-be-reset.tistory.com/91

 

[websocket] Sec-WebSocket-Key 변환

def handshake(client): request = client.recv(2048) p=re.compile('Sec-WebSocket-Key: (.*)\\r') m = p.search(request.decode()) #key = m.group(1)+'258EAFA5-E914-47DA-95CA-C5AB0DC85B11' key = 'dGhlIHNhb..

not-to-be-reset.tistory.com

https://blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=eztcpcom&logNo=220040171267 

 

HTML5 웹소켓(WebSocket) 접속 과정.

안녕하세요. Jack 입니다. 지난 시간에 이어서 이번에는 HTML5의 웹소켓 접속과정에 대해서 알아보겠...

blog.naver.com

https://developer.mozilla.org/ko/docs/Web/API/WebSockets_API/Writing_WebSocket_servers

 

웹소켓 서버 작성하기 - Web API | MDN

웹 소켓 서버는 특정한 프로토콜을 따르는 서버의 임의 포트를 리스닝하고 있는 TCP 어플리케이션입니다. 사용자 서버를 만드는 작업은 두려운 일일수도 있습니다. 하지만, 당신이 선택한 플

developer.mozilla.org

https://byeongukchoi.github.io/TIL/6.PYTHON/1.%EC%9B%B9%EC%86%8C%EC%BC%93.html

 

웹소켓으로 채팅 프로그램 만들기 | TIL

웹소켓으로 채팅 프로그램 만들기 cilent : javascript server: python2 순서 소켓 준비 WebSocket Handshake (클라이언트 -> 서버 : 핸드쉐이킹 요청, 서버 -> 클라이언트 : 핸드 쉐이킹 응답) 데이터 프레임 교환

byeongukchoi.github.io

반응형

'전기차충전기' 카테고리의 다른 글

[안드로이드] UI 테스트 - 01  (0) 2021.08.17
[충전기 통신] OCPP 2.0 - Todo  (0) 2021.08.11
[SSL/TLS] mbedTLS 분석 - Todo  (0) 2021.08.06
[원격펌웨어] ESP8266 OTA  (0) 2021.08.06
[원격펌웨어] Atmel 부트로더  (0) 2021.08.05
Comments