2017-08-28 9 views
0

サーバーからクライアントにメッセージを送信できるPythonアプリケーションを作成しようとしています。現在、このサンプルコードはhereから使用しています。これはチャットアプリで、うまくいきます。私は、アプリケーションを変更し、クライアントにメッセージ "ダミー"を印刷するサーバー側のPythonコードで新しい関数を追加しようとしましたが、うまくいかなかったようです。Flask-Socket IOを使用してサーバーからクライアントにメッセージを送信する方法

は、ここに私のhtmlコードです:

index.htmlを

<body> 
    <ul id="messages"></ul> 
    <ul id="output"></ul> 
    <form action=""> 
     <input id="m" autocomplete="off" /><button>Send</button> 
    </form> 

<script src="{{url_for('static', filename='assets/vendor/socket.io.min.js')}}"></script> 
<script src="{{url_for('static', filename='assets/vendor/jquery.js')}}"></script> 

<script> 
    var socket = io.connect('http://127.0.0.1:5000/chat'); 

    $('form').submit(function(){ 
    socket.emit('chat message', $('#m').val()); 
    $('#m').val(''); 
    return false; 
    }); 

    socket.on('chat message', function(msg){ 
    $('#messages').html($('<li>').text(msg)); 
    }); 

    socket.on('output', function(msg){ 
    alert(msg) 
    $('#messages').html($('<li>').text(msg)); 
    }); 
</script> 

ここに私のバックエンドのコードです:

web_app.py

from flask import Flask 
from flask import render_template 
from flask_socketio import SocketIO 
from flask_socketio import emit 

app = Flask(__name__) 
app.config['SECRET_KEY'] = 'secret!' 
socketio = SocketIO(app) 
connected = False 

def socket_onload(json): 
    socketio.emit('output', str(json), namespace='/chat') 
    print('received message: ' + str(json)) 


@socketio.on('chat message', namespace='/chat') 
def handle_chat_message(json): 
    print('received message: ' + str(json)) 
    emit('chat message', str(json), broadcast=True) 


@socketio.on('connect') # global namespace 
def handle_connect(): 
    global connected 
    connected = True 
    print('Client connected') 

@socketio.on('connect', namespace='/chat') 
def handle_chat_connect(): 
    print('Client connected to chat namespace') 
    emit('chat message', 'welcome!') 

@socketio.on('disconnect', namespace='/chat') 
def test_disconnect(): 
    print('Client disconnected') 


@app.route('/') 
def index(): 
    return render_template('index.html') 


@app.route('/blah/') 
def blah(): 
    return render_template('blah.html') 

main.py

import web_app 
import threading 
import time 

def main(): 
    import web_app 
    webapp_thread = threading.Thread(target=run_web_app) 
    webapp_thread.start() 
    # webapp_thread = threading.Thread(target=run_web_app, args=(i,)) 

    while web_app.connected==False: 
     print "waiting for client to connect" 
     time.sleep(1) 
     pass 

    print "Connected..." 
    time.sleep(3) 
    print "Trying to print dummy message..." 
    web_app.socket_onload("Dummy") 

def run_web_app(): 
    web_app.socketio.run(web_app.app) 

if __name__ == '__main__': 
    main() 

私は、「受信したメッセージ:ダミー」を参照してくださいすることができ、端末ではなく、Webブラウザ上で何も変更。

+0

テストするための完全な例がなくても分かりません。エラーがあるかどうかをブラウザのコンソールで確認しましたか? – Miguel

答えて

0

これらのデコレータは単にページindex.htmlblah.htmlをロードするためのものです。これらは何もしません---変数を渡さないでください、あるいは単にそれらをレンダリングするテンプレートに何も書き込まないでください。やっているあなたは、それは、これらの機能でなければならないであろう何かを印刷したり、合格する必要がある場合は、コマンドラインのためにあります。

@app.route('/') 
def index(): 
    return render_template('index.html') 


@app.route('/blah/') 
def blah(): 
    return render_template('blah.html') 
+0

これは 'Thread'の' target = 'にあります。 –

1

あなたはそうすることからあなたを防ぐ2つのミスがあります。

を最初、ソケットコンテキスト外のsocket.ioでイベントを発行しようとしています。

関数を@socketio.onデコレータでラップすると、Event-Handlersになります。 サーバー側でイベントが発生している間、イベントを処理するための適切なハンドラを検索し、イベントを発行した特定のクライアントへのコンテキストを初期化します。

このコンテキストが初期化されていないと、サーバは応答を返すべき相手をサーバが知らないため、何もしません。

とにかく、手動特定のクライアント(あなたはそのコンテキスト中でなくても)にイベントを放出するためのちょっとしたトリックがあります。ソケットが開かれるたびに、サーバーはソケットID(sid)と同じ名前の「プライベート」ルームにソケットを割り当てます。したがって、クライアントのコンテキストから外部のクライアントにメッセージを送信するには、接続されたクライアントのIDのリストを作成し、room=<id>引数を指定してemit関数を呼び出します。例えば

web_app。もたらした(

import web_app 
import threading 
import time 

def main(): 
    webapp_thread = threading.Thread(target=target=run_web_app) 
    webapp_thread.start() 

    while not web_app.clients: 
     print "waiting for client to connect" 
     time.sleep(1) 

    print "Connected..." 
    time.sleep(3) 
    print "Trying to print dummy message..." 
    web_app.send_message(web_app.clients[0], "Dummy") 

... 

しかし、あなたはこれを試す場合でも、それは動作しません:PY:

... 

clients = [] 

@socketio.on('connect') 
def handle_connect(): 
    print('Client connected') 
    clients.append(request.sid) 

@socketio.on('disconnect') 
def handle_disconnect(): 
    print('Client disconnected') 
    clients.remove(request.sid) 

def send_message(client_id, data): 
    socketio.emit('output', data, room=client_id) 
    print('sending message "{}" to client "{}".'.format(data, client_id) 

... 

あなたはおそらく次のようにこれを使用します。

main.py私たちは2番目の間違いに)。


第二、あなたは、通常のPythonのスレッドでeventlet混合され、それは良い考えではありません。イベントレットが使用する緑色のスレッドは、通常のスレッドではうまく動作しません。代わりに、すべてのスレッドの必要性に緑のスレッドを使用する必要があります。

私はインターネットで見つけた1つのオプションは、スレッド、ソケットなどがイベントレットフレンドリなバージョンに置き換えられるように、Python標準ライブラリを猿にパッチすることです。これは、main.pyスクリプトの一番上で行うことができます。

import eventlet 
eventlet.monkey_patch() 

その後、正常に動作するはずです(私自身で試しました)。別の問題がある場合はお知らせください...

+0

お返事ありがとうございます。しかし、それはまだ動作しませんでした。コンソールログにもエラーはありません。ちょうど質問、リアルタイムpython-htmlの更新を実装するための最良の方法/ライブラリは何ですか? flask-socketioのように、これを直接行う方法はありません。私の唯一の目的は、Pythonモジュールに他のPythonモジュールの出力をhtmlにプッシュさせることです。 – nyamuk91

+0

私はなぜこのために別のスレッドを作成しようとしているのか分かりません。あなたが必要とする流れの例を教えてもらえますか?私はあなたがあなたのアクションをsocket.ioサーバスレッドから開始でき、バックグラウンドタスクを実行したい場合にのみ 'socketio.start_background_task'関数を使用してください。 – AlonP

+0

申し訳ありません、私はフラスコにはとても新しいです。別のスレッドを作成するのは、 'web_app.socketio.run(web_app.app) 'という行が次のプロセスをブロックしていたからです。 現在、私はユーザーの音声を入力として受け取り、Watson STT> Watson Conversation Service> Watsonから応答を得る> Pythonで応答を表示してテキストをテキストに変換するユーザーコンピュータの会話アプリケーションを開発しています。この部分はすでに完了しています。だから、私は入力(転写されたテキスト)とワトソンからの応答をウェブページに(リアルタイムで)表示する予定です – nyamuk91

関連する問題