dynamically adding a resource to a python coap server with coapthon library - python

I am trying to build a coap server, in which I can add a new resource without the need to stop the server, recode it and restart .my server is suppossed to host two types of resources, "sensors(Sens-Me)" and "Actuators(Act-Me)" . I want that if I press the A key, a new instance of actuator should be added to the server, likewise If i Press S for Sensor .Below is my code :
from coapthon.resources.resource import Resource
from coapthon.server.coap import CoAP
class Sensor(Resource):
def __init__(self,name="Sensor",coap_server=None):
super(Sensor,self).__init__(name,coap_server,visible=True,observable=True,allow_children=True)
self.payload = "This is a new sensor"
self.resource_type = "rt1"
self.content_type = "application/json"
self.interface_type = "if1"
self.var = 0
def render_GET(self,request):
self.payload = "new sensor value ::{}".format(str(int(self.var+1)))
self.var +=1
return self
class Actuator(Resource):
def __init__(self,name="Actuator",coap_server=None):
super(Actuator,self).__init__(name,coap_server,visible=True,observable=True)
self.payload="This is an actuator"
self.resource_type="rt1"
def render_GET(self,request):
return self
class CoAPServer(CoAP):
def __init__(self, host, port, multicast=False):
CoAP.__init__(self,(host,port),multicast)
self.add_resource('sens-Me/',Sensor())
self.add_resource('act-Me/',Actuator())
print "CoAP server started on {}:{}".format(str(host),str(port))
print self.root.dump()
def main():
ip = "0.0.0.0"
port = 5683
multicast=False
server = CoAPServer(ip,port,multicast)
try:
server.listen(10)
print "executed after listen"
except KeyboardInterrupt:
server.close()
if __name__=="__main__":
main()

I am not sure what exactly do you want to do.
Is it just to replace a resource on the same route or add a new one?
Replace a resource
It is not possible according to the current coapthon version source:
https://github.com/Tanganelli/CoAPthon/blob/b6983fbf48399bc5687656be55ac5b9cce4f4718/coapthon/server/coap.py#L279
try:
res = self.root[actual_path]
except KeyError:
res = None
if res is None:
if len(paths) != i:
return False
resource.path = actual_path
self.root[actual_path] = resource
Alternatively, you can solve it in scope of request.
Say, have a registry of handlers which are used by resources and can be changed on a user input event. Well, you'll not be able to add new routes.
If you absolutely need that feature, you may request it from a developer or contribute to that project.
Add a new resource
I have extended your snippet a little bit.
I have a little experience in Python so I an not sure I've made everything properly, but it works.
There is a separate thread polling the user input and adding the same resource. Add the needed code there.
from coapthon.resources.resource import Resource
from coapthon.server.coap import CoAP
from threading import Thread
import sys
class Sensor(Resource):
def __init__(self,name="Sensor",coap_server=None):
super(Sensor,self).__init__(name,coap_server,visible=True,observable=True,allow_children=True)
self.payload = "This is a new sensor"
self.resource_type = "rt1"
self.content_type = "application/json"
self.interface_type = "if1"
self.var = 0
def render_GET(self,request):
self.payload = "new sensor value ::{}".format(str(int(self.var+1)))
self.var +=1
return self
class Actuator(Resource):
def __init__(self,name="Actuator",coap_server=None):
super(Actuator,self).__init__(name,coap_server,visible=True,observable=True)
self.payload="This is an actuator"
self.resource_type="rt1"
def render_GET(self,request):
return self
class CoAPServer(CoAP):
def __init__(self, host, port, multicast=False):
CoAP.__init__(self,(host,port),multicast)
self.add_resource('sens-Me/',Sensor())
self.add_resource('act-Me/',Actuator())
print "CoAP server started on {}:{}".format(str(host),str(port))
print self.root.dump()
def pollUserInput(server):
while 1:
user_input = raw_input("Some input please: ")
print user_input
server.add_resource('sens-Me2/', Sensor())
def main():
ip = "0.0.0.0"
port = 5683
multicast=False
server = CoAPServer(ip,port,multicast)
thread = Thread(target = pollUserInput, args=(server,))
thread.setDaemon(True)
thread.start()
try:
server.listen(10)
print "executed after listen"
except KeyboardInterrupt:
print server.root.dump()
server.close()
sys.exit()
if __name__=="__main__":
main()

Related

What is the difference in creating an instance of a class inside a thread loop versus outside

I have recently started working on threads and queues in Python. I have seen the following pattern for multi threading and queuing:
VALID_TARGETS = ['10.192.20.2','10.233.1.3', '10,235,0.3']
queue2 = Queue.Queue(maxsize=10)
for target in VALID_TARGETS:
queue2.put(target)
for i in range(100):
try:
valAuth_obj = ValAuth(queue2, user_id, pwd)
valAuth_obj.daemon = True
valAuth_obj.start()
except Exception, error:
print "ERROR"
break
queue2.join()
Where ValAuth is a class inheriting threading.Threads, whose run function is:
def run(self):
while True:
target = self.queue.get()
self.login(target)
self.queue.task_done()
The program is running as expected. But i have noticed we are calling the class valAuth for every thread i want to run. Then i tried the following, where i pulled out the valAuth() outside the loop.
VALID_TARGETS = ['10.192.20.2','10.233.1.3', '10,235,0.3']
queue2 = Queue.Queue(maxsize=10)
valAuth_obj = ValAuth(queue2, user_id, pwd)
for target in VALID_TARGETS:
queue2.put(target)
for i in range(100):
try:
valAuth_obj.daemon = True
valAuth_obj.start()
except Exception, error:
print "ERROR"
break
queue2.join()
The program still gives me the same result but I can notice there is some difference in terms of speed. Can someone please explain what is the difference in terms of background operations and which one should we stick to?
CODE for valAuth class
class valAuth(threading.Thread):
""" Authenticate all targeted SCM build machines """
def __init__(self, queue, user_id, password):
threading.Thread.__init__(self)
self.queue = queue
self.user = user
self.password = password
def run(self):
while True:
target = self.queue.get()
self.auth(target)
self.queue.task_done()
def auth(self, target):
""" Check all SCM build machines are active with login authentication and
also checks if the account is not AD locked.
"""
print "P1: " + self.user + " target: "+ target
# Company's Authentication Protocol base code ... (cannot show ! SORRY !)
print "P1: " + self.user + " target: "+ target + " Run complete"
Thanks in advance.

Python Multiprocessing Manager - Client unable to reconnect

I am running an application which cannot sit and wait the successful/unsuccessful connection to a Python Manager. The client application should try to send some info to the supposedly running server, and in case it fails, another measure is taken. The problem is that whenever the server is down the connection takes a lot of time to return the control to the client application, and it cannot waste time waiting for it because there is other stuff to do.
I came up with a scheme where an intermediary object is in charge of the connection but it only works once. Let's say that for the first time, when there is still no connection to the server, this intermediary object handles the connecting part without blocking the client application. If, for some reason, the server goes down and comes back again, I can't get it to work anymore.
Suppose I have the following server:
# server.py
from multiprocessing import Queue, managers
from multiprocessing.queues import Empty
import select
import threading
class RServer(object):
def __init__(self, items_buffer):
self.items_buffer = items_buffer
def receive_items(self):
while True:
(_, [], []) = select.select([self.items_buffer._reader], [], [])
while True:
try:
item = self.items_buffer.get(block=False)
# do something with item
print('item received')
except Empty:
break
class SharedObjectsManager(managers.BaseManager):
pass
if __name__ == '__main__':
items_buffer = Queue()
remote_server = RServer(items_buffer)
remote_server_th = threading.Thread(target=remote_server.receive_items)
remote_server_th.start()
SharedObjectsManager.register('items_buffer', callable=lambda: items_buffer)
shared_objects_manager = SharedObjectsManager(address=('localhost', 5001),
authkey=str.encode('my_server'),
serializer='xmlrpclib')
s = shared_objects_manager.get_server()
s.serve_forever()
And here is the intermediary object to handle the connection:
# bridge.py
from multiprocessing.managers import BaseManager
import threading
import socket
class ConnectionManager():
def __init__(self):
self.remote_manager = BaseManager(address=('localhost', 5001),
authkey=b'my_server',
serializer='xmlrpclib')
self.remote_manager.register('items_buffer')
self.items_buffer = None
self.items_buffer_lock = threading.Lock()
self.connecting = False
self.connecting_lock = threading.Lock()
self.connection_started_condition = threading.Condition()
def transmit_item(self, item):
try:
with self.items_buffer_lock:
self.items_buffer.put(item)
except (AttributeError, EOFError, IOError):
with self.connection_started_condition:
with self.connecting_lock:
if not self.connecting:
self.connecting = True
connect_th = threading.Thread(target=self.connect_to_server,
name='Client Connect')
connect_th.start()
self.connection_started_condition.notify()
raise ConnectionError('Connection Error')
def connect_to_server(self):
with self.connection_started_condition:
self.connection_started_condition.wait()
try:
self.remote_manager.connect()
except socket.error:
pass
else:
try:
with self.items_buffer_lock:
self.items_buffer = self.remote_manager.items_buffer()
except (AssertionError, socket.error):
pass
with self.connecting_lock:
self.connecting = False
class ConnectionError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
And finally the client application:
# client.py
import time
from bridge import ConnectionManager, ConnectionError
remote_buffer = ConnectionManager()
while True:
try:
remote_buffer.transmit_item({'rubish': None})
print('item sent')
except ConnectionError:
# do something else
print('item not sent')
# do other stuff
print('doing other stuff')
time.sleep(15)
I am for sure doing something wrong with the thread but I can't figure it out. Any idea?

Can pyzmq publishers be operated from class instances?

I have following code for a Publisher, which instantiates a few class instances and publishes some messages.
However, I don't receive anything at Subscriber side.
Publisher
import zmq
import time
from multiprocessing import Process
class SendData:
def __init__(self, msg, port):
self.msg = msg
self.port = port
ctx = zmq.Context()
self.sock = ctx.socket(zmq.PUB)
self.sock.bind('tcp://127.0.0.1:'+str(self.port))
time.sleep(1)
def sender(self):
self.sock.send_json(self.msg)
def main():
for device, port in zip(['2.2.2.2', '5.5.5.5'],[5001, 5002]):
msg = {device:'Some random message'}
instance = SendData(device, port)
Process(target=instance.sender).start()
if __name__ == "__main__":
main()
Subscriber
import zmq
ctx = zmq.Context()
recv_sock1 = ctx.socket(zmq.SUB)
recv_sock1.connect('tcp://127.0.0.1:5001')
recv_sock1.setsockopt(zmq.SUBSCRIBE, '')
recv_sock2 = ctx.socket(zmq.SUB)
recv_sock2.connect('tcp://127.0.0.1:5002')
recv_sock2.setsockopt(zmq.SUBSCRIBE, '')
while True:
if recv_sock1.poll(10):
msg = recv_sock1.recv_json()
print msg
if recv_sock2.poll(10):
msg = recv_sock2.recv_json()
print msg
I had subscribers started before publishers could publish anything. Also, I can see TCP connections are in Established so connections are made.
pyzmq version 16.0.0
python version 2.7
Q1: Are 0mq publishers supported from class instances?
Q2: What am I missing?
As was said before, trying to share the ZeroMQ context between processes is the problem here and the solution by user3666197 will work.
However, I would suggest subclassing multiprocessing.Process in this case. That way, it is much clearer what part of the code is executed in which process. It also makes your code more readable and reusable.
The following code creates one sender process per device. The sender processes can be reused during the runtime of your program to send more data:
import multiprocessing
import queue
import zmq
import time
class Sender(multiprocessing.Process):
def __init__(self, port):
super(Sender, self).__init__()
self._port = port
self._messages = multiprocessing.Queue()
self._do_stop = multiprocesing.Event()
def run(self):
"""
This code is executed in a new process.
"""
ctx = zmq.Context()
sock = ctx.socket(zmq.PUB)
sock.bind("tcp://127.0.0.1:" + str(self._port))
while not self._do_stop.is_set():
try:
msg = self._message.get_nowait()
sock.send_json(msg)
except queue.Empty:
time.sleep(0.01)
def stop(self):
self._do_stop.set()
def send_message(self, msg):
self._messages.put(msg)
def main():
data = zip(['2.2.2.2', '5.5.5.5'], [5001, 5002])
# create senders
senders = {device: Sender(port) for device, port in data}
# start senders
for device in senders:
senders[device].start()
# send messages
for device, port in zip(['2.2.2.2', '5.5.5.5'],[5001, 5002]):
msg = {device: 'Some random message'}
senders[device].send_message(msg)
# do more stuff here....
# ... e.g. send more messages
# ...
# once you are finished, stop the subprocesses
for device in senders:
senders[device].stop()
I hope this helps solving your problem.
A1: Yes, they are.
A2: Conflicts of scope-of-use v/s Zero-sharing, one of ZeroMQ maxims
Once your original Publisher code is being executed in main(), the class instantiation process creates ( i.e. inside the main()-process scope-of-use ), via the .__init__() constructor-method, it's own Context() -instance, which thus belongs ( incl. all of it's derived child-objects ( sockets et al ) ) to this main()-process.
Next, the call to the Process(...) initiates another few processes, that receive the class-instances ( the pity is that these have already created ZeroMQ non-shareable toys ) from the main()-scope-of-use.
Solution?
A possible dirty quick hack could be to defer the ZeroMQ Context() instantiation -- yes, just move it from .__init__() to some .aDeferredSETUP() that will be executed specifically under different scope-of-use inside each of the spinned-of Process()-process, different from main()-process and you ought be done, as Zero-sharing is safely obeyed.
class SendData:
def __init__(self, msg, port):
self.msg = msg
self.port = port
self.NotSETUP = True
self.ctx = None
self.sock = None
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ L8R
# ctx = zmq.Context()
# self.sock = ctx.socket( zmq.PUB )
# self.sock.bind( 'tcp://127.0.0.1:' + str( self.port ) )
# time.sleep( 1 )
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ L8R
def sender( self ):
if self.NotSETUP:
self.aDeferredSETUP()
self.sock.send_json( self.msg )
def aDeferredSETUP( self ): # create I/O-threads in Process(), not main()
self.ctx = zmq.Context()
self.sock = self.ctx.socket( zmq.PUB )
self.sock.bind( 'tcp://127.0.0.1:' + str( self.port ) )
time.sleep( 1 )

too many file descriptors in select() python in windows

i am trying to receive about 1000 connections to my server but it cannot receive more than 512. What can i do to increase the amount of open connections? I am running windows 8.1
Not: I am very new to this stuff so, thanks for help
Here is my code;
import asyncore
import socket
import uuid
import time
import threading
class statistics(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
while True:
entry = raw_input("")
zaman = int(time.time())
cmd = receivedCmd
print "calculating.."
time.sleep(1)
if entry == 'istatistik':
print str(receivedCmd-cmd) + " command/second"
print "total received commands: " + str(receivedCmd)
entry = ""
class tcpClient:
def __init__(self):
self.clientid = uuid.uuid1(int(time.time()))
self.buffer = ""
self.buffer_size = 0
self.conn_time = time.time()
self.overflow = 0
#print str(self.clientid) + " assingned"
def recv_msg(self, msg):
global receivedCmd
self.buffer = msg
self.buffer_size = len(self.buffer)
receivedCmd = receivedCmd + 1
if self.buffer_size >= 1024:
self.overflow = 1
def __del__(self):
print str(self.clientid) + " has left."
class TCPHandler(asyncore.dispatcher_with_send):
global clist
def handle_read(self):
data = self.recv(1024)
if data:
if clist[self].overflow:
self.send("overflow")
self.handle_close()
else:
self.send(data)
clist[self].recv_msg(data)
def handle_close(self):
del clist[self]
self.close()
def handle_error(self):
del clist[self]
self.close()
class TCPServer(asyncore.dispatcher):
global clist
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind((host, port))
self.listen(5)
def handle_accept(self):
self.clist = clist
pair = self.accept()
if pair is None:
pass
else:
sock, addr = pair
#print 'Connection : %s' % repr(addr)
clist[TCPHandler(sock)] = tcpClient()
if __name__ == '__main__':
clist = {}
receivedCmd = 0
server = TCPServer('', 5000)
server2 = TCPServer('',5001)
StaticsThread = statistics()
StaticsThread.start()
asyncore.loop()
Note: I still cannot receive more than 512 connections with the Twisted Framework, i don't know what to do. There have to be thousands of connected clients. Please help.
The asyncore module relies in the select OS function, which only supports a limited number of file descriptors.
As an alternative use a multi-threading server (I won't recommend this) or, better, the Twisted framework which is event-driven (highly recommended!).
Hope this helps!
Since Twisted's default reactor under Windows is also select-based then you should consider using the IOCP reactor instead.
from twisted.internet import iocpreactor
iocpreactor.install()
from twisted.internet import reactor
But also take into account that Twisted prefers Linux systems (where the default reactor is epoll-based) rather than Windows. Maybe switching to Linux is a better choice.

SocketServer Python with multiple requests

i'm coding a Python Server (with SocketServer) for my Raspberry Pi.
This server wait for incoming clients and activate any components like Relay and leds from that remote connection.
This is my first project so i'm having some trouble:
in my main i create the object and i send the arraylist of the components i want to control; like led with all his own functions
Server.Server(ComponentList)
while True:
do stuff
in Server.py i launch the server and set some settings
class Server():
def __init__(self, ComponentList):
self.ComponentList = ComponentList
self.current_component = 0
self.server = Socket.ThreadedTCPServer((settings.HOSTNAME,settings.PORT), Socket.ThreadedTCPRequestHandler)
self.server_thread = threading.Thread(target=self.server.serve_forever)
self.server_thread.daemon = True
self.server_thread.start()
self.server.set_componentlist(self.ComponentList)
self.server.set_current_component(self.current_component)
def set_current_component(self, current_component):
self.current_component = current_component
def get_current_component(self):
return self.current_component
def set_componentlist(self, ComponentList):
self.ComponentList = ComponentList
def get_componentlist(self):
return self.ComponentList
finally in Socket.py i coded the real server where are spawning the bugs
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
def handle(self):
print "Client connected with ", self.client_address
self.request.send("Insert Password\r\n")
if self.request.recv(1024).strip() == settings.PASSWORD:
time.sleep(1)
self.request.send("Correct password\r\n")
try:
while 1:
data = None
self.request.send("---------------------\r\n")
self.request.send("Listening for commands\r\n")
self.request.send("1: Connected devices\r\n")
self.request.send("2: Select devices\r\n")
self.request.send("0: Close connection\r\n")
self.request.send("---------------------\r\n")
data = self.request.recv(1024).strip()
if data is not None:
if data == "1":
self.request.send(str(len(self.server.get_componentlist()))+" Components loaded\r\n")
c=0
for i in self.server.get_componentlist():
self.request.send(str(str(c)+": "+i.get_note()+"\r\n"))
c=c+1
if data == "2":
data = self.request.recv(1024).strip()
self.request.send("Select component id\r\n")
self.server.set_current_component(data)
self.request.send("Selected component: "+data+"\r\n")
if data == "0":
break
finally:
self.request.close()
print "Client exited"
else:
time.sleep(1)
self.request.send("Incorrect password\r\n")
self.request.send("Bye\r\n")
self.request.close()
print "Client unauthorized"
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
allow_reuse_address = True
def set_componentlist(self, ComponentList):
self.ComponentList = ComponentList
def get_componentlist(self):
return self.ComponentList
def set_current_component(self, current_component):
self.current_component = current_component
def get_current_component(self):
return self.current_component
in the loop while, after the password request, i can get the first choice (1,2 or 0) but i can't choose the device, and i can get another value from request.recv(1024).
if data == "2":
data = self.request.recv(1024).strip()
self.request.send("Select component id\r\n")
self.server.set_current_component(data)
self.request.send("Selected component: "+data+"\r\n")
the program skip the data = self.request... keeping data empty
and print the output twice.
i guess i'm missing something and i cannot sending multiple information to the server with one connection.
Thanks

Categories