2020年3月7日土曜日

WebSocketでチャット(Tornadoを使う)

暇なので、WebSocketでチャットしてみた。
(Tornadoを使う)
クライアントからアクセスするIPアドレスやポートは適当に変更する。

※追記3(2020/03/09 20:40)※
HTTPとWebSocketサーバを一つにしてみた。

サーバ(HTTPサーバ及びWebSocketサーバ)
例えば:tornado_server.py というファイル名にする。
このファイルを置いたディレクトリに templates と static という名の子ディレクトリを作っておく。
#!/usr/bin/env python
#-*- coding:utf-8 -*-

import tornado.ioloop
import tornado.web
import tornado.websocket
import datetime
import os.path

cl = []
dic = {}
todaydetail = datetime.datetime.today()
today = todaydetail.strftime("%Y_%m_%d")
print(today)
today_log = str(today) + "_log.txt"
print(today_log)
if not os.path.exists(today_log):
    f = open(today_log, "w")

#クライアントからメッセージを受けるとopen → on_message → on_closeが起動する
class WebSocketHandler(tornado.websocket.WebSocketHandler):
    def check_origin(self, origin):
        return True

    #websocketオープン
    def open(self):
        print("open")
        if self not in cl:
            cl.append(self)
            print(len(dic))
            dic[self] = len(dic) 
            print(self)

            f = open(today_log, "r")
            for row in f:
                self.write_message(row.strip())
            f.close()

            self.write_message("Welcome !;;")
 
    #処理
    def on_message(self, message):
        print("on_message")
        mess = str(message) + "; ID=" + str(self)[37:47]
        f = open(today_log, "a")
        f.write(mess + "\n")
        f.close()

        for client in cl:
            print(str(self))
            print(message)
            #クライアントへメッセージを送信
            client.write_message(mess)
 
    #websockeクローズ
    def on_close(self):
        print("close")
        if self in cl:
            cl.remove(self)

#HTTPサーバ
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("index.html")

app = tornado.web.Application([
    (r"/", MainHandler),
    (r"/websocket", WebSocketHandler),
    ],

    #HTTPサーバで使うpathを設定
    template_path = os.path.join(os.getcwd(),  "templates"),
    static_path = os.path.join(os.getcwd(),  "static"),
)

if __name__ == "__main__":
   app.listen(8888)
   tornado.ioloop.IOLoop.instance().start()


インデックス
index.html と言うファイル名にする。これを templates ディレクトリに置く。
HTTPサーバにアクセスすると、この index.html が呼ばれる。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,
 initial-scale=1.0,user-scalable=yes" />
</head>
 <body>
  Tornado is awesome !<br>
  <a href="{{static_url("websocket_chat_client.html")}}">Chat Client</a>
 </body>
</html>


クライアント
websocket_chat_client.html と言うファイル名にする。これを static ディレクトリに置く。
インデックスのリンクから呼び出される。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width,
  initial-scale=1.0,user-scalable=yes" />
<title>WebSocketでチャットしてみよう</title>
<style>
    #name{
        width:100px;
        height:20px;
    }

    #message{
        width:250px;
        height:20px;
    }
</style>
<script langage="JavaScript">
    ws = new WebSocket("ws://192.168.1.11:8888/websocket");

    ws.onopen = function(e) {
//  ws.send("Hi Open; ");
    }

    ws.onmessage = function(e) {
        var mon = document.getElementById("monitor");
        var mes = e.data;
        mes_line = mes.split(";");

        var div = document.createElement("div");
        mon.appendChild(div);
        div.style.width = "500px";
        div.style.padding = "10px 10px 10px 10px";
        div.style.margin = "10px 0px 10px 0px";
        div.style.border = "solid 1px #0000ff";
        var div_att = "<div class='mess' style='overflow:auto;padding:5px 5px 5px 15px'>";
        div.innerHTML = mes_line[0] + mes_line[2] + div_att + mes_line[1] + "</div>";

//alert(document.body.clientHeight);
        var c_height = document.body.clientHeight;
        if(mes_line[0] == "Welcome !"){
            c_height = 0;
        }
        window.scrollTo(0, c_height);
    }

    function button00(mes){
        var weeks = new Array('日','月','火','水','木','金','土');
        var now = new Date();

        var year = now.getYear(); // 年
        var month = now.getMonth() + 1; // 月
        var day = now.getDate(); // 日
        var week = weeks[ now.getDay() ]; // 曜日
        var hour = now.getHours(); // 時
        var min = now.getMinutes(); // 分
        var sec = now.getSeconds(); // 秒

        if(year < 2000) { year += 1900; }

        // 数値が1桁の場合、頭に0を付けて2桁で表示する指定
        if(month < 10) { month = "0" + month; }
        if(day < 10) { day = "0" + day; }
        if(hour < 10) { hour = "0" + hour; }
        if(min < 10) { min = "0" + min; }
        if(sec < 10) { sec = "0" + sec; }

        var now_date = year + "/" + month + "/" + day + "(" + week + ")";
        var now_time = hour + ":" + min + ":" + sec;
        var nam = document.getElementById("name").value;
        ws.send(nam + " " + now_date + " " + now_time + ";" + mes);

        document.getElementById("message").value = "";
    }

</script>
</head>
<body>
<h1>WebSocketでチャットしてみよう</h1>
<h3>メッセージ</h3>
<div id="monitor"></div>

<p>
表示する名前
<input type="text" id="name" value="ななし" class="name" />
</p>

<p>
<input type="text" id="message" value="text" class="message"/>
<button onClick="button00(document.getElementById('message').value)">送信</button>
</p>
<p>
※ WebSocketのテストです ※
</p>
</body>
</html>