2017-08-28 47 views
0

我試圖創造一個Python應用程序,可以從服務器發送消息給客戶端發送消息給客戶端。目前我使用here這個示例代碼。這是一個聊天應用程序,它工作正常。我試圖修改應用程序,並在服務器端Python代碼中添加一個新功能,該功能將在客戶端打印一條消息「Dummy」,但看起來不起作用。如何從服務器使用瓶套接字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() 

我可以看到「收到的消息:虛擬」在終端,但沒有對網絡瀏覽器的變化。

+0

很難知道,而無需一個完整的例子來進行測試。您是否在瀏覽器的控制檯中查看是否有任何錯誤? – Miguel

回答

0

這些裝飾都是在那裏只需加載index.html的頁面和blah.html這些沒有做任何事情---不傳遞任何變量或不寫什麼模板,他們只是使其,同時所有的東西你正在做的是那裏的命令行,如果你要打印或通過任何它必須是在這些功能:

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


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

它在'Thread'的'target ='中。 –

1

你有錯誤,其阻止你這樣做:

第一,您正嘗試從套接字上下文之外的socket.io發出事件。

當一個函數被@socketio.on修飾器包裝時,它將變成Event-Handlers。 雖然事件是在服務器端的發射將尋找正確的處理程序來處理事件和初始化的背景下發出該事件的特定的客戶端。

沒有這方面的初始化,您socketio.emit('output', str(json), namespace='/chat')會做任何事情,因爲服務器不知道誰應發出迴響應。

反正有手動發射事件特定客戶(即使你是不是在它的上下文中)的一個小動作。每次打開套接字時,服務器都會將其分配給與套接字標識(sid)具有相同名稱的「私人」空間。因此,爲了從客戶方面將消息發送到客戶端外,您可以創建連接的客戶端ID的列表,並調用與room=<id>參數信號發送的功能。

例如:

web_app。潘岳:

... 

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:

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") 

... 

但是,即使你試試這個,這是不行的(這使我們到了第二個錯誤)。


,你用常規的Python線程混合eventlet,它是不是一個好主意。 eventlet使用的綠色線程對常規線程無效。相反,您應該使用綠色線程來滿足您的所有線程需求。

一個選擇,我在互聯網上找到,是猴子修補Python標準庫,使線程,插座等與eventlet友好的版本替換。您可以在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)'行阻止了進一步的進程。 所以我目前正在開發一個用戶的計算機「對話」的應用程序,將用戶的語音作爲輸入>使用沃森STT其轉錄成文本>發送到沃森通話服務>擺脫在Python沃森>顯示響應響應。這部分已經完成。所以現在,我計劃還將輸入(轉錄文本)和沃森的迴應顯示在網頁中(實時) – nyamuk91

相關問題