- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在开发 raspberry pi 和 android 应用程序,每次打开应用程序时,它都会在网络中搜索 raspberry pi,如果找到 raspberry pi,则进行进一步的操作,否则会向用户提供 aknwolegement。我只需要树莓派的 IP 地址来做进一步的处理。
解决方案的目的-
将树莓派 IP 地址设为静态 - 不适用,因为应用程序从 Play 商店分发并且无法访问路由器。
正在网络中搜索树莓派 - 正在处理这个问题。
我尝试使用 SSDP、DLNA、UPNP 协议(protocol)在树莓派上创建服务器,每次应用程序在线时在网络中搜索树莓派。
使用资源
这是我做的
private static final String tag = "SSDP";
private static final String query = "M-SEARCH * HTTP/1.1\r\n" + "HOST: 239.255.255.250:1900\r\n" + "MAN: \"ssdp:discover\"\r\n" + "MX: 1\r\n" +
//"ST: urn:schemas-upnp-org:device:MediaServer:1\r\n" +
"ST: ssdp:all\r\n"+
"\r\n";
private static final int port = 1900;
String request() {
String response = "";
byte[] sendData;
byte[] receiveData = new byte[1024];
sendData = query.getBytes();
DatagramPacket sendPacket = null;
try {
sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("239.255.255.250"), port);
} catch (UnknownHostException e) {
Log.d(tag, "Unknown Host Exception Thrown after creating DatagramPacket to send to server");
e.printStackTrace();
}
DatagramSocket clientSocket = null;
try {
clientSocket = new DatagramSocket();
} catch (SocketException e) {
Log.d(tag, "Socket Exception thrown when creating socket to transport data");
e.printStackTrace();
}
try {
if (clientSocket != null) {
clientSocket.setSoTimeout(50000);
clientSocket.send(sendPacket);
}
} catch (IOException e) {
Log.d(tag, "IOException thrown when sending data to socket");
e.printStackTrace();
}
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
try {
if (clientSocket != null) {
clientSocket.receive(receivePacket);
}
} catch (IOException e) {
Log.d(tag, "IOException thrown when receiving data");
e.printStackTrace();
}
//the target package should not be empty
//try three times
for (int i = 0; i < 3; i++) {
Log.d(tag, "Checking target package to see if its empty on iteration#: " + i);
response = new String(receivePacket.getData());
Log.d(tag, "Response contains: " + response);
if (response.contains("Location:")) {
break;
}
}
String adress = "";
//filter IP address from "Location"
Matcher ma = Pattern.compile("Location: (.*)").matcher(response);
if (ma.find()) {
adress += ma.group(1);
adress = adress.split("/")[2].split(":")[0];
}
return adress;
}
使用上述方法和解决方案,我每次都能找到路由器 IP 地址,但不是 pi。还浏览了我在互联网上可以找到但没有用的每个图书馆。除此方法外,如有其他建议将不胜感激。
最佳答案
现在我终于想出了解决方案,我将逐步分享我的答案。我正在使用 ssdp 协议(protocol)在 Pi 具有动态 IP 地址的网络上找出 Pi。所以我在 python 中创建了服务器并使用 android 作为客户端。让我们先从服务器开始 -
您还可以找到服务器脚本 https://github.com/ZeWaren/python-upnp-ssdp-example
from lib.ssdp import SSDPServer
from lib.upnp_http_server import UPNPHTTPServer
import uuid
import netifaces as ni
from time import sleep
import logging
NETWORK_INTERFACE = 'wlp2s0'
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
def get_network_interface_ip_address(interface='eth0'):
while True:
if NETWORK_INTERFACE not in ni.interfaces():
logger.error('Could not find interface %s.' % (interface,))
exit(1)
interface = ni.ifaddresses(interface)
if (2 not in interface) or (len(interface[2]) == 0):
logger.warning('Could not find IP of interface %s. Sleeping.' % (interface,))
sleep(60)
continue
return interface[2][0]['addr']
device_uuid = uuid.uuid4()
local_ip_address = get_network_interface_ip_address(NETWORK_INTERFACE)
http_server = UPNPHTTPServer(8088,
friendly_name="Personal Home",
manufacturer="Home Personal SAS",
manufacturer_url='http://www.example.com/',
model_description='Home Appliance 3000',
model_name="Personal",
model_number="3000",
model_url="http://www.example.com/en/prducts/personal-3000/",
serial_number="PER425133",
uuid=device_uuid,
presentation_url="http://{}:5000/".format(local_ip_address))
http_server.start()
ssdp = SSDPServer()
ssdp.register('local',
'uuid:{}::upnp:rootdevice'.format(device_uuid),
'urn:schemas-upnp-org:device:MediaServer:1',
'http://{}:8088/jambon-3000.xml'.format(local_ip_address))
ssdp.run()
这将为服务器脚本创建一个执行点。
import random
import time
import socket
import logging
from email.utils import formatdate
from errno import ENOPROTOOPT
SSDP_PORT = 1900
SSDP_ADDR = '239.255.255.250'
SERVER_ID = 'Personal Home SSDP Server'
logger = logging.getLogger()
class SSDPServer:
known = {}
def __init__(self):
self.sock = None
def run(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if hasattr(socket, "SO_REUSEPORT"):
try:
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
except socket.error as le:
# RHEL6 defines SO_REUSEPORT but it doesn't work
if le.errno == ENOPROTOOPT:
pass
else:
raise
addr = socket.inet_aton(SSDP_ADDR)
interface = socket.inet_aton('0.0.0.0')
cmd = socket.IP_ADD_MEMBERSHIP
self.sock.setsockopt(socket.IPPROTO_IP, cmd, addr + interface)
self.sock.bind(('0.0.0.0', SSDP_PORT))
self.sock.settimeout(1)
while True:
try:
data, addr = self.sock.recvfrom(1024)
self.datagram_received(data, addr)
except socket.timeout:
continue
self.shutdown()
def shutdown(self):
for st in self.known:
if self.known[st]['MANIFESTATION'] == 'local':
self.do_byebye(st)
def datagram_received(self, data, host_port):
"""Handle a received multicast datagram."""
(host, port) = host_port
try:
header, payload = data.decode().split('\r\n\r\n')[:2]
except ValueError as err:
logger.error(err)
return
lines = header.split('\r\n')
cmd = lines[0].split(' ')
lines = map(lambda x: x.replace(': ', ':', 1), lines[1:])
lines = filter(lambda x: len(x) > 0, lines)
headers = [x.split(':', 1) for x in lines]
headers = dict(map(lambda x: (x[0].lower(), x[1]), headers))
logger.info('SSDP command %s %s - from %s:%d' % (cmd[0], cmd[1], host, port))
logger.debug('with headers: {}.'.format(headers))
if cmd[0] == 'M-SEARCH' and cmd[1] == '*':
# SSDP discovery
self.discovery_request(headers, (host, port))
elif cmd[0] == 'NOTIFY' and cmd[1] == '*':
# SSDP presence
logger.debug('NOTIFY *')
else:
logger.warning('Unknown SSDP command %s %s' % (cmd[0], cmd[1]))
def register(self, manifestation, usn, st, location, server=SERVER_ID, cache_control='max-age=1800', silent=False,
host=None):
"""Register a service or device that this SSDP server will
respond to."""
logging.info('Registering %s (%s)' % (st, location))
self.known[usn] = {}
self.known[usn]['USN'] = usn
self.known[usn]['LOCATION'] = location
self.known[usn]['ST'] = st
self.known[usn]['EXT'] = ''
self.known[usn]['SERVER'] = server
self.known[usn]['CACHE-CONTROL'] = cache_control
self.known[usn]['MANIFESTATION'] = manifestation
self.known[usn]['SILENT'] = silent
self.known[usn]['HOST'] = host
self.known[usn]['last-seen'] = time.time()
if manifestation == 'local' and self.sock:
self.do_notify(usn)
def unregister(self, usn):
logger.info("Un-registering %s" % usn)
del self.known[usn]
def is_known(self, usn):
return usn in self.known
def send_it(self, response, destination, delay, usn):
logger.debug('send discovery response delayed by %ds for %s to %r' % (delay, usn, destination))
try:
self.sock.sendto(response.encode(), destination)
except (AttributeError, socket.error) as msg:
logger.warning("failure sending out byebye notification: %r" % msg)
def discovery_request(self, headers, host_port):
"""Process a discovery request. The response must be sent to
the address specified by (host, port)."""
(host, port) = host_port
logger.info('Discovery request from (%s,%d) for %s' % (host, port, headers['st']))
logger.info('Discovery request for %s' % headers['st'])
# Do we know about this service?
for i in self.known.values():
if i['MANIFESTATION'] == 'remote':
continue
if headers['st'] == 'ssdp:all' and i['SILENT']:
continue
if i['ST'] == headers['st'] or headers['st'] == 'ssdp:all':
response = ['HTTP/1.1 200 OK']
usn = None
for k, v in i.items():
if k == 'USN':
usn = v
if k not in ('MANIFESTATION', 'SILENT', 'HOST'):
response.append('%s: %s' % (k, v))
if usn:
response.append('DATE: %s' % formatdate(timeval=None, localtime=False, usegmt=True))
response.extend(('', ''))
delay = random.randint(0, int(headers['mx']))
self.send_it('\r\n'.join(response), (host, port), delay, usn)
def do_notify(self, usn):
"""Do notification"""
if self.known[usn]['SILENT']:
return
logger.info('Sending alive notification for %s' % usn)
resp = [
'NOTIFY * HTTP/1.1',
'HOST: %s:%d' % (SSDP_ADDR, SSDP_PORT),
'NTS: ssdp:alive',
]
stcpy = dict(self.known[usn].items())
stcpy['NT'] = stcpy['ST']
del stcpy['ST']
del stcpy['MANIFESTATION']
del stcpy['SILENT']
del stcpy['HOST']
del stcpy['last-seen']
resp.extend(map(lambda x: ': '.join(x), stcpy.items()))
resp.extend(('', ''))
logger.debug('do_notify content', resp)
try:
self.sock.sendto('\r\n'.join(resp).encode(), (SSDP_ADDR, SSDP_PORT))
self.sock.sendto('\r\n'.join(resp).encode(), (SSDP_ADDR, SSDP_PORT))
except (AttributeError, socket.error) as msg:
logger.warning("failure sending out alive notification: %r" % msg)
def do_byebye(self, usn):
"""Do byebye"""
logger.info('Sending byebye notification for %s' % usn)
resp = [
'NOTIFY * HTTP/1.1',
'HOST: %s:%d' % (SSDP_ADDR, SSDP_PORT),
'NTS: ssdp:byebye',
]
try:
stcpy = dict(self.known[usn].items())
stcpy['NT'] = stcpy['ST']
del stcpy['ST']
del stcpy['MANIFESTATION']
del stcpy['SILENT']
del stcpy['HOST']
del stcpy['last-seen']
resp.extend(map(lambda x: ': '.join(x), stcpy.items()))
resp.extend(('', ''))
logger.debug('do_byebye content', resp)
if self.sock:
try:
self.sock.sendto('\r\n'.join(resp), (SSDP_ADDR, SSDP_PORT))
except (AttributeError, socket.error) as msg:
logger.error("failure sending out byebye notification: %r" % msg)
except KeyError as msg:
logger.error("error building byebye notification: %r" % msg)
一个实现 SSDP 服务器的类。 notify_received 和 searchReceived 方法在适当的类型时被调用 服务器收到数据报。
from http.server import BaseHTTPRequestHandler, HTTPServer
import threading
PORT_NUMBER = 8080
class UPNPHTTPServerHandler(BaseHTTPRequestHandler):
# Handler for the GET requests
def do_GET(self):
if self.path == '/boucherie_wsd.xml':
self.send_response(200)
self.send_header('Content-type', 'application/xml')
self.end_headers()
self.wfile.write(self.get_wsd_xml().encode())
return
if self.path == '/jambon-3000.xml':
self.send_response(200)
self.send_header('Content-type', 'application/xml')
self.end_headers()
self.wfile.write(self.get_device_xml().encode())
return
else:
self.send_response(404)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(b"Not found.")
return
def get_device_xml(self):
"""
Get the main device descriptor xml file.
"""
xml = """<root>
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<device>
<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>
<friendlyName>{friendly_name}</friendlyName>
<manufacturer>{manufacturer}</manufacturer>
<manufacturerURL>{manufacturer_url}</manufacturerURL>
<modelDescription>{model_description}</modelDescription>
<modelName>{model_name}</modelName>
<modelNumber>{model_number}</modelNumber>
<modelURL>{model_url}</modelURL>
<serialNumber>{serial_number}</serialNumber>
<UDN>uuid:{uuid}</UDN>
<serviceList>
<service>
<URLBase>http://xxx.yyy.zzz.aaaa:5000</URLBase>
<serviceType>urn:boucherie.example.com:service:Jambon:1</serviceType>
<serviceId>urn:boucherie.example.com:serviceId:Jambon</serviceId>
<controlURL>/jambon</controlURL>
<eventSubURL/>
<SCPDURL>/boucherie_wsd.xml</SCPDURL>
</service>
</serviceList>
<presentationURL>{presentation_url}</presentationURL>
</device>
</root>"""
return xml.format(friendly_name=self.server.friendly_name,
manufacturer=self.server.manufacturer,
manufacturer_url=self.server.manufacturer_url,
model_description=self.server.model_description,
model_name=self.server.model_name,
model_number=self.server.model_number,
model_url=self.server.model_url,
serial_number=self.server.serial_number,
uuid=self.server.uuid,
presentation_url=self.server.presentation_url)
@staticmethod
def get_wsd_xml():
"""
Get the device WSD file.
"""
return """<scpd xmlns="urn:schemas-upnp-org:service-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
</scpd>"""
class UPNPHTTPServerBase(HTTPServer):
"""
A simple HTTP server that knows the information about a UPnP device.
"""
def __init__(self, server_address, request_handler_class):
HTTPServer.__init__(self, server_address, request_handler_class)
self.port = None
self.friendly_name = None
self.manufacturer = None
self.manufacturer_url = None
self.model_description = None
self.model_name = None
self.model_url = None
self.serial_number = None
self.uuid = None
self.presentation_url = None
class UPNPHTTPServer(threading.Thread):
"""
A thread that runs UPNPHTTPServerBase.
"""
def __init__(self, port, friendly_name, manufacturer, manufacturer_url, model_description, model_name,
model_number, model_url, serial_number, uuid, presentation_url):
threading.Thread.__init__(self, daemon=True)
self.server = UPNPHTTPServerBase(('', port), UPNPHTTPServerHandler)
self.server.port = port
self.server.friendly_name = friendly_name
self.server.manufacturer = manufacturer
self.server.manufacturer_url = manufacturer_url
self.server.model_description = model_description
self.server.model_name = model_name
self.server.model_number = model_number
self.server.model_url = model_url
self.server.serial_number = serial_number
self.server.uuid = uuid
self.server.presentation_url = presentation_url
def run(self):
self.server.serve_forever()
为 UPnP XML 文件提供服务的 HTTP 处理程序。让我们使用 android 在网络上扫描 Pi。
private static final String tag = "SearchPi";
private static final String query = "M-SEARCH * HTTP/1.1\r\n" + "HOST: 239.255.255.250:1900\r\n" + "MAN: \"ssdp:discover\"\r\n" + "MX: 1\r\n" +
"ST: urn:schemas-upnp-org:device:MediaServer:1\r\n" +
//"ST: ssdp:all\r\n" +
"\r\n";
private static final int port = 1900;
现在让我们创建一个新的 asyncTask,因为它是网络相关的进程,并在 asyncTask 中添加以下代码
String response = "";
byte[] sendData;
byte[] receiveData = new byte[1024];
sendData = query.getBytes();
DatagramPacket sendPacket = null;
try {
sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("239.255.255.250"), port);
} catch (UnknownHostException e) {
Log.d(tag, "Unknown Host Exception Thrown after creating DatagramPacket to send to server");
e.printStackTrace();
}
DatagramSocket clientSocket = null;
try {
clientSocket = new DatagramSocket();
} catch (SocketException e) {
Log.d(tag, "Socket Exception thrown when creating socket to transport data");
e.printStackTrace();
}
try {
if (clientSocket != null) {
clientSocket.setSoTimeout(1000);
clientSocket.send(sendPacket);
}
} catch (IOException e) {
Log.d(tag, "IOException thrown when sending data to socket");
e.printStackTrace();
}
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
try {
if (clientSocket != null) {
clientSocket.receive(receivePacket);
}
} catch (IOException e) {
Log.d(tag, "IOException thrown when receiving data");
e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
response = new String(receivePacket.getData());
Log.d(tag, "Response contains: " + response);
if (response.contains("/jambon-3000.xml")) {
Log.d("logCat", receivePacket.getAddress().toString());
break;
}
else {
Log.d("logCat", "Popz! Pi not found");
}
}
使用上面的代码,您还可以在 Pi 上创建媒体服务器。
关于android - 使用 Android 在网络上搜索树莓派,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57957090/
我最近在/ drawable中添加了一些.gifs,以便可以将它们与按钮一起使用。这个工作正常(没有错误)。现在,当我重建/运行我的应用程序时,出现以下错误: Error: Gradle: Execu
Android 中有返回内部存储数据路径的方法吗? 我有 2 部 Android 智能手机(Samsung s2 和 s7 edge),我在其中安装了一个应用程序。我想使用位于这条路径中的 sqlit
这个问题在这里已经有了答案: What's the difference between "?android:" and "@android:" in an android layout xml f
我只想知道 android 开发手机、android 普通手机和 android root 手机之间的实际区别。 我们不能从实体店或除 android marketplace 以外的其他地方购买开发手
自Gradle更新以来,我正在努力使这个项目达到标准。这是一个团队项目,它使用的是android-apt插件。我已经进行了必要的语法更改(编译->实现和apt->注释处理器),但是编译器仍在告诉我存在
我是android和kotlin的新手,所以请原谅要解决的一个非常简单的问题! 我已经使用导航体系结构组件创建了一个基本应用程序,使用了底部的导航栏和三个导航选项。每个导航选项都指向一个专用片段,该片
我目前正在使用 Facebook official SDK for Android . 我现在正在使用高级示例应用程序,但我不知道如何让它获取应用程序墙/流/状态而不是登录的用户。 这可能吗?在那种情
我在下载文件时遇到问题, 我可以在模拟器中下载文件,但无法在手机上使用。我已经定义了上网和写入 SD 卡的权限。 我在服务器上有一个 doc 文件,如果用户单击下载。它下载文件。这在模拟器中工作正常但
这个问题在这里已经有了答案: What is the difference between gravity and layout_gravity in Android? (22 个答案) 关闭 9
任何人都可以告诉我什么是 android 缓存和应用程序缓存,因为当我们谈论缓存清理应用程序时,它的作用是,缓存清理概念是清理应用程序缓存还是像内存管理一样主存储、RAM、缓存是不同的并且据我所知,缓
假设应用程序 Foo 和 Eggs 在同一台 Android 设备上。任一应用程序都可以获取设备上所有应用程序的列表。一个应用程序是否有可能知道另一个应用程序是否已经运行以及运行了多长时间? 最佳答案
我有点困惑,我只看到了从 android 到 pc 或者从 android 到 pc 的例子。我需要制作一个从两部手机 (android) 连接的 android 应用程序进行视频聊天。我在想,我知道
用于使用 Android 以编程方式锁定屏幕。我从 Stackoverflow 之前关于此的问题中得到了一些好主意,并且我做得很好,但是当我运行该代码时,没有异常和错误。而且,屏幕没有锁定。请在这段代
文档说: android:layout_alignParentStart If true, makes the start edge of this view match the start edge
我不知道这两个属性和高度之间的区别。 以一个TextView为例,如果我将它的layout_width设置为wrap_content,并将它的width设置为50 dip,会发生什么情况? 最佳答案
这两个属性有什么关系?如果我有 android:noHistory="true",那么有 android:finishOnTaskLaunch="true" 有什么意义吗? 最佳答案 假设您的应用中有
我是新手,正在尝试理解以下 XML 代码: 查看 developer.android.com 上的文档,它说“starStyle”是 R.attr 中的常量, public static final
在下面的代码中,为什么当我设置时单选按钮的外观会发生变化 android:layout_width="fill_parent" 和 android:width="fill_parent" 我说的是
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 9
假设我有一个函数 fun myFunction(name:String, email:String){},当我调用这个函数时 myFunction('Ali', 'ali@test.com ') 如何
我是一名优秀的程序员,十分优秀!