flask新人問題, 想從不同的伺服器用Websocket收發資料,
主要的Flask Server程式部分:
from flask_socketio import SocketIO
app = Flask(__name__)
app.config.from_object(Config)
@socketio.on('for_test')
def for_test(test):
print("test")
if __name__ == '__main__':
socketio.run(app, host='0.0.0.0', port=5002, use_reloader=True, debug=True)
test.html:
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/socket.io/1.3.6/socket.io.min.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
var socket = io.connect('http://' + '192.168.1.183' + ':' + '5002');
$('#aa').click(function(event) {
socket.emit('for_test');
});
<!-- Socket on -->
socket.on('state_message', function(data) {
console.log(data);
var $textarea = $('#state_message');
$textarea.val(data);
})
});
<button id="aa" class="btn btn-primary btn-lg col-xs-3 col-xs-offset-3">aa</button>
按下'aa按鈕'後會'socket.emit'到'for_test', 然後Server會print出"test".
在這邊將var socket中的IP設為0.0.0.0或192.168.1.183皆可正常執行.
但想從其他伺服器送過來的時候卻都沒反應, 例如把上面這些整個複製、準備另外一份如下:
from flask_socketio import SocketIO
app = Flask(__name__)
app.config.from_object(Config)
@socketio.on('for_test')
def for_test(test):
print("test")
if __name__ == '__main__':
socketio.run(app, host='0.0.0.0', port=5003, use_reloader=True, debug=True)
在這邊只改了Port到5003, 然後網頁端完全一樣, 理想中的結果是在Port 5003網頁中的'aa按鈕'後, 5002會收到.
但測試結果卻沒有反應, 不清楚是哪裡寫錯, 還是對Websocket的用法理解錯誤了?
(這些都在架在同一台ubuntu伺服器上, 應該沒有被防火牆擋住之類的問題?)
現在狀況像這張圖, 全部都在同一台server進行. 在5002和5003各建一個flask server, 各自的server和web的websocket功能都正常, 但要是把位置改成另外一台, 例如5002送到5003(這樣在頁面需要同時建立5002:5002和5002:5003嗎?我的理解是只需要5002:5003), websocket會沒反應
後來找到問題了
Cross-Origin Controls
For security reasons, this server enforces a same-origin policy by default. In practical terms, this means the following:If an incoming HTTP or WebSocket request includes the Origin header, this header must match the scheme and host of the connection URL. In case of a mismatch, a 400 status code response is returned and the connection is rejected.
No restrictions are imposed on incoming requests that do not include the Origin header.
If necessary, the cors_allowed_origins option can be used to allow other origins. This argument can be set to a string to set a single allowed origin, or to a list to allow multiple origins. A special value of '*' can be used to instruct the server to allow all origins, but this should be done with care, as this could make the server vulnerable to Cross-Site Request Forgery (CSRF) attacks.
flask預設不能跨域
設為cors_allowed_origins='*'
就可以了
(這些都在架在同一台ubuntu伺服器上, 應該沒有被防火牆擋住之類的問題?)
還好你後面還是 「?」
其實就算是同一台機器呼叫。還是會有防火的問題存在。
再加上你用了其它port。大多數的port是鎖住的。
基本來說,會先試著將防火關掉再看看是不是防火的問題。
是的話,再打開一個一個調整試試。
sudo iptables -I INPUT -p tcp --dport 5002 -j ACCEPT
我用了這個指令開了5002, 5003, 80結果都一樣
基本我會先試著將iptables 暫時關掉試試。先確定是否是防火的問題。
service iptables stop整個關掉後仍然沒反應, 我自己是比較傾向我有寫錯
websocket是瀏覽器跟伺服器之間的連線,如果同時要接5002跟5003,那需要做兩個連線。另外,如果要5002收到5003的東西,那需要透過瀏覽器轉送。我不知道你是否是這樣做?
我現在想要讓5003的網頁送到5002的伺服器, 用前面貼的寫法可以5002網頁送到5002伺服器, 但不知道為什麼不能5003網頁送到5002伺服器.
建立連線我的理解是網頁端的這段和伺服器做連接
var socket = io.connect('http://' + '192.168.1.183' + ':' + '5002');
沒去注意到你說websocket
正常不同PORT的是無法直接互傳的。大多數都是由SERVER來做中間交接處理才對。
這部份我比較不熟門熟路,就請專業的回答你正確的答案了。
簡單說,websocket建立的是「瀏覽器」與「伺服器」之間的連線。如果你要兩個伺服器之間傳資料,那得要:
所以頁面可能會像這樣:
var socket1 = io.connect('url to 5002');
var socket2 = io.connect('url to 5003');
socket1.on('from_5002', function(data) {
socket2.emit('to_5003', data);//收到5002的資料,轉送到5003
}
我沒用過flask,所以也不知道他的能力。不過如果他有websocket client的功能,也是有可能用他直接送資料,不透過頁面來中轉就是了。
現在狀況像這張圖, 全部都在同一台server進行. 在5002和5003各建一個flask server, 各自的server和web的websocket功能都正常, 但要是把位置改成另外一台, 例如5002送到5003(這樣在頁面需要同時建立5002:5002和5002:5003嗎?我的理解是只需要5002:5003), websocket會沒反應
我用node.js寫:
corssws/index.js:
const args = require('minimist')(process.argv.slice(2));
const app = require('express')();
const http = require('http').createServer(app);
const io = require('socket.io')(http);
if(args._.length > 0) {
var port = parseInt(args._[0], 10);
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
http.listen(port, function(){
console.log(`listening on *:${port}`);
});
io.on('connection', socket => {
socket.emit('from-5002', 'message from 5002');
socket.on('to-5003', data => {
socket.emit('from-5003', `[5003 received] ${data}`);
});
});
} else {
help();
}
function help() {
console.log('[usage] node crossws [port]');
}
然後html:
<!doctype html>
<html>
<body>
<div id="panel"></div>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket1 = io('http://localhost:5002');
var socket2 = io('http://localhost:5003');
var hello = false;
socket1.on('from-5002', data => {
if(!hello)
socket2.emit('to-5003', data);
message(`from 5002: ${data}`);
});
socket2.on('from-5003', data => {
message(`from 5003: ${data}`);
});
function message(msg) {
var t = document.getElementById('panel');
t.innerHTML += `<br>${msg}`;
}
</script>
</body>
</html>
然後啟動兩個伺服器
> node crossws 5002
> node crossws 5003
開啟網頁( http://localhost:5002 ),會看到
from 5002: message from 5002
from 5003: [5003 received] message from 5002
(對了,這個例子要裝express, minimist 跟 socket.io)
html改了一下,有地方沒寫好:
<!doctype html>
<html>
<body>
<div id="panel"></div>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket1 = io('http://localhost:5002');
var socket2 = io('http://localhost:5003');
var hello = false;
socket1.on('from-5002', data => {
if(!hello) {
socket2.emit('to-5003', data);
message(`from 5002: ${data}`);
hello = true;
}
});
socket2.on('from-5003', data => {
message(`from 5003: ${data}`);
});
function message(msg) {
var t = document.getElementById('panel');
t.innerHTML += `<br>${msg}`;
}
</script>
</body>
</html>
不影響結果就是了。
python有 socketIO-client 套件可以轉發。
不過我搞不太懂這個應用場景是要幹麻,簡單的chat room一個server就夠了。
我猜只是為了測試而已,只是想法不太對,所以測不出東西。
改了一個交互送資料的版本:
index.js
const args = require('minimist')(process.argv.slice(2));
const app = require('express')();
const http = require('http').createServer(app);
const io = require('socket.io')(http);
if(args._.length > 0) {
var port = parseInt(args._[0], 10);
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
http.listen(port, function(){
console.log(`listening on *:${port}`);
});
io.on('connection', socket => {
socket.emit(`from-${port}`, `message from ${port}`);
console.log('client connected...');
socket.on(`to-${port}`, data => {
console.log(`server ${port} received: ${data}`);
socket.emit(`from-${port}`, `[${port} received] ${data}`);
});
});
} else {
help();
}
function help() {
console.log('[usage] node crossws [port]');
}
index.html
<!doctype html>
<head>
<style>
#panel {
border: solid 1px black;
height: 480px;
overflow-x: hidden;
overflow-y: scroll;
padding: 5px 5px 5px 5px;
}
</style>
</head>
<html>
<body>
<div id="panel"></div>
<script src="/socket.io/socket.io.js"></script>
<script>
var ports = ['5002', '5003'];
var count = 0;
var sockets = ports.reduce((prev, curr) => {
prev.push(io(`http://localhost:${curr}`));
return prev;
}, []);
sockets.forEach((socket, idx) => {
socket.on(`from-${ports[idx]}`, data => {
if(count < 30) {
var t = (idx+1)%ports.length;
sockets[t].emit(`to-${ports[t]}`, data);
message(`from ${ports[idx]}: ${data}, ${count}`);
count++;
}
});
});
function message(msg) {
var t = document.getElementById('panel');
t.innerHTML += `${msg}<br><hr size="1" width="100%"/>`;
}
</script>
</body>
</html>
頁面跑出來的結果:
雖然是js版的還是謝謝, 最後問題是flask預設不能跨域, 設定
cors_allowed_origins='*'
就可以了
socket收發部分是沒有寫錯的
那就好XD