以最少的数据使用推送通知
Push notifications with minimal data usage
在我的项目中,我想从 Internet 调用对 Raspberry Pi 的操作。有点像这样:
- 访问网页
- 点击网页上的按钮
- Raspberry pi 执行脚本
困难的部分是 raspberry pi 只有移动互联网连接 没有统一费率 。因此,发送和接收数据 from/to Raspberry Pi 是昂贵的。
所以这是我的问题:
我可以使用哪些技术和模式将推送通知发送到 raspberry pi ,同时使用最少的数据?
首先在 RPi 上创建或启动接受传入连接的东西。像下面的例子那样的小东西:
#!/usr/bin/python
from socket import *
s = socket()
s.bind(('', 8001))
s.listen(4)
while 1:
ns, na = s.accept()
print(na,'sent you:',ns.recv(8192))
现在,上面的例子只会在 8001
上打开一个端口,然后打印其他发送给它的任何内容。
在服务器端,我建议您设置一个 Web 服务器或其他易于访问的东西,可以将 IP 存储在 database/register 某处。
然后,在你的树莓派启动期间(首选在网络服务启动之后)继续并安排:
curl https://your-server.eu/reg_ip.php > /dev/null 2>&1
现在,在服务器 your-server.eu:443
上,确保 req_ip.php
将客户端 IP(客户端是您的 RPi)保存在某个数据库中。
现在,您需要发送 PUSH 通知的任何应用程序都可以在数据库中查找客户端的当前 IP 并尝试连接到这些 IP 上的端口 8001
并发送您需要的任何数据.
现在有两件事:
侦听 TCP 套接字(在 RPi 上)根本不会用完任何数据,但会在需要时允许传入连接。
如果您的 RPi 上的 IP 发生变化(例如,它可能会在移动的 GSM/3G/4G 网络上发生变化),您需要向服务器发送另一个 curl
请求。然而,这可以很容易地绑定到例如 ip monitor
命令,然后执行 curl 请求。
tl;博士
这是您的链条:
Pi opens a listening socket -> Pi connects to HTTP(S) -> servers saves IP -> when server has something to send -> connect to last known IP on port X -> send data -> close connection
进一步加强
现在,单独的 HTTP header 就相当大了,实际上它是默认的 78 字节包数据(TCP 和 IP headers 通常不包括在数据速率中,只有数据正在传输的是 - 在本例中为 HTTP 数据。)。所以你可以扩展的是,如果你也可以在服务器上使用上面的简单套接字示例,只需获取 na[0]
变量并将其发送到数据库,这样你就可以直接使用 0 data-rate 在您的数据订阅上。
只有稍后从服务器应用程序作为 "PUSH notification" 发送的实际数据才会用完数据。
如果您的树莓派位于基于 NAT 的网络(专用网络)上
看到 OP 获得了一个 10.X.X.X
地址,侦听套接字不太可能做到这一点。
相反,您可以做的是简单地尝试建立连接并保持连接打开,并让服务器在有数据时通过任何打开的套接字发送数据。
这里有一个关于如何实现它的非常粗略的想法。
我保持简单和愚蠢只是为了提供一个想法而没有解决整个问题。
同样,在您实际通过通道发送数据之前,客户端 (RPi) 和服务器之间的开放套接字不会用完任何数据。
您可以在服务器中从数据库中获取要发送给客户端的数据,您真的可以做任何事情。由于我不知道你的目标,所以我暂时保持原样。
服务器:
#!/usr/bin/python
from socket import *
from threading import *
from time import time, sleep
from random import randint
class ClientThread(Thread)
def __init__(self, clients):
self.clients = clients
self.messages = []
Thread.__init__(self)
self.start()
def notify(self, message):
if type(message) is str: message = bytes(message, 'UTF-8')
self.messages.append(message)
def run(self):
while 1:
if len(self.messages) > 0:
m = self.messages.pop(0)
for client in self.clients:
self.clients[client]['sock'].send(m)
class RandomMessageGenerator(Thread):
def __init__(self, notify_func):
self.notify_func = notify_func
self.last = time()
Thread.__init__(self)
self.start()
def run(self):
while 1:
self.notify_func('Time since last update: ' + str(time() - self.last))
self.last = time()
sleep(randint(0,30))
client_list = {}
client_thread_handle = ClientThread(client_list)
random_generator = RandomMessageGenerator(client_thread_handle.nofity)
s = socket()
s.bind(('', 8001))
s.listen(4)
while 1:
ns, na = s.accept()
client_list[na] = {'sock' : 'ns'}
客户:
from socket import *
s = socket()
s.connect(('server', 8001))
while 1:
print(s.recv(8192))
在我的项目中,我想从 Internet 调用对 Raspberry Pi 的操作。有点像这样:
- 访问网页
- 点击网页上的按钮
- Raspberry pi 执行脚本
困难的部分是 raspberry pi 只有移动互联网连接 没有统一费率 。因此,发送和接收数据 from/to Raspberry Pi 是昂贵的。
所以这是我的问题:
我可以使用哪些技术和模式将推送通知发送到 raspberry pi ,同时使用最少的数据?
首先在 RPi 上创建或启动接受传入连接的东西。像下面的例子那样的小东西:
#!/usr/bin/python
from socket import *
s = socket()
s.bind(('', 8001))
s.listen(4)
while 1:
ns, na = s.accept()
print(na,'sent you:',ns.recv(8192))
现在,上面的例子只会在 8001
上打开一个端口,然后打印其他发送给它的任何内容。
在服务器端,我建议您设置一个 Web 服务器或其他易于访问的东西,可以将 IP 存储在 database/register 某处。
然后,在你的树莓派启动期间(首选在网络服务启动之后)继续并安排:
curl https://your-server.eu/reg_ip.php > /dev/null 2>&1
现在,在服务器 your-server.eu:443
上,确保 req_ip.php
将客户端 IP(客户端是您的 RPi)保存在某个数据库中。
现在,您需要发送 PUSH 通知的任何应用程序都可以在数据库中查找客户端的当前 IP 并尝试连接到这些 IP 上的端口 8001
并发送您需要的任何数据.
现在有两件事:
侦听 TCP 套接字(在 RPi 上)根本不会用完任何数据,但会在需要时允许传入连接。
如果您的 RPi 上的 IP 发生变化(例如,它可能会在移动的 GSM/3G/4G 网络上发生变化),您需要向服务器发送另一个
curl
请求。然而,这可以很容易地绑定到例如ip monitor
命令,然后执行 curl 请求。
tl;博士
这是您的链条:
Pi opens a listening socket -> Pi connects to HTTP(S) -> servers saves IP -> when server has something to send -> connect to last known IP on port X -> send data -> close connection
进一步加强
现在,单独的 HTTP header 就相当大了,实际上它是默认的 78 字节包数据(TCP 和 IP headers 通常不包括在数据速率中,只有数据正在传输的是 - 在本例中为 HTTP 数据。)。所以你可以扩展的是,如果你也可以在服务器上使用上面的简单套接字示例,只需获取 na[0]
变量并将其发送到数据库,这样你就可以直接使用 0 data-rate 在您的数据订阅上。
只有稍后从服务器应用程序作为 "PUSH notification" 发送的实际数据才会用完数据。
如果您的树莓派位于基于 NAT 的网络(专用网络)上
看到 OP 获得了一个 10.X.X.X
地址,侦听套接字不太可能做到这一点。
相反,您可以做的是简单地尝试建立连接并保持连接打开,并让服务器在有数据时通过任何打开的套接字发送数据。
这里有一个关于如何实现它的非常粗略的想法。
我保持简单和愚蠢只是为了提供一个想法而没有解决整个问题。
同样,在您实际通过通道发送数据之前,客户端 (RPi) 和服务器之间的开放套接字不会用完任何数据。
您可以在服务器中从数据库中获取要发送给客户端的数据,您真的可以做任何事情。由于我不知道你的目标,所以我暂时保持原样。
服务器:
#!/usr/bin/python
from socket import *
from threading import *
from time import time, sleep
from random import randint
class ClientThread(Thread)
def __init__(self, clients):
self.clients = clients
self.messages = []
Thread.__init__(self)
self.start()
def notify(self, message):
if type(message) is str: message = bytes(message, 'UTF-8')
self.messages.append(message)
def run(self):
while 1:
if len(self.messages) > 0:
m = self.messages.pop(0)
for client in self.clients:
self.clients[client]['sock'].send(m)
class RandomMessageGenerator(Thread):
def __init__(self, notify_func):
self.notify_func = notify_func
self.last = time()
Thread.__init__(self)
self.start()
def run(self):
while 1:
self.notify_func('Time since last update: ' + str(time() - self.last))
self.last = time()
sleep(randint(0,30))
client_list = {}
client_thread_handle = ClientThread(client_list)
random_generator = RandomMessageGenerator(client_thread_handle.nofity)
s = socket()
s.bind(('', 8001))
s.listen(4)
while 1:
ns, na = s.accept()
client_list[na] = {'sock' : 'ns'}
客户:
from socket import *
s = socket()
s.connect(('server', 8001))
while 1:
print(s.recv(8192))