
일단 나는 python server에서 socketIO를 바탕으로 웹소캣을 구현했다.
이전 node.js에서 구현한 websocket보다 간편한 부분도 있지만, 다른 부분도 있었따.
def start_servers():
socketio.start_background_task(target=broadcast_periodically)
socketio.run(app, host="0.0.0.0", port=5119)
이런 식으로 서버를 우선 구현하면 된다. 나는 어쩌피 비동기로 백그라운드에서 돌릴거니까..
근데 이렇게 말고 정말 간단한 pub/sub 방식을 구현할거면 python에 pynng를 추천한다. 그건 다음에 말할게요
이 프로젝트에서 문제는 이미 비동기가 돌아가고 있다는 점, 비동기로 돌아가는 데이터에서 비동기 웹소캣으로 보내야한다는 점이 문제였다..
어쩌피 connect 연결되면 데이터 주는거야 문제가 안된다지만 해당 프로젝트는 1초 주기로 새로운데이터를 받아 준실시간? 같은 느낌이었따.
async def main():
global api_thread
start_servers_thread = Thread(target=start_servers, daemon=True)
start_servers_thread.start()
addresses = ["tcp://:12345", "tcp://:12346", "tcp://:12347"]
topics = [f'{kind}.{args.asset}' for kind in ['0', '0', '0]]
try:
await subscriber(topics, addresses)
except asyncio.CancelledError:
print("Subscriber task cancelled")
finally:
await cleanup()
이건 main에서 실행될 부분에 대해 나타낸 부분이다. 물론 아래 if name =="main" 에서 실행시켜도 될 줄 알았찌만, 그럴 경우 이전 씽크에서 돌던 로직과 충돌이 난다.. 원인은 추후 파악할 예정
그래서 난 main()에서 쓰레드를 실행시킬 때 target을 broadcast_periodically로 미리 구현한 함수를 지정하였다.
아래 addresses는 내가 pynng로 만들어 놓은 pubsub..
사실 websocket 하기 귀찮아서 api 1초마다 호출하면 안되냐 했다가 혼났다.
socketio = SocketIO(
app,
cors_allowed_origins="*",
async_mode="threading",
logger=False,
engineio_logger=False
)
@socketio.on("connect")
def handle_connect():
print(f"Connect Complite")
socketio.emit("server_message", {"data": "연결 성공!"})
def broadcast_periodically():
while not shutdown_flag:
try:
if Abnormality:
utc_now = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
time.sleep(0.1)
socketio.emit("anormal1", {'data':data, 'checktime': utc_now})
print("Broadcasting:", data)
except Exception as e:
print("Error during socketio.emit:", e)
time.sleep(1)
내가 위에서 구현한 socketIO는 사실 이상이 발생했을 때 즉각적인 알림이 갈 수 있게끔 하기 위해 구현 한 것이다.
순서대로 socketIO에 대한 설정을 해야한다.
기본적으로 개발 초기니까 cores_Allowed를 *로 설정해놨으며 async_mode는 내가 쓰레드로 만들었으니.. 당연히.. logger관련 내용은 true로 설정할 때 송수신 결과를 눈으로 확인할 수 있따.
그 후는 간단하다.
connect로 연결을 시키고 emit으로 받은 message를 확인하면
broadcast_periodically를 쓰레드로 task 돌리고 있으니 난 내가 원하는대로 1초마다 이상에 대한 데이터를 받을 수 있었따.
물론 리소스 낭비를 줄이기 위해 try안에 조건 문을 걸고 해야하는 건 필수..
프론트 환경은 vue를 사용했다. nuxt라고 해야하나..
우선 사용하기 위해
import { io } from 'socket.io-client';
socket.io-client를 npm으로 설치해야한다. 당연히 page에 import도 해야하고
선택인데 socket.js로 만들어 전역으로 사용하는 것도 있더라 나는 안함
data() {
return {
siteName: "--",
connected: false,
wsio: io('http://0.0.0.0:5119', {
transports: ['websocket'],
withCredentials: false,
cors: {
origin: '*'
},
}),
저렇게 io안에 주소를 넣어야하는 건 다들 알꺼라 생각한다..
근데 mounted안에 넣으면 에러난다! 안돼!
아마 js를 더 공부해봐야알겠지만 mounted 되기 전에 데이터를 지니고 있어야하는 건 아닐까.. 아닌가.. mounted가 먼저인가.. 아무튼..
handleWebSocketData(data) {
try {
function getCurrentTimeWithMilliseconds() {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0'); // 월은 0부터 시작하므로 +1
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
const milliseconds = String(now.getMilliseconds()).padStart(3, '0');
// 원하는 형식으로 반환
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}.${milliseconds}`;
}
const parsedData = {};
for (const key in data.data) {
const value = data.data[key];
if (typeof value === "string") {
parsedData[key] = JSON.parse(value);
} else {
}
}
const eventdata = this.formatedEvents(parsedData);
// console.log("Formatted Events:", eventdata);
this.eventDatas = eventdata;
const receive_time = getCurrentTimeWithMilliseconds();
const sendTime = new Date(data.checktime).getTime();
const receiveTime = new Date(receive_time).getTime();
const diff = receiveTime - sendTime;
console.log("send time : ", data.checktime);
console.log("receive time : ", receive_time);
console.log("Time difference (ms):", diff);
const logEntry = `
Send Time : ${data.checktime}
Receive Time : ${receive_time}
Time Difference (ms) : ${diff}`
this.logData.push(logEntry)
} catch (e) {
console.log("Error processing WebSocket data:", error);
}
},
위는 소켓 받는 시간이 얼마나 걸릴지 계산하는 식같은게 있따..
이건 단지 어떤식으로 데이터를 받을지 정한 것이고 진짜는 따로 있따..
getEventDatas() {
try {
this.wsio.on("connect", () => {
console.log("connect success");
});
this.wsio.on('anormal1', (data) => {
this.handleWebSocketData(data);
});
this.wsio.on('disconnect', () => {
console.log('WebSocket disconnected');
this.connected = false;
});
// 연결 오류 처리
this.wsio.on('connect_error', (error) => {
console.error('WebSocket connection error:', error);
});
} catch (error) {
console.error("Error initializing WebSocket:", error);
}
}
이렇게 간단하다. socket.emit으로 보낸 내용을 io.on 형태로 받고 data를 핸들링하기만 하면 된다. 근데 왜 못했냐고? 나도 궁금하다.. 대체 왜 그랬던걸까..
혹시 websocket할 사람은 꼭 작업자 모드에서 network -> ws에서 받아오는 데이터에 집착하지말고 해야한다..
난 심지어 connect안에 anormal1을 호출해서 받아오기도 했는데 말도 안된다 생각해보면..
그리고 지속적으로 재연결되는거같다 하는거면 socket 선언 시기에 대해 생각해보는 것도 좋을 것이다.