在线程上使用阻塞套接字的UPnP事件订阅

2024-09-26 17:54:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在提拉订阅UPnP设备(WeMo运动传感器)上的事件。我首先向设备发送一个HTTP订阅请求,设备应该开始在指定地址向我发送事件通知。这个部分工作得很好(除了我收到了太多的通知;即使状态没有改变,但是对于不同的线程来说这是一个不同的问题)

如果我在一个单独的python进程上运行keepListening函数,那么一切正常。但是,当我将函数作为线程运行时,它不起作用

import socket
import requests
from threading import Thread

def keepListening(): #running this function on a separate process works
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.settimeout(600)
    sock.bind(('192.168.10.231',1234))
    sock.listen(5)

    while 1:
        notification = ''

    try:
        conn, addr =  sock.accept()
        conn.setblocking(1)
        notification= conn.recv(1024) 
        conn.sendall(r'''HTTP/1.1 200 OK
Content-Type: text/plain

''')
    except Exception as er:
        print er

    print notification




x = Thread(target=keepListening)
x.start()

message = {
'CALLBACK': '<http://192.168.10.231:1234>',
'NT': 'upnp:event',
'TIMEOUT': 'Second-600',
'HOST': '192.168.10.159:49153'}

k = requests.request('SUBSCRIBE','http://192.168.10.159:49153/upnp/event/basicevent1',headers=message)
print k
# keep doing other important works

每一个事件通知都必须回复200个OK回复,否则设备将不会再发送通知;这是我很难理解的事实。我有一个疑问,这可能很愚蠢,那就是,当在线程中运行时,与单独的进程相反,应答消息没有被及时发送,因此设备不再发送任何通知。 值得一提的是,即使我在线程中运行函数,我也确实会在订阅后得到初始通知(根据UPnP协议,设备必须在订阅后立即强制发送初始通知),但我没有收到进一步的通知(这表明我的200ok回复没有正常通过;不过,我在wireshark上看到了)

在线程中运行函数(与单独的进程相反)会导致函数失败,有什么不同吗?在

谢谢。在


Tags: 函数importhttp进程事件notificationsocketconn
2条回答

我假设,现在的情况是,在线程激活并开始监听接口之前,您发送了订阅请求。所以设备无法连接到插座。在

几天前,我得到了一个wemo运动传感器,开关和树莓,所以我开始修补。在

脚本订阅wemo设备的“binaryState”事件。 每次事件发生时,它都会打印出一个“警报”(你可以在那里做其他事情)。 250秒后,它将续订。在

要使脚本适应您的需要,您必须更改IP:

你的电脑

远程ip:wemo传感器或交换机的ip

我是python新手(3天前开始的),所以脚本可能需要一些修改,但它可以工作。在

import socket
import threading
import requests

host = ''
port = 1234
localIp = '<http://192.168.1.32:1234>' # local IP of your computer 
remoteIp = '192.168.1.47:49153' # the ip of the wemo device 

global uid # stores the uuid of the event
uid = ''

class client(threading.Thread):
    def __init__(self, conn):
        super(client, self).__init__()
        self.conn = conn
        self.data = ""

    def run(self):
        global uid
        while True:
            self.data = self.data + self.conn.recv(1024)

            if self.data.endswith(u"\r\n"):
                print self.data # data from the wemo device

                uidPos = self.data.find("uuid")
                if uidPos != -1: # data contains the uuid of the event 
                    uid = self.data[uidPos+5:uidPos+41]

                if "<BinaryState>1</BinaryState>" in self.data:
                    print "ALERT                      Alert"      
                    # NOTIFICATION ! 

                if "/e:propertyset" in self.data:
                    self.conn.sendall('HTTP/1.1 200 OK\r\nContent-Type:text/html\r\n\r\n')
                    return 
                self.data = ""

    def send_msg(self,msg):
        self.conn.send(msg)

    def close(self):
        self.conn.close()

class connectionThread(threading.Thread):
    def __init__(self, host, port):
        super(connectionThread, self).__init__()
        try:
            self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.s.bind((host,port))
            self.s.listen(5)

        except socket.error:
            print 'Failed to create socket'
            sys.exit()
        self.clients = []

    def run(self):
        while True:
            print uid
            conn, address = self.s.accept()
            c = client(conn) 
            c.start()
            print '[+] Client connected: {0}'.format(address[0])

def main():
    get_conns = connectionThread(host, port)
    get_conns.start()
    print get_conns.clients
    while True:
        try:
            response = raw_input() 
        except KeyboardInterrupt:
            sys.exit()

def setCalback():
  global uid
  threading.Timer(250.0, setCalback).start()
  if uid == "": # no uuid set so we subscribe to the event
    eventSubscribe()
  else:         # uuid is set, so we renew the subsciption
    eventRefresh()


def eventSubscribe(): # subscribe to the wemo-event 
    message = {
        'CALLBACK': localIp,
        'NT': 'upnp:event',
        'TIMEOUT': 'Second-300',
        'HOST': remoteIp} 
    k = requests.request('SUBSCRIBE', "http://"+remoteIp+'/upnp/event/basicevent1',headers=message)
    print k


def eventRefresh() # refresh the subscription with the known uuid
    myuid = "uuid:"+uid
    message = {
        'SID': myuid,
        'TIMEOUT': 'Second-300',
        'HOST': remoteIp } 
    k = requests.request('SUBSCRIBE',"http://"+remoteIp+'/upnp/event/basicevent1',headers=message)
    print k


if __name__ == '__main__':
    threading.Timer(2.0, setCalback).start() # wait 2 sec. then subscribe to the service
    main()

相关问题 更多 >

    热门问题