Monitoring PUB/SUB pattren in ZeroMQ in python - python

I am using a PUB/SUB patteren.
I need to monitor this.
I got following code for monitor REP/REP patteren, I want something like this for PUB/SUB..
when I am changing PUB/SUB in this but then this code is not working.
Please let me know if how monitoring is possible for PUB/SUB
import time
import zmq
from zmq.devices.basedevice import ProcessDevice
from zmq.devices.monitoredqueuedevice import MonitoredQueue
from zmq.utils.strtypes import asbytes
from multiprocessing import Process
import random
frontend_port = 8888
backend_port = 8882
monitor_port = 5562
number_of_workers = 2
def monitordevice():
in_prefix=asbytes('in')
out_prefix=asbytes('out')
monitoringdevice = MonitoredQueue(zmq.XREP, zmq.XREQ, zmq.PUB, in_prefix, out_prefix)
monitoringdevice.bind_in("tcp://127.0.0.1:%d" % frontend_port)
monitoringdevice.bind_out("tcp://127.0.0.1:%d" % backend_port)
monitoringdevice.bind_mon("tcp://127.0.0.1:%d" % monitor_port)
monitoringdevice.setsockopt_in(zmq.SNDHWM, 1)
monitoringdevice.setsockopt_out(zmq.SNDHWM, 1)
monitoringdevice.start()
print("Program: Monitoring device has started")
def server(backend_port):
print("Program: Server connecting to device")
context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind("tcp://127.0.0.1:%s" % backend_port)
server_id = random.randrange(1,10005)
while True:
message = socket.recv()
print("Server: Received - %s" % message)
socket.send_string("Response from server #%s" % server_id)
def client(frontend_port, client_id):
print("Program: Worker #%s connecting to device" % client_id)
context = zmq.Context()
socket = context.socket(zmq.REQ)
socket.connect("tcp://127.0.0.1:%s" % frontend_port)
request_num = 1
socket.send_string("Request #%s from client#%s" % (request_num, client_id))
message = socket.recv_multipart()
print("Client: Received - %s" % message)
def monitor():
print("Starting monitoring process")
context = zmq.Context()
socket = context.socket(zmq.SUB)
print("Collecting updates from server...")
socket.connect ("tcp://127.0.0.1:%s" % monitor_port)
socket.setsockopt_string(zmq.SUBSCRIBE, "")
while True:
string = socket.recv_multipart()
print("Monitoring Client: %s" % string)
if __name__ == "__main__":
monitoring_p = Process(target=monitordevice)
monitoring_p.start()
server_p = Process(target=server, args=(backend_port,))
server_p.start()
monitorclient_p = Process(target=monitor)
monitorclient_p.start()
time.sleep(2)
for client_id in range(number_of_workers):
Process(target=client, args=(frontend_port, client_id,)).start()
time.sleep(10)
server_p.terminate()
monitorclient_p.terminate()
monitoring_p.terminate()
when I am changing PUB/SUB in above code then this code is not working.
Please let me know if how monitoring is possible for PUB/SUB

Related

Sending and receiving using sockets python

I am trying to create a function to send and receive information over a socket client & server. It appears that my code is somehow blocking. In the code the first command iteration in my for loop is carried out but then the process becomes blocked. Does anyone have any suggestions how to do this using threading or multithreading?
My code is below:
import socket
import json
import sys
import time
import select
import queue
Ni_Rio_IP= "172.22.11.2"
Ni_Base_IP= "172.22.11.1"
class AliceRio:
def __init__(self, ip_rio, ip_pc):
self.ip_rio = ip_rio
AliceRio.udp_port_rio = 60006
self.ip_pc = ip_pc
AliceRio.udp_port_pc = 50005
AliceRio.json= '{"Dest":"","Name":"","Time":"","Val":{"Str":[],"Pos":[[]],"Data":[[]]},"IP":0,"Port":0,"RT error":{"status":false,"code":0,"source":""}}'
AliceRio.dict= json.loads(self.json)
def PrintUDP(self):
print("RIO IP: %s" % self.ip_rio)
print("RIO UDP port: %s" % self.udp_port_rio)
print("PC IP: %s" % self.ip_pc)
print("PC UDP port: %s" % self.udp_port_pc)
def SendRec(self, send_str):
# Set up socket for sending
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Internet, UDP
sock.sendto(bytes(send_str, 'utf-8'), (self.ip_rio, self.udp_port_rio))
sock.close()
print('got here')
# Set up socket for receiving
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # Internet, UDP
sock.bind((self.ip_pc, self.udp_port_pc))
rec_str, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
print('got here2')
sock.close()
return rec_str
def Receive(self, rec_str):
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # Internet, UDP
sock.bind((self.ip_pc, self.udp_port_pc))
rec_str, addr = sock.recvfrom(1024) # buffer size is 1024 bytes
sock.close()
return rec_str
def Send(self, send_str):
# Set up socket for sending
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Internet, UDP
sock.sendto(bytes(send_str, 'utf-8'), (self.ip_rio, self.udp_port_rio))
sock.close()
#return rec_str
def Aim(self, aim_perc):
if aim_perc < 0 or aim_perc > 100: return "aim_perc out of range"
send_dict=AliceRio.dict
send_dict["Dest"]='Rio'
send_dict["Name"]='Laser Control'
Laser_Mode=1
Simmer_A=0
Pulse_A= 0
Pulse_ms= 20
send_dict["Val"]["Str"]=[str(Laser_Mode), str(aim_perc), str(Simmer_A), str(Pulse_A), str(Pulse_ms)]
send_json=json.dumps(send_dict)
# send it out
self.SendRec(send_json)
rec_json= self.SendRec(send_json)
rec_dict=json.loads(rec_json)
return "Aim laser now at " + rec_dict["Val"]["Str"][1] +'%'
def PWM_Laser_Fan(self, fan_perc):
send_dict=AliceRio.dict
send_dict["Dest"]='Rio'
send_dict["Name"]='PWM Laser'
send_dict["Val"]["Str"][0]=str(fan_perc)
send_json=json.dumps(send_dict)
# send it out
rec_json= self.SendRec(send_json)
rec_dict=json.loads(rec_json)
return rec_dict["Val"]["Str"][0]
def Poll(self):
send_dict=AliceRio.dict
send_dict["Dest"]='Rio'
send_dict["Name"]='Poll'
send_json=json.dumps(send_dict)
# send it out
rec_json= self.SendRec(send_json)
rec_dict=json.loads(rec_json)
if rec_dict["Val"]["Data"][0][0]==0: pid_mode='off'
else: pid_mode='PID'
print('PID mode:', pid_mode)
print('Pos X:', rec_dict["Val"]["Data"][0][1])
print('Pos Y:', rec_dict["Val"]["Data"][0][2])
print('Home:', rec_dict["Val"]["Data"][0][3])
print('Enabled:', rec_dict["Val"]["Data"][0][4])
def PIDControl(self, pid_mode,pid_center):
if pid_mode=="off": mode= 0
elif pid_mode=="PID":mode =1
else: return "pid_mode not valid"
if pid_center[0] not in range(-2048,2048): return "center x-pos not in range"
if pid_center[1] not in range(-2048,2048): return "center y-pos not in range"
send_dict=AliceRio.dict
send_dict["Dest"]='Rio'
send_dict["Name"]='PID Control'
send_dict["Val"]["Str"]=[str(mode), str(pid_center[0]), str(pid_center[1])]
send_json=json.dumps(send_dict)
# send it out
rec_json= self.SendRec(send_json)
rec_dict=json.loads(rec_json)
return "PID mode now at " + rec_dict["Val"]["Str"][0]
Alice1 = AliceRio(Ni_Rio_IP, Ni_Base_IP)
Alice1.PrintUDP()
for i in range(10):
Alice1.Aim((i*10)+10)
time.sleep(0.2)
I would suggest learning to use Pdb and trace through the execution of your program to find where it is getting caught.
Also when learning/developing with sockets I've found that it helps to have separate programs for your client and server in the beginning so you can see how both sides are handling exchanges instead of going the threading route to start since the logging can get confusing, best of luck!
Module threading does help in this scenario.
We can create a thread to receiving incoming messages. And when new message received the thread trigger an event to notify the waiting method SendRec.
import sys
import socket
import json
import threading
import time
class AliceRio:
def __init__(self, .....):
# .........
self.s_in = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.s_in.bind((self.ip_pc, self.udp_port_pc))
self.evt = threading.Event()
self.last_msg = None
def _recv(self):
while True:
msg, _ = self.s_in.recvfrom(1024)
self.last_msg = msg
self.evt.set()
def SendRec(self, send_str):
if not hasattr(self, 'th_recv'):
th = threading.Thread(target=self._recv)
th.setDaemon(True)
th.start()
self.th_recv = th
self.evt.clear()
rio_endpoint = (self.ip_rio, self.udp_port_rio)
s_out = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s_out.sendto(bytes(send_str, 'utf-8'), rio_endpoint)
s_out.close()
if self.evt.wait(timeout=15.0) and self.last_msg:
return self.last_msg
raise Exception('timeout waiting for response.')

control not returned to main thread

I have written a python program in which I created a UDP listener in thread 1 and trying to do something in thread 2. The issue here is control is stuck up in thread 1 and it never returns to main thread so thread 2 is not even starting up.
import threading
import socket
import time
data = ''
def ListenerUDP():
sock1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_address1 = ('localhost', 5000)
print('starting up UDP server on %s port %s' % server_address1)
sock1.bind(server_address1)
while True:
print('\nUDP server is now listening up')
data, address = sock1.recvfrom(4096)
print('received %s bytes from %s' % (len(data), address))
print('is %s' % data.hex())
def Forwarder():
print('do something')
print('Starting main thread')
t1 = threading.Thread(target=ListenerUDP)
t1.start()
t2 = threading.Thread(target=Forwarder)
t2.start()
can someone please help fixing it.

Stop a python script from executing

I have the below python script(server.py) in order to listen to a port and capture the requests from the client. I am calling this script from another python file(Main.py). My requirement is to stop executing server.py after certain amount of time. I tried using exit() at the last line of the file - server.py to stop the server and stop the execution of the file, however I was not able to stop the script from running and the server kept responding. Can anyone help me in letting me know where I am going wrong.
Server.py
bind_ip = "127.0.0.1"
bind_port = 2530
def servercreate():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((bind_ip,bind_port))
server.listen(5)
while True:
client, addr = server.accept()
print('[*] Accepted connection from: %s:%d' % (addr[0], addr[1]))
client_handler = threading.Thread(target=handle_client, args=(client,))
client_handler.start()
def handle_client(client_socket):
request = client_socket.recv(2056)
print('[*] Received: %s' % request)
message = "{}"
client_socket.send(message.encode('utf-8'))
client_socket.close()
if __name__ == '__main__':
servercreate()
Main.py
import Server
Server.servercreate()
if you don't want your code interrupted by time.sleep (which I think stops the code from running), use this:
import time
timeout = time.time() + 10
while True:
print ('hello')
if time.time() > timeout:
print ('program terminated')
break
if you want 10 minutes worth of time use:
timeout = time.time() + 60*10
If you just want to stop the program running after a certain amount of time use something like
import time
x=0
while True:
print ('waiting 5')
time.sleep(5)
x += 1
if x == (10):
break
the time.sleep is in seconds, break stops the loop and should end your program
update, try this:
import time
bind_ip = "127.0.0.1"
bind_port = 2530
def servercreate():
#put minutes of time you want program to run for below
minutes = 10
timeout = time.time() + (60*minutes)
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((bind_ip,bind_port))
server.listen(5)
while True:
client, addr = server.accept()
print('[*] Accepted connection from: %s:%d' % (addr[0], addr[1]))
client_handler = threading.Thread(target=handle_client, args=(client,))
client_handler.start()
if time.time() > timeout:
break
def handle_client(client_socket):
request = client_socket.recv(2056)
print('[*] Received: %s' % request)
message = "{}"
client_socket.send(message.encode('utf-8'))
client_socket.close()
if __name__ == '__main__':
servercreate()

How to get the modbus_tk master's IP?

I write a slave.py(server) base on modbus_tk(https://github.com/ljean/modbus-tk).
Then,I use the client tools to connect the slave,It's OK.
And now,I want to get which master(client) access to me,I want to get source IP and port.
I find the key point 'client, address = self._sock.accept()' in function _do_run(self) in Class TcpServer(server) ,modbus_tcp.py.
I tried some methods, but it didn't work.
slave.py
import modbus_tk
import modbus_tk.modbus_tcp as modbus_tcp
import modbus_tk.defines as mdef
import threading
import sys
from lxml import etree
logger = modbus_tk.utils.create_logger(name='console', record_format='%(message)s')
server = modbus_tcp.TcpServer(port=502,address='0.0.0.0')
class Modbus_server(object):
def main(self):
try:
logger.info("running...")
logger.info("enter 'quit' for closing the server")
server.start()
self.config_slaves()
while True:
cmd = sys.stdin.readline()
if cmd.find('quit')==0:
#when input"quit",the program exit!
sys.stdout.write('bye-bye\r\n')
sys.exit(0)
finally:
server.stop()
#get slave configuration
def config_slaves(self):
dom = etree.parse('modbus.xml')
slaves = dom.xpath('//modbus/slaves/*')
try:
for s in slaves:
slave_id = int(s.attrib['id'])
slave = server.add_slave(slave_id)
logger.debug('Added slave with id %s.', slave_id)
for b in s.xpath('./blocks/*'):
name = b.attrib['name']
request_type = eval('mdef.' + b.xpath('./type/text()')[0])
start_addr = int(b.xpath('./starting_address/text()')[0])
size = int(b.xpath('./size/text()')[0])
slave.add_block(name, request_type, start_addr, size)
logger.debug(
'Added block %s to slave %s. '
'(type=%s, start=%s, size=%s)',
name, slave_id, request_type, start_addr, size)
logger.info('modbus initialized')
except (Exception) as e:
logger.info(e)
modbus=Modbus_server()
modbus.main()`
modbus_tcp.py
''''''
......
def _do_run(self):
"""called in a almost-for-ever loop by the server"""
#check the status of every socket
inputready = select.select(self._sockets, [], [], 1.0)[0]
#handle data on each a socket
for sock in inputready:
try:
if sock == self._sock:
# handle the server socket
client, address = self._sock.accept()
client.setblocking(0)
LOGGER.info("%s is connected with socket %d...", str(address), client.fileno())
self._sockets.append(client)
call_hooks("modbus_tcp.TcpServer.on_connect", (self, client, address))
''''''
''''''

How can I adapt between non zmq socket and pyzmq?

I want to write a bridge adapt between non ZMQ socket and ZMQ socket.
client code:
import socket
if __name__ == '__main__':
HOST = "localhost"
PORT = 8888
BUFFER = 4096
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print sock
ret = sock.connect((HOST, PORT))
print ret
ret = sock.send('hello, tcpServer!')
print ret
recv = sock.recv(BUFFER)
print ('[tcpServer siad]: %s' % recv)
sock.close()
except e:
print e
proxy code, use this proxy to send request to ZMQ_REP server.
import zmq
if __name__ == '__main__':
context = zmq.Context()
socket = context.socket(zmq.STREAM)
socket.bind("tcp://*:8888")
socket_req = context.socket(zmq.REQ)
socket_req.connect("tcp://localhost:5556")
while True:
clientid, message = socket.recv_multipart();
print("id: %r" % clientid)
print("request:",message.decode('utf8'))
socket_req.send(clientid, flags=zmq.SNDMORE, copy=False)
socket_req.send("Hi", copy=False)
clientid, message = socket_req.recv_multipart()
print("id: %r" % clientid)
print("request:",message.decode('utf8'))
ZMQ_REP server code:
import zmq
import time
import sys
if __name__ == '__main__':
port = '5556'
if len(sys.argv) > 1:
port = sys.argv[1]
int(port)
context = zmq.Context()
socket = context.socket(zmq.REP)
socket.bind("tcp://*:%s" % port)
while True:
message = socket.recv()
print "Received request: ", message
time.sleep(1)
socket.send("world from %s" % port)
the REQ get error:
Received request: k
Traceback (most recent call last):
File "req_server.py", line 21, in <module>
socket.send("world from %s" % port)
File "zmq/backend/cython/socket.pyx", line 574, in zmq.backend.cython.socket.Socket.send (zmq/backend/cython/socket.c:5434)
File "zmq/backend/cython/socket.pyx", line 621, in zmq.backend.cython.socket.Socket.send (zmq/backend/cython/socket.c:5196)
File "zmq/backend/cython/socket.pyx", line 181, in zmq.backend.cython.socket._send_copy (zmq/backend/cython/socket.c:2035)
File "zmq/backend/cython/checkrc.pxd", line 21, in zmq.backend.cython.checkrc._check_rc (zmq/backend/cython/socket.c:6248)
zmq.error.ZMQError: Operation cannot be accomplished in current state
First point: It's generally not recommended to use REQ/REP in zmq. Use the more general DEALER/ROUTER combination. The only difference:
When the ROUTER recvs, a routing ID is the first part of the message. This is used to route replies back to the sender.
the lock-step req/rep/req/rep sequence is not enforced (this is the error you are seeing).
Here's a version of your proxy using DEALER:
import zmq
if __name__ == '__main__':
context = zmq.Context()
socket = context.socket(zmq.STREAM)
socket.bind("tcp://*:8888")
socket_req = context.socket(zmq.DEALER)
socket_req.connect("tcp://localhost:5556")
while True:
clientid, message = socket.recv_multipart()
print("id: %r" % clientid)
print("request: %s" % message.decode('utf8'))
socket_req.send(message)
reply = socket_req.recv()
print("reply: %s" % reply.decode('utf8'))
socket.send_multipart([clientid, reply])
And your server, using ROUTER:
import zmq
import time
import sys
if __name__ == '__main__':
port = 5556
if len(sys.argv) > 1:
port = int(sys.argv[1])
context = zmq.Context()
socket = context.socket(zmq.ROUTER)
socket.bind("tcp://127.0.0.1:%i" % port)
while True:
message = socket.recv_multipart()
req_id = message[0]
print("Received request: %s" % message[1:])
time.sleep(1)
socket.send_multipart([req_id, "world from %s" % port])
socket_req.send(clientid, flags=zmq.SNDMORE, copy=False)
socket_req.send("Hi", copy=False)
Best guess is that it's not properly registering the SNDMORE flag and attempting to send a whole new request rather than appending to the first one (thus breaking the strict SEND/RECEIVE order for REQ sockets)... thus the "current state" of the socket would not allow it to send the second part of your message. Try using send_multipart(), or validating that your parameters are being passed in correctly.

Categories