將android攝像頭視訊釋出到公網
阿新 • • 發佈:2018-12-11
想用舊android手機作為監控,拍攝家裡的視訊。
1.首先需要 ip攝像頭 這款軟體。這款安卓軟體本身是在區域網中使用的,可以把手機變為攝像頭,也可以播放器他變為攝像頭的手機,他本身是啟動了web伺服器和流媒體伺服器,用來等待其他手機來連結攝像頭。
2.然後需要Qpython,這是在安卓手機上執行python指令碼的app,用他來執行python-ngrok指令碼,將開啟攝像頭本身手機的8081埠,也就是ip攝像頭開啟web應用的埠,對映到ngrok的一個子域名下,這樣可以在外網訪問ngrok,在方位到攝像頭主機的8081埠。
3.python-ngrok是一個Qpthon內網穿透指令碼,現在用於將本級的8081埠,對映到ngrok的一個子域名下。
工具上傳了
使用方法就是,先啟用Qpython,執行python-ngrok.py指令碼,在開啟IP攝像頭,點選 把手機變為攝像頭 ,在用另外一個手機,安卓ip攝像頭,新增一個url,這個url就是ngrok給我們分配的子域名。
其中python-ngrok.py內容如下
#!/usr/bin/env python # -*- coding: UTF-8 -*- # 建議Python 2.7.9 或 Python 3.4.2 以上執行 # 專案地址: https://github.com/hauntek/python-ngrok # Version: v1.46 import socket import ssl import json import struct import random import sys import time import logging import threading host = 'tunnel.qydev.com' # Ngrok伺服器地址 port = 4443 # 埠 bufsize = 1024 # 吞吐量 Tunnels = list() # 全域性渠道賦值 #這個怎樣用,還不知道 #body = dict() #body['protocol'] = 'http' #body['hostname'] = 'jingchudne' #body['subdomain'] = '' #body['rport'] = 0 #body['lhost'] = '127.0.0.1' #body['lport'] = 80 #Tunnels.append(body) # 加入渠道佇列 #這裡是http端頭對映,意思就是,在ngrok下,建立一個jingchunde的子域,訪問這個子域,就能得到本級8081的埠內容。 body = dict() body['protocol'] = 'http' body['hostname'] = '' body['subdomain'] = 'jingchunde' body['rport'] = 0 body['lhost'] = '127.0.0.1' body['lport'] = 8081 Tunnels.append(body) # 加入渠道佇列 #這裡是tcp埠對映 #body = dict() #body['protocol'] = 'tcp' #body['hostname'] = '' #body['subdomain'] = '' #body['rport'] = 55499 #body['lhost'] = '127.0.0.1' #body['lport'] = 22 #Tunnels.append(body) # 加入渠道佇列 # 讀取配置檔案 if len(sys.argv) >= 2: file_object = open(sys.argv[1]) try: all_the_text = file_object.read() config_object = json.loads(all_the_text) host = config_object["server"]["host"] # Ngrok伺服器地址 port = int(config_object["server"]["port"]) # 埠 bufsize = int(config_object["server"]["bufsize"]) # 吞吐量 Tunnels = list() # 重置渠道賦值 for Tunnel in config_object["client"]: body = dict() body['protocol'] = Tunnel["protocol"] body['hostname'] = Tunnel["hostname"] body['subdomain'] = Tunnel["subdomain"] body['rport'] = int(Tunnel["rport"]) body['lhost'] = Tunnel["lhost"] body['lport'] = int(Tunnel["lport"]) Tunnels.append(body) # 加入渠道佇列 del all_the_text del config_object except Exception: # logger = logging.getLogger('%s' % 'config') # logger.error('The configuration file read failed') # exit(1) pass finally: file_object.close() mainsocket = 0 ClientId = '' pingtime = 0 def getloacladdr(Tunnels, Url): protocol = Url[0:Url.find(':')] hostname = Url[Url.find('//') + 2:] subdomain = hostname[0:hostname.find('.')] rport = Url[Url.rfind(':') + 1:] for tunnelinfo in Tunnels: if tunnelinfo.get('protocol') == protocol: if tunnelinfo.get('protocol') in ['http', 'https']: if tunnelinfo.get('hostname') == hostname: return tunnelinfo if tunnelinfo.get('subdomain') == subdomain: return tunnelinfo if tunnelinfo.get('protocol') == 'tcp': if tunnelinfo.get('rport') == int(rport): return tunnelinfo return dict() def dnsopen(host): try: ip = socket.gethostbyname(host) except socket.error: return False return ip def connectremote(host, port): try: host = socket.gethostbyname(host) client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ssl_client = ssl.wrap_socket(client, ssl_version=ssl.PROTOCOL_SSLv23) ssl_client.connect((host, port)) ssl_client.setblocking(1) logger = logging.getLogger('%s:%d' % ('Conn', ssl_client.fileno())) logger.debug('New connection to: %s:%d' % (host, port)) except socket.error: return False return ssl_client def connectlocal(localhost, localport): try: localhost = socket.gethostbyname(localhost) client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((localhost, localport)) client.setblocking(1) logger = logging.getLogger('%s:%d' % ('Conn', client.fileno())) logger.debug('New connection to: %s:%d' % (localhost, localport)) except socket.error: return False return client def NgrokAuth(): Payload = dict() Payload['ClientId'] = '' Payload['OS'] = 'darwin' Payload['Arch'] = 'amd64' Payload['Version'] = '2' Payload['MmVersion'] = '1.7' Payload['User'] = 'user' Payload['Password'] = '' body = dict() body['Type'] = 'Auth' body['Payload'] = Payload buffer = json.dumps(body) return(buffer) def ReqTunnel(Protocol, Hostname, Subdomain, RemotePort): Payload = dict() Payload['ReqId'] = getRandChar(8) Payload['Protocol'] = Protocol Payload['Hostname'] = Hostname Payload['Subdomain'] = Subdomain Payload['HttpAuth'] = '' Payload['RemotePort'] = RemotePort body = dict() body['Type'] = 'ReqTunnel' body['Payload'] = Payload buffer = json.dumps(body) return(buffer) def RegProxy(ClientId): Payload = dict() Payload['ClientId'] = ClientId body = dict() body['Type'] = 'RegProxy' body['Payload'] = Payload buffer = json.dumps(body) return(buffer) def Ping(): Payload = dict() body = dict() body['Type'] = 'Ping' body['Payload'] = Payload buffer = json.dumps(body) return(buffer) def lentobyte(len): return struct.pack('<LL', len, 0) def sendbuf(sock, buf, isblock = False): if isblock: sock.setblocking(1) sock.sendall(buf) if isblock: sock.setblocking(0) def sendpack(sock, msg, isblock = False): if isblock: sock.setblocking(1) sock.sendall(lentobyte(len(msg)) + msg.encode('utf-8')) logger = logging.getLogger('%s:%d' % ('Send', sock.fileno())) logger.debug('Writing message: %s' % msg) if isblock: sock.setblocking(0) def tolen(v): if len(v) == 8: return struct.unpack('<II', v)[0] return 0 def getRandChar(length): _chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz" return ''.join(random.sample(_chars, length)) # 客戶端程式處理過程 def HKClient(sock, linkstate, type, tosock = None): global mainsocket global ClientId global pingtime recvbuf = bytes() while True: try: if linkstate == 0: if type == 1: sendpack(sock, NgrokAuth(), False) linkstate = 1 if type == 2: sendpack(sock, RegProxy(ClientId), False) linkstate = 1 if type == 3: linkstate = 1 recvbut = sock.recv(bufsize) if not recvbut: break if len(recvbut) > 0: if not recvbuf: recvbuf = recvbut else: recvbuf += recvbut if type == 1 or (type == 2 and linkstate == 1): lenbyte = tolen(recvbuf[0:8]) if len(recvbuf) >= (8 + lenbyte): buf = recvbuf[8:lenbyte + 8].decode('utf-8') logger = logging.getLogger('%s:%d' % ('Recv', sock.fileno())) logger.debug('Reading message with length: %d' % len(buf)) logger.debug('Read message: %s' % buf) js = json.loads(buf) if type == 1: if js['Type'] == 'ReqProxy': newsock = connectremote(host, port) if newsock: thread = threading.Thread(target = HKClient, args = (newsock, 0, 2)) thread.setDaemon(True) thread.start() if js['Type'] == 'AuthResp': ClientId = js['Payload']['ClientId'] logger = logging.getLogger('%s' % 'client') logger.info('Authenticated with server, client id: %s' % ClientId) sendpack(sock, Ping()) pingtime = time.time() for tunnelinfo in Tunnels: # 註冊通道 sendpack(sock, ReqTunnel(tunnelinfo['protocol'], tunnelinfo['hostname'], tunnelinfo['subdomain'], tunnelinfo['rport'])) if js['Type'] == 'NewTunnel': if js['Payload']['Error'] != '': logger = logging.getLogger('%s' % 'client') logger.error('Server failed to allocate tunnel: %s' % js['Payload']['Error']) time.sleep(30) else: logger = logging.getLogger('%s' % 'client') logger.info('Tunnel established at %s' % js['Payload']['Url']) if type == 2: if js['Type'] == 'StartProxy': loacladdr = getloacladdr(Tunnels, js['Payload']['Url']) newsock = connectlocal(loacladdr['lhost'], loacladdr['lport']) if newsock: thread = threading.Thread(target = HKClient, args = (newsock, 0, 3, sock)) thread.setDaemon(True) thread.start() tosock = newsock linkstate = 2 else: body = '<html><body style="background-color: #97a8b9"><div style="margin:auto; width:400px;padding: 20px 60px; background-color: #D3D3D3; border: 5px solid maroon;"><h2>Tunnel %s unavailable</h2><p>Unable to initiate connection to <strong>%s</strong>. This port is not yet available for web server.</p>' html = body % (js['Payload']['Url'], loacladdr['lhost'] + ':' + str(loacladdr['lport'])) header = "HTTP/1.0 502 Bad Gateway" + "\r\n" header += "Content-Type: text/html" + "\r\n" header += "Content-Length: %d" + "\r\n" header += "\r\n" + "%s" buf = header % (len(html.encode('utf-8')), html) sendbuf(sock, buf.encode('utf-8')) if len(recvbuf) == (8 + lenbyte): recvbuf = bytes() else: recvbuf = recvbuf[8 + lenbyte:] if type == 3 or (type == 2 and linkstate == 2): sendbuf(tosock, recvbuf) recvbuf = bytes() except socket.error: break if type == 1: mainsocket = False if type == 3: try: tosock.shutdown(socket.SHUT_WR) except socket.error: tosock.close() logger = logging.getLogger('%s:%d' % ('Close', sock.fileno())) logger.debug('Closing') sock.close() # 客戶端程式初始化 if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG, format='[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s', datefmt='%Y/%m/%d %H:%M:%S') logger = logging.getLogger('%s' % 'client') logger.info('python-ngrok v1.46') while True: try: # 檢測控制連線是否連線. if mainsocket == False: ip = dnsopen(host) if ip == False: logger = logging.getLogger('%s' % 'client') logger.info('update dns') time.sleep(10) continue mainsocket = connectremote(ip, port) if mainsocket == False: logger = logging.getLogger('%s' % 'client') logger.info('connect failed...!') time.sleep(10) continue thread = threading.Thread(target = HKClient, args = (mainsocket, 0, 1)) thread.setDaemon(True) thread.start() # 傳送心跳 if pingtime + 20 < time.time() and pingtime != 0: sendpack(mainsocket, Ping()) pingtime = time.time() time.sleep(1) except socket.error: pingtime = 0 except KeyboardInterrupt: sys.exit()
一會把測試視訊傳上來