[Python 인터넷] [Python] Websocket을 사용하는 방법

 

안녕하세요. 명월입니다.

 

이 글은 Python에서 Websocket을 사용하는 방법에 대한 글입니다.

 

Websocket은 웹 브라우져에서 javascript로 TCP 동기 통신을 위한 통신 프로토콜입니다. 제가 이전에 Java로 websocket을 구현한 적이 있는데 참고하시면 이해하기 편하실 것입니다.

링크 - [Java] 웹 소켓 (WebSocket)

 

이런 웹 소켓을 C#에서는 signalR을 사용하고 Java에서는 표준 Websocket을 사용합니다.(SignalR이라고 웹소켓을 사용하지 않는 것은 아니고 MVC Framework에 맞게 표준 websocket에서 여러 기능을 추가한 것입니다.)

그런데 저의 경우는 Python에서 왜 웹 소켓을 사용할까 하는 것에 PHP에서는 웹소켓을 구현하기가 힘듭니다. 그 이유는 여러가지가 있는데 제가 생각하기에는 PHP에서 직접적으로 Thread를 관리하기가 어렵기 때문이지 않을까 싶습니다.

 

웹 소켓이라고 하지만 실제는 http 프로토콜로 tcp socket접속을 해서 해더의 handshake를 하여 http 접속을 비동기식(request & response)처리를 하고 접속을 끊는 행위가 아니라 동기식으로 접속을 유지해야 합니다.

그렇다면 접속을 관리해야 하는 멀티 쓰레드를 만들어야하고 그렇다면 쓰레드를 관리하는 풀과 제어가 만들어져야 하는데 그 점이 PHP에서는 관리하기가 어렵지 않을까 싶습니다.

PHP는 단순히 한번의 request와 response에 대한 스크립트로 표현되어 있기 때문에 한계가 있습니다.

 

그래서 할 수 있는 대안으로 node.js의 socket.io와 python의 websocket이 있습니다.

구글링을 하면 PHP의 웹 소켓 대안으로 socket.io가 많이 설명이 되어있네요. 언젠가 기회가 되면 node.js도 포스팅을 하고 싶습니다만, 개인적으로 node.js를 좋아하지 않아요.

node.js가 언어적으로 한계가 있다라기 보다는 python이라는 훌륭한 로컬 스크립트가 있는데.. 굳이 왜?라는 인식이 있기 때문입니다.

그리고 socket.io는 정확히 websocket 기술이 아닙니다. AJAX Long Polling기술이라고 이게 http 프로토콜에서 request & response 후에 접속을 바로 팍 끊는 게 아니고 약간 갭을 주는 것입니다.

그래서 데이터가 바뀌면 브라우져로 하여금 재 요청을 하게 하는 것인데.. 유저가 느끼기에는 http의 풀링으로 마치 접속이 연결을 유지하는 듯한 효과를 내는 방법입니다.

그러나 이게 결국은 tcp로 동기적으로 묶여 있는 것이 아니기 때문에 여러가지 버그가 발생합니다. 대표적인게 반응이 느린 점이 있겠네요.

 

그래서 저의 경우는 이 python으로 websocket을 구현하는 게 가장 좋지 않을까 생각됩니다.

python에서 웹 소켓을 사용하려면 라이브러리를 다운로드 받아야 합니다.

Copy!
 [소스 보기] cmd

pip install websockets

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

설치가 완료가 되었으면 websocket 스크립트를 작성하겠습니다.

Copy!
 [소스 보기] websocketServer.py
 
import asyncio;
 
# 웹 소켓 모듈을 선언한다.
 
import websockets;
 
 
 
# 클라이언트 접속이 되면 호출된다.
 
async def accept(websocket, path):
 
while True:
 
# 클라이언트로부터 메시지를 대기한다.
 
data = await websocket.recv();
 
print("receive : " + data);
 
# 클라인언트로 echo를 붙여서 재 전송한다.
 
await websocket.send("echo : " + data);
 
 
 
# 웹 소켓 서버 생성.호스트는 localhost에 port는 9998로 생성한다.
 
start_server = websockets.serve(accept, "localhost", 9998);
 
# 비동기로 서버를 대기한다.
 
asyncio.get_event_loop().run_until_complete(start_server);
 
asyncio.get_event_loop().run_forever();

그리고 클라이언트는 로컬의 적당한 장소에 html파일로 작성합니다.(python으로 웹서버를 만든 것이 아니기 때문에 웹 브라우져를 실행해야할 html파일이 필요합니다.)

Copy!
 [소스 보기] index.html
 
<!DOCTYPE html>
 
<html>
 
<head>
 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 
<title>Insert title here</title>
 
</head>
 
<body>
 
<form>
 
<!-- 서버로 메시지를 보낼 텍스트 박스 -->
 
<input id="textMessage" type="text">
 
<!-- 전송 버튼 -->
 
<input onclick="sendMessage()" value="Send" type="button">
 
<!-- 접속 종료 버튼 -->
 
<input onclick="disconnect()" value="Disconnect" type="button">
 
</form>
 
<br />
 
<!-- 출력 area -->
 
<textarea id="messageTextArea" rows="10" cols="50"></textarea>
 
<script type="text/javascript">
 
// 웹 서버를 접속한다.
 
var webSocket = new WebSocket("ws://localhost:9998");
 
// 웹 서버와의 통신을 주고 받은 결과를 출력할 오브젝트를 가져옵니다.
 
var messageTextArea = document.getElementById("messageTextArea");
 
// 소켓 접속이 되면 호출되는 함수
 
webSocket.onopen = function(message){
 
messageTextArea.value += "Server connect...\n";
 
};
 
// 소켓 접속이 끝나면 호출되는 함수
 
webSocket.onclose = function(message){
 
messageTextArea.value += "Server Disconnect...\n";
 
};
 
// 소켓 통신 중에 에러가 발생되면 호출되는 함수
 
webSocket.onerror = function(message){
 
messageTextArea.value += "error...\n";
 
};
 
// 소켓 서버로 부터 메시지가 오면 호출되는 함수.
 
webSocket.onmessage = function(message){
 
// 출력 area에 메시지를 표시한다.
 
messageTextArea.value += "Recieve From Server => "+message.data+"\n";
 
};
 
// 서버로 메시지를 전송하는 함수
 
function sendMessage(){
 
var message = document.getElementById("textMessage");
 
messageTextArea.value += "Send to Server => "+message.value+"\n";
 
//웹소켓으로 textMessage객체의 값을 보낸다.
 
webSocket.send(message.value);
 
//textMessage객체의 값 초기화
 
message.value = "";
 
}
 
function disconnect(){
 
webSocket.close();
 
}
 
</script>
 
</body>
 
</html>

웹 브라우져에서 위에 작성한 html를 실행시키면 javascript에서 python websocket서버로 접속을 합니다. 그리고 hello와 test의 메시지를 작성해서 보냈는데 server측에서는 hello와 test의 메시지를 받아서 콘솔에 출력을 했고 브라우저에서는 echo : 가 붙은 메시지가 표시가 되었습니다.

사실 여기까지만 해도 python에서 웹 소켓을 사용하는 데 문제없습니다.

 

그런데 python에서는 websocket의 서버 뿐아니라 client의 입장에서도 서버측으로 메시지를 보낼 수가 있네요.

제가 예전에 어플리케이션에서 Websocket을 사용할 수 있으면 Tomcat으로도 어플리케이션을 구현할 수 있겠다고 글을 쓴 적이 있습니다.

링크 - [Java] Tomcat의 websocket을 이용해서 socket서버 만들기

 

이게 Python에서는 구현이 되어있네요..

Copy!
 [소스 보기] websocketClient.py
 
import asyncio
 
# 웹 소켓 모듈을 선언한다.
 
import websockets
 
 
 
async def connect():
 
# 웹 소켓에 접속을 합니다.
 
async with websockets.connect("ws://localhost:8080/WebSocketExample/websocket") as websocket:
 
# 10번을 반복하면서 웹 소켓 서버로 메시지를 전송합니다.
 
for i in range(1,10,1):
 
await websocket.send("hello socket!!");
 
# 웹 소켓 서버로 부터 메시지가 오면 콘솔에 출력합니다.
 
data = await websocket.recv();
 
print(data);
 
# 비동기로 서버에 접속한다.
 
asyncio.get_event_loop().run_until_complete(connect())
Copy!
 [소스 보기] websocket.java
 
import javax.websocket.OnClose;
 
import javax.websocket.OnError;
 
import javax.websocket.OnMessage;
 
import javax.websocket.OnOpen;
 
import javax.websocket.server.ServerEndpoint;
 
 
 
@ServerEndpoint("/websocket")
 
public class websocket {
 
/***
 
* 웹 소켓이 연결되면 호출되는 이벤트
 
*/
 
@OnOpen
 
public void handleOpen(){
 
System.out.println("client is now connected...");
 
}
 
/**
 
* 웹 소켓으로부터 메시지가 오면 호출되는 이벤트
 
* @param message
 
* @return
 
*/
 
@OnMessage
 
public String handleMessage(String message){
 
System.out.println("receive from client : "+message);
 
String replymessage = "echo "+message;
 
System.out.println("send to client : "+replymessage);
 
return replymessage;
 
}
 
/**
 
* 웹 소켓이 닫히면 호출되는 이벤트
 
*/
 
@OnClose
 
public void handleClose(){
 
System.out.println("client is now disconnected...");
 
}
 
/**
 
* 웹 소켓이 에러가 나면 호출되는 이벤트
 
* @param t
 
*/
 
@OnError
 
public void handleError(Throwable t){
 
t.printStackTrace();
 
}
 
}

클라이언트(python)에서 웹 소켓서버(java)로 접속을 하니 잘 됩니다. 이렇게 되면 자이썬(java에서 사용되는 python) IronPython등을 이용하면 예전에 제가 만든 C# 프로그램처럼 websocket 프로토콜을 1부터 만들 필요가 없을 듯 싶네요.

 

여기까지 Python에서 Websocket을 사용하는 방법에 관한 설명이었습니다.

 

궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.

출처: https://nowonbun.tistory.com/674 [명월 일지:티스토리]

 

 

 

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
번호 제목 글쓴이 날짜 조회 수
64 [python][자료구조] "pdf 취소선 검출" How to identify strike-out text from PDF files using Python 졸리운_곰 2024.07.18 544
63 [python][자료구조] 오픈 소스 Python PDF 파서 라이브러리 file 졸리운_곰 2024.07.16 445
62 [python][자료구조] 벡터화 | Vectorization file 졸리운_곰 2023.12.21 330
61 [python][자료구조] Python의 Loop? NO! , Python의 Vectorization? OK!!! file 졸리운_곰 2023.12.21 473
60 [python][자료구조] Python - MySQL 데이터 추가, 삭제, 업데이트 졸리운_곰 2023.05.13 488
59 [python][자료구조] Python의 JSON - 문자열을 JSON으로 변환하는 방법 졸리운_곰 2023.05.06 456
58 [python][자료구조] [Python] Logging to MongoDB (로그 남기기) file 졸리운_곰 2023.03.24 428
57 [python][자료구조] [스파르타 웹 개발 종합] 파이썬으로 크롤링하고 DB에 저장하기(request, bs4, mongoDB 패키지 사용) 졸리운_곰 2023.03.12 461
56 [python][자료구조] [MongoDB] Document Query(조회) – find() 메소드 졸리운_곰 2023.03.08 315
55 [python][자료구조] Python(flask)으로 mongoDB 제어하기 – pymongo file 졸리운_곰 2023.03.08 604
54 [python][자료구조] django sqlite3 MySQL로 전환하기 file 졸리운_곰 2023.03.02 409
53 [python][자료구조] django에서 db.sqlite3 데이터를 mysql로 옮기기 졸리운_곰 2023.03.02 427
52 [python][자료구조] Python - JSON 파일 읽고 쓰는 방법 졸리운_곰 2023.02.04 480
51 [python][자료구조] [인코딩] 유니코드 인코딩 처리 (특히 json 입출력 시) 졸리운_곰 2023.02.04 363
50 [python][자료구조] Dropbox API 사용하기 (with python) 졸리운_곰 2022.12.03 306
49 [Python][자료구조] SQLAlchemy Tutorial(한글) - 2 졸리운_곰 2022.12.03 393
48 [Python]][자료구조] SQLAlchemy Tutorial(한글) - 1 졸리운_곰 2022.12.03 275
47 [python][자료구조] python anaconda 에서 mysql 접속 졸리운_곰 2022.01.25 657
46 [python 자료구조] 림코딩의 파이썬으로 csv 다루기 강좌 (읽기,쓰기,수정,추가) 졸리운_곰 2022.01.16 521
45 python - 읽은 후 kafka 메시지를 삭제하는 방법 졸리운_곰 2021.07.13 902
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED