Связанный вопрос без ответов Использование DatagramSocket и python сокета с устройствами, подключенными к точке доступа
Моя цель реализовать что-то вроде syncthing , чтобы я мог передавать файлы через мои устройства в локальной сети. (Это двунаправленный, т.е. Android до P C, P C до Android, P C до P C, Android до Android).
(My setup - это ноутбук и устройство Android 10, которое я использую в качестве точки доступа для доступа к inte rnet в моем ноутбуке)
Я пытался реализовать обнаружение сетевых устройств с помощью jmdns
, Jmdns смог обнаружить локальные сервисы, только когда оба устройства были подключены к одному и тому же WIFI, но он не работал на устройстве Android при использовании его в качестве точки доступа.
Я наконец смог заставить его работать используя Android NSD , и он смог обнаружить мой p c при использовании в качестве точки доступа. Там, где я запускаю простой скрипт zeroconf python, объявляющий сервер с использованием назначенного ОС порта.
pip install zeroconf==0.25.0 ifaddr==0.1.6
Код сервера
Следующий код разрешит P C к P C передача сообщений, чтобы можно было загрузить файл. Это также позволяет Android NSD обнаруживать это устройство.
import random
from contextlib import closing
from socket import *
from threading import Thread
from typing import List
import ifaddr
from zeroconf import (ServiceBrowser, ServiceInfo, ServiceListener, Zeroconf,
ZeroconfServiceTypes)
class MyListener:
def remove_service(self, zeroconf, type, name):
print("Service {} of type {} removed".format(name, type))
def add_service(self, zeroconf, type, name):
info = zeroconf.get_service_info(type, name)
print("Service %s added, service info: %s" % (name, info))
# https://stackoverflow.com/a/51596612/8608146
print("Address", inet_ntoa(info.address), info.port)
Thread(target=client_handler, args=(info,)).start()
def client_handler(info: ServiceInfo):
with closing(socket(AF_INET, SOCK_DGRAM)) as s:
print(info.address, info.port)
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
s.bind(('', info.port))
while True:
print("Waiting..", s.getsockname())
m = s.recvfrom(1024)
print(m)
# https://stackoverflow.com/a/45690594/8608146
def find_free_port():
with closing(socket(AF_INET, SOCK_STREAM)) as s:
s.bind(('', 0))
s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
return s.getsockname()[1]
# https://github.com/p-sanches/somabits/blob/d581abaab6f045d65a774a78fbb43e232cf6f8da/somoserver/SomoServer/ZeroConf.py#L42
def get_all_addresses() -> List[str]:
return list(set(
addr.ip
for iface in ifaddr.get_adapters()
for addr in iface.ips
# Host only netmask 255.255.255.255
if addr.is_IPv4 and addr.network_prefix != 32
))
def get_local_ip(starts_with="192"):
list_ip = get_all_addresses()
local_ip = [i for i in list_ip if i.startswith(starts_with)]
return local_ip[0]
print(get_all_addresses())
print(get_local_ip())
print(gethostname())
print(gethostbyname(gethostname()))
zeroconf = Zeroconf()
send_port = find_free_port()
local_ip = get_local_ip()
# assign a random name to this service
name = "pc-" + str(random.randint(0, 100))
# register a service
zeroconf.register_service(ServiceInfo(
"_coolapp._udp.local.",
"{}._coolapp._udp.local.".format(name),
inet_aton(local_ip), send_port, 0, 0,
# this is the txt record
properties={"data": "device"}
))
listener = MyListener()
browser = ServiceBrowser(zeroconf, "_coolapp._udp.local.", listener)
try:
std_response = ''
s = socket(AF_INET, SOCK_DGRAM)
s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
while std_response != 'q':
std_response = input("Press q to exit...\n\n")
# print(x)
s.sendto(std_response.encode('utf8'), ('255.255.255.255', send_port))
finally:
zeroconf.close()
И я реализовал передачу сообщений Android до Android в приложение, и оно работает, когда оба устройства подключены к одной сети ( даже одна из них является горячей точкой).
Теперь я пытаюсь получить доступ к своему Android IP-адресу устройства с сервера python и моему ноутбуку из приложения Android.
Экземпляр соединения zeroconf имеет поля host
, т. Е. IP-адрес P C и port
на стороне Android. И address
и port
на стороне сервера python.
Поэтому я открываю сокет по адресу host:port
(P C или хост и порт другого Android устройства) в приложении Android я открываю сокет на IP-адресе соединения zeroconf, полученного от приложения Android или другого address:port
P C на сервере python. И попробуйте выполнить чтение / запись в сокет со стороны Android.
, которая работает ТОЛЬКО для Android до Android и от P C до P C передачи сообщений. Но от p c до Android оба отказываются подключаться. (Напоминаю, что я использую подключение к точке доступа моего устройства Android)
Код Android находится в этом репозитории github .
Часть сокета код
// NSD stuff gives address and port
...
//
// to receive messages from other devices
private inner class ReceivingThread : Runnable {
override fun run() {
...
val s = Socket(address, port)
// The error is here in the next line
// which is simply a timeout Exception
val inputStream = BufferedInputStream(s.getInputStream())
try {
while (!Thread.currentThread().isInterrupted && !s.isClosed) {
...
Log.d(TAG, "[Client RT] receive: $message")
}
} catch (e: Exception) {
Log.d(TAG, "[Client RT] run: something went wrong ${this@Client}", e)
}
}
}
private inner class SendingThread(private val message: String) : Runnable {
override fun run() {
val s = socket ?: return
val outputStream = BufferedOutputStream(s.getOutputStream() ?: return)
Log.d(TAG, "run: outputStream = $outputStream")
try {
outputStream.write(message)
outputStream.flush()
...
Log.d(TAG, "[Client ST] send: $message")
} catch (e: Exception) {
Log.d(TAG, "[Client ST] run: something went wrong $this", e)
}
}
}
Моя ошибка при отправке чего-либо из приложения Android на сервер:
java.net.ConnectException: failed to connect to /192.168.56.1 (port 51914) from /:: (port 39748): connect failed: ETIMEDOUT (Connection timed out)
При попытке подключиться к клиенту на сервере это
Traceback (most recent call last):
File "C:\Users\Rithvij\AppData\Local\Programs\Python\Python38\lib\threading.py", line 932, in _bootstrap_inner
self.run()
File "C:\Users\Rithvij\AppData\Local\Programs\Python\Python38\lib\threading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "ano.py", line 65, in client_handler
s.bind((inet_ntoa(info.address), info.port))
OSError: [WinError 10049] The requested address is not valid in its context
На моем P C
λ ipconfig.exe | grep IPv4
IPv4 Address. . . . . . . . . . . : 192.168.56.1
IPv4 Address. . . . . . . . . . . : 192.168.99.1
IPv4 Address. . . . . . . . . . . : 192.168.43.159
IPv4 Address. . . . . . . . . . . : 192.168.137.1
на моем Android устройстве (Termux)
$ ifconfig | grep inet
Warning: cannot open /proc/net/dev (Permission denied). Limited output.
inet 127.0.0.1 netmask 255.0.0.0
inet 10.83.151.210 netmask 255.255.255.252
inet 25.135.14.145 netmask 255.255.255.252
inet 192.168.43.1 netmask 255.255.255.0 broadcast 192.168.43.255
IP-адрес либо недоступен, либо нет знать что-нибудь.