일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 전기차
- esp8266
- 라즈베리파이
- 급속충전기
- flask
- 플라스크
- 충전기
- Android
- dynamodb
- STM32
- 에버온
- everon
- IOT Core
- homeassistant
- 전기차충전
- thread
- raspberry
- 안드로이드
- 보안
- YMODEM
- 디자인패턴
- lambda
- AWS
- 완속충전기
- 서버리스
- OCPP
- 펌웨어
- 파이썬
- 홈어시스턴트
- 전기차충전기
- Today
- Total
Louie NRT Story
[웹소켓] 동작 원리 및 기본용어 본문
작성일: 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
https://naldo627.github.io/2019/04/08/http-analyze/
https://not-to-be-reset.tistory.com/91
https://blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=eztcpcom&logNo=220040171267
https://developer.mozilla.org/ko/docs/Web/API/WebSockets_API/Writing_WebSocket_servers
https://byeongukchoi.github.io/TIL/6.PYTHON/1.%EC%9B%B9%EC%86%8C%EC%BC%93.html
'전기차충전기' 카테고리의 다른 글
[안드로이드] 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 |