无法在移动设备上打开 websocket
Posted
技术标签:
【中文标题】无法在移动设备上打开 websocket【英文标题】:Can't open websocket on mobile devices 【发布时间】:2016-12-09 04:46:17 【问题描述】:我正在尝试设置一个 websocket,并在我的树莓派上运行服务器。下面的代码是根据我找到的 here 的一个例子稍微修改的。
我围绕这个示例构建了一个完整的网页,允许我控制 gpio 并将消息发送到插入 pi 的串行设备。该站点和此示例都可以在我的笔记本电脑上完美运行(Windows 10 使用 Chrome 或 Firefox)。
但是,当我从手机连接时(android 5.0.1 使用 Chrome for android)。它似乎永远不会打开套接字。在示例代码中,它只显示“消息到这里。
我的第一个想法是 android 上的 chrome 不支持 websockets,但我能够在该站点 http://www.websocket.org/echo.html 上连接和回显消息。所以看起来功能就在那里。
还有什么会阻止套接字打开?
pysocket.py
import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
class WSHandler(tornado.websocket.WebSocketHandler):
def check_origin(self, origin):
return True
def open(self):
print 'New connection was opened'
self.write_message("Welcome to my websocket!")
def on_message(self, message):
print 'Incoming message:', message
self.write_message("You said: " + message)
def on_close(self):
print 'Connection was closed...'
application = tornado.web.Application([
(r'/ws', WSHandler),
])
if __name__ == "__main__":
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8888)
tornado.ioloop.IOLoop.instance().start()
pysocket.php
<!doctype html>
<html>
<head>
<title>WebSockets with Python & Tornado</title>
<meta charset="utf-8" />
<style type="text/css">
body
text-align: center;
min-width: 500px;
</style>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script>
$(function()
var ws;
var logger = function(msg)
var now = new Date();
var sec = now.getSeconds();
var min = now.getMinutes();
var hr = now.getHours();
$("#log").html($("#log").html() + "<br/>" + hr + ":" + min + ":" + sec + " ___ " + msg);
//$("#log").animate( scrollTop: $('#log')[0].scrollHeight, 100);
$('#log').scrollTop($('#log')[0].scrollHeight);
var sender = function()
var msg = $("#msg").val();
if (msg.length > 0)
ws.send(msg);
$("#msg").val(msg);
ws = new WebSocket("ws://raspberrypi-mike:8888/ws");
ws.onmessage = function(evt)
logger(evt.data);
;
ws.onclose = function(evt)
$("#log").text("Connection was closed...");
$("#thebutton #msg").prop('disabled', true);
;
ws.onopen = function(evt) $("#log").text("Opening socket..."); ;
$("#msg").keypress(function(event)
if (event.which == 13)
sender();
);
$("#thebutton").click(function()
sender();
);
);
</script>
</head>
<body>
<h1>WebSockets with Python & Tornado</h1>
<div id="log" style="overflow:scroll;width:500px; height:200px;background-color:#ffeeaa; margin:auto; text-align:left">Messages go here</div>
<div style="margin:10px">
<input type="text" id="msg" style="background:#fff;width:200px"/>
<input type="button" id="thebutton" value="Send" />
</div>
<a href="http://lowpowerlab.com/blog/2013/01/17/raspberrypi-websockets-with-python-tornado/">www.LowPowerLab.com</a>
</body>
</html>
【问题讨论】:
你试过用树莓派的IP代替raspberrypi-mike
吗?
我没有。今晚我会试试的。我想,因为我的笔记本电脑可以连接主机名,所以它正在工作。我的手机需要 IP 而不是主机名有什么特别的原因吗?
用 ip 替换主机名确实解决了问题。现在我很好奇为什么我的手机浏览器无法解析主机名。
我已经添加了一个答案和解释,我认为正在发生的事情。
【参考方案1】:
添加了一些额外的代码
我建议使用 node.js:
var express = require("express");
var app = express();
var http = require("http").Server(app);
var path = require("path");
var io = require('socket.io')(http);
var SerialPort = require('serialport');
var gpio = require('rpio');
http.listen(3000);
var serialPort = new SerialPort.SerialPort("/dev/ttyAMA0",
baudrate: 115200,
dataBits: 8,
parity: "none",
stopBits: 1,
flowControl: false
);
io.on('connection', function(socket)
console.log('Connected');
socket.on("WriteSerial:get",function(data)
var hex = new Buffer (data, "hex"); //be careful passing data
writeSerial(serialPort, hex);
io.emit("WriteSerial:response", "Data writen!");
);
socket.on("ReadGPIO:get",function(data)
var input = readPin(data.pin);
io.emit("ReadGPIO:response", input);
);
socket.on("WriteGPIO:get",function(data)
writePin(data.pin, data.time);
io.emit("WriteGPIO:response", "Set!");
);
socket.on("unWriteGPIO:get",function(data)
unwritePin(data);
io.emit("unWriteGPIO:response", "Set!");
);
app.use(express.static(path.join(__dirname, '/')));
app.get("/home",function(req,res,next)
res.sendFile(path.join(__dirname + "/index.html"));
);
function writeSerial (port, data)
port.write(data, function(err)
if (err)
return console.log('Error on write: ', err.message);
else
console.log('Data written: ' + data);
);
function readPin(pin)
rpio.open(pin, rpio.INPUT);
var read = rpio.read(pin) ? 'high' : 'low';
return read;
function writePin(pin, timeInMs)
rpio.open(pin, rpio.OUTPUT, rpio.LOW);
rpio.write(pin, rpio.HIGH);
if (timeInMs > 0)
setTimeout(function()
rpio.write(pin, rpio.LOW);
, timeInMs);
//You can put 0 if You want it to be high until You shut it down
function unWritePin(pin)
if(readPin(pin) === 'high')
rpio.write(pin, rpio.LOW);
else
console.log("Pin already low!");
确保您已安装正确版本的 node.js。如果不在终端中执行此操作:
sudo apt-get remove nodered && sudo apt-get remove nodejs nodejs-legacy && 卷曲-sLhttps://deb.nodesource.com/setup_4.x | sudo bash - && sudo apt-get install -y nodejs
在 '/home/pi/' 中创建一个文件夹 'server',将 server.js 添加到其中。添加我提供给 server.js 的代码。使用终端打开该文件夹:
cd /home/pi/server/
安装服务器上使用的所有模块之后:
sudo npm install express && sudo npm install http && sudo npm install path && sudo npm install socket.io && sudo npm install serialport --unsafe-perm && sudo npm install rpio --unsafe-perm
现在我们要做的就是创建客户端部分。在文件夹“/home/pi/server”中创建 index.html 文件并添加名为“js”的文件夹。在文件夹“js”中为客户端添加 socket.io.js,您可以在文件夹 '/home/pi/server/node_modules/socket.io/node_modules/socket.io-client/' 中找到.
将客户端的 socket.io.js 包含到您的 index.html 中,如下所示:
<script type="text/javascript" src="js/socket.io.js" /></script>
还将 main.js 文件添加到“js”文件夹中,您将在其中放置您的 javascript 代码并将其包含到 index.html:
<script type="text/javascript" src="js/main.js" /></script>
<script type="text/javascript" src="js/jquery.js" /></script>
我不会制作任何图形,但这里有一些 main.js 代码:
$(document).ready(function()
var socket = io.connect('http://your_ip_address_rpi:3000');
$( "#myButton" ).click(function()
io.emit("WriteSerial:get", $("#myTextHolder").val()); //"FAAF531C" this is string of hex, should be added some filter to pass error when char is not part of HEX!
);
$( "#myButton2" ).click(function()
io.emit("WriteGPIO:get", "pin" : $("#myPinHolder").val(), "time" : $("#myTimeHolder").val())
要在 RPI 启动时运行服务器,请使用“sudo nano”编辑器在“exit 0”之前添加“sudo node /home/pi/server/server.js &”到“/etc/rc.local”。
它适用于任何设备。
【讨论】:
谢谢。我从未使用过 node.js,但我可以试一试。您能否详细说明它的不同之处在于它可以在我的手机上运行,而我的原始代码却不能? 我已经对其进行了测试,并且可以在我尝试过的所有移动设备上运行。 Node 具有更好的性能,具有处理 Web 请求和响应的内置库,因此您不需要单独的 Web 服务器或其他依赖项。正如我们所说的 Raspberry Pi 节点将保持 RPI 的稳定性。与 node 相比,PHP 使用起来“容易”,但我仍然建议在这种状态下使用 node。 我自己做了很多节点服务器,我个人更喜欢节点而不是 PHP。 还有一些功能您可以添加到节点服务器正在播放 mp3 文件,因此您可以制作诸如声音站(搜索节点模块播放声音)之类的东西,在 RPI 上添加图片以制作时间间隔或捕获许多mjpeg 图片在 1 秒内发布并像视频一样发布到客户端。如果您喜欢玩 RPI,这就是您的选择。【参考方案2】:为了使设备的主机名能够跨网络工作,设备必须公布自己的主机名或仅响应 DNS 查询以获取自己的主机名。
无论 Raspberry Pi 使用什么实现,您的笔记本电脑都支持它,但您的手机不支持。
因此,为了能够连接,您需要在 JavaScript 代码中将主机名 raspberrypi-mike
更改为您的 Raspberry Pi 的 IP 地址。
【讨论】:
以上是关于无法在移动设备上打开 websocket的主要内容,如果未能解决你的问题,请参考以下文章
Node wss Websocket 在桌面上工作,而不是在移动设备上
我无法在 iOS 移动设备上使用 Phonegap 打开弹出对话框