I'm trying to subscribe to a pub-sub server.
When doing that using Python there is no problem, it works like expected.
But when I'm trying to subscribe to the exact same server with NodeJS ZMQ nothing happens.
I can't figure out where something goes wrong, probably at the subscribe-part?
Python:
from gzip import GzipFile
from cStringIO import StringIO
import zmq
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect("tcp://127.0.0.1:6701")
socket.setsockopt(zmq.SUBSCRIBE, '')
while True:
multipart = socket.recv_multipart()
address = multipart[0]
contents = ''.join(multipart[1:])
contents = GzipFile('','r',0,StringIO(contents)).read()
print("[%s] %s\n" % (address, contents))
socket.close()
context.term()
NodeJS:
var zmq = require('zmq')
, sock = zmq.socket('sub');
sock.connect('tcp://127.0.0.1:6701');
sock.subscribe('');
console.log('Subscriber connected to port 6701');
sock.on('message', function(topic, message) {
console.log('received a message related to:', topic, 'containing message:', message);
});
The on-message part in the NodeJS example never gets fired.
When I run a simple NodeJS publisher the subscriber works like expected.
Note that the address I connect to is a local IP due to the fact that I run some local distribution tool for the ZeroMQ messages.
What can be the difference between the two scripts that the NodeJS script does not behave like the Python script on the same publishing source?
Both are using ZeroMQ 4.
Edit:
As suggested by Jason I would post some the code of the publisher. But because this is a 3rd party I don't have the code of that. But when I fire up a simple Python publisher the subscribers act the same like they do on the 3rd party publisher.
Simple Python publisher:
import zmq
import random
import sys
import time
port = "6701"
if len(sys.argv) > 1:
port = sys.argv[1]
int(port)
context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind("tcp://*:%s" % port)
while True:
topic = random.randrange(9999,10005)
messagedata = random.randrange(1,215) - 80
print "%d %d" % (topic, messagedata)
socket.send("%d %d" % (topic, messagedata))
time.sleep(1)
NodeJS publisher:
var zmq = require('zmq')
, sock = zmq.socket('pub');
sock.bindSync('tcp://127.0.0.1:6701');
console.log('Publisher bound to port 3000');
setInterval(function(){
console.log('sending a multipart message envelope');
sock.send(['kitty cats', 'meow!']);
}, 500);
The NodeJS publisher works with both the Python and the NodeJS subscriber but the Python publisher works only with the Python subscriber and not the NodeJS one.
Fixed.
Removing node_modules and reinstaling it by npm install zmq.
Related
I'm trying to send a file from my laptop(win10) to my mobile(android) over bluetooth. I followed this answer and I'm doing the same with python 3.6
I'm using PyOBEX Python 3 Package and this is what I've tried.
import sys
from PyOBEX.client import Client
from bluetooth import *
addr = '60:7E:DD:A7:42:43'
print("Searching for OBEX service on {}".format(addr))
services = find_service(address=addr, name=b'OBEX Object Push\x00')
if len(services) == 0:
sys.exit()
first_match = services[0]
port = first_match["port"]
client = Client(addr, port)
client.connect()
client.put("test.txt", "Hello world\n")
client.disconnect()
When I run this, the device is discovered but it doesn't establish a connection or send files. This is the error it gives
I tried messing around with the PyOBEX package by changing the type of data returned by socket_.recv to str but it gives me another error,
I'm stuck and I have never worked with bluetooth or sockets before. Any help is appreciated
For a project I need to communicate between C++ and Python via ZMQ over the WLAN network.
If I use my C++ implementation, everything works fine. I just type in the IP+Port number at the client.bind("tcp:// ...) and I can send messages via WLAN.
If I try the same with the Python Code, it does not work.
So I just tested the python examples (so no C++ anymore): http://zguide.zeromq.org/py:durapub
http://zguide.zeromq.org/py:durasub
I replaced the >localhost< in the client with the IP of my host computer. I do not receive any messages. I am using exactly the code from the example, except the replacement.
Here is the Code:
PUBLISHER:
import zmq
import time
context = zmq.Context()
# Subscriber tells us when it's ready here
sync = context.socket(zmq.PULL)
sync.bind("tcp://*:5564")
# We send updates via this socket
publisher = context.socket(zmq.PUB)
publisher.bind("tcp://*:5565")
# Wait for synchronization request
sync_request = sync.recv()
# Now broadcast exactly 10 updates with pause
for n in xrange(10):
msg = "Update %d" % n
publisher.send(msg)
time.sleep(1)
publisher.send("END")
time.sleep(1) # Give 0MQ/2.0.x time to flush output
SUBSCRIBER
import zmq
import time
context = zmq.Context()
# Connect our subscriber socket
subscriber = context.socket(zmq.SUB)
subscriber.setsockopt(zmq.IDENTITY, "Hello")
subscriber.setsockopt(zmq.SUBSCRIBE, "")
subscriber.connect("tcp://192.168.2.119:5565")
# Syncronize with the publisher
sync = context.socket(zmq.PUSH)
sync.connect("tcp://192.168.2.119:5564")
sync.send("")
# Get updates, expect random Ctrl-C death
while True:
data = subscriber.recv()
print data
if data == "END":
break
Its exactly the example code, except that I changed localhost to the IP Adress of my publisher in the Subscriber-Code. Btw, I did the same in the C++ example Code and it works.
I am trying to publish a message(it's like broadcast when using raw sockets) to my subnet with a known port but at subscriber end, the message is not received. The idea is the IP address of the first machine should not be known to the second machine that's why I am using broadcast IP. With UDP or TCP raw socket, it works but I am trying to learn pub-sub pattern not sure how to incorporate that idea.
This is my codes:
Publisher:
import zmq
import sys
import time
context=zmq.Context()
socket=context.socket(zmq.PUB)
socket.bind("tcp://192.168.1.255:5677")
while True:
data='hello'.encode()
socket.send(data)
#time.sleep(1)
Subscriber:
context=zmq.Context()
sub=context.socket(zmq.PUB)
sub.setsocketopt(zmq.SUBSCRIBE, "".encode())
sub.connect('tcp://192.168.1.255:5677')
sub.recv()
print(sub.recv())
In terms of raw UDP, I wrote a code which works perfectly.
broadcast:
def broadcast(Host,port):
#send bd
sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
msg=get_ip_data("wlp3s0")
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
time.sleep(1.5)
# print("yes sending", client)
sock.sendto(msg.encode(), (Host,port))
recv:
def broadcast_recv():
#listen bd
sock=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
sock.bind((get_bd_address("wlp1s0"),12345))
# receive broadcast
msg, client = sock.recvfrom(1024)
a=(msg.decode())
print(a)
It seems you forgot the zmq.SUB in the subscriber side. Also you used sub.setsocketopt() instead of sub.setsockopt().
Try it:
Publisher:
import zmq
import time
context = zmq.Context()
socket = context.socket(zmq.PUB)
socket.bind("tcp://*:5677") # Note.
while True:
socket.send_string('hello')
time.sleep(1)
Subscriber:
context = zmq.Context()
sub=context.socket(zmq.SUB) # Note.
sub.setsockopt(zmq.SUBSCRIBE, b"") # Note.
sub.connect('tcp://192.168.1.255:5677')
while True:
print(sub.recv())
[NOTE]:
You can also change the .bind() and .connect() in subscriber and publisher with your policy. (This post is relevant).
Make sure that 5677 is open in the firewall.
socket.bind("tcp://*:5677") or socket.bind("tcp://0.0.0.0:5677") is broadcasting trick.
I think the problem is that the SUB socket cannot register itself with the PUB socket. Even though in-concept the data only goes from PUB to SUB, in reality, there are also control messages (e.g. subscription topics), being sent back to the PUB.
If your netmask is 255.255.255.0, this will probably not work as expected.
I am new to networking programming and python.
I am trying to figure out how to run different jobs at the server side.
For example, I want one function to create connections for incoming clients but in the same time I can still do some administration work from the terminal.
My code is as below but it doesn't work:
Edited: it doesn't work means it will get stuck in the init_conn() function
Like:
starting up on localhost port 8887
Thread: 0 Connected with 127.0.0.1:48080
# waiting
I am looking into SocketServer framework but don't know how that works.
from thread import *
import socket
def init_conn():
thread_count =0
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the port
server_address = ('localhost', 8887)
print >>sys.stderr, 'starting up on %s port %s' % server_address
sock.bind(server_address)
# Listen for incoming connections
sock.listen(10)
#now keep talking with the client
while 1:
#wait to accept a connection - blocking call
conn, addr = sock.accept()
print 'Thread: '+ str(thread_count) + ' Connected with ' + addr[0] + ':' + str(addr[1])
#start new thread takes 1st argument as a function name to be run, second is the tuple of arguments to the function.
start_new_thread(clientthread ,(conn,))
thread_count +=1
sock.close()
def clientthread(conn):
# receive data from client and send back
def console():
print 'this is console'
option = raw_input('-v view clients')
if option == 'v':
print 'you press v'
def main():
start_new_thread( init_conn(),() )
start_new_thread( console(),() )
if __name__ == "__main__":
main()
Your problem is probably that you start the program, sometimes it prints "this is console" and then it ends.
The first bug is that you call the methods instead of passing the handle to start_new_thread. It must be:
start_new_thread( init_conn, () )
i.e. no () after the function name.
The program doesn't do much because start_new_thread() apparent starts a thread and then waits for it to stop. The documentation is pretty unclear. It's better to use the new threading module; See http://pymotw.com/2/threading/
def main():
t = threading.Thread( target=init_conn )
t.daemon = True
t.start()
console()
so the code will run until console() ends.
I suggest to split the server and the command line tool. Create a client which accepts commands from the command line and sends them to the server. That way, you can start the console from anywhere and you can keep the code for the two separate.
Seeing that you're new to python, have you tried taking a look at the threading module that comes with the standard library?
import threading
... #rest of your code
while conditions==True:
i = threading.Thread(target=init_conn)
c = threading.Thread(target=console)
i.start()
c.start()
Can't say I've done too much with networking programming with python, so I don't really have much to say in that manner, but at least this should get you started with adding multithreading to your project.
Using SocketServer you may implement a client/server system. The documentation gives small examples which may be useful for you. Here is an extended example from there:
server.py :
import SocketServer
import os
import logging
FORMAT = '[%(asctime)-15s] %(message)s'
logging.basicConfig(format=FORMAT, level=logging.DEBUG)
class MyServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
# By setting this we allow the server to re-bind to the address by
# setting SO_REUSEADDR, meaning you don't have to wait for
# timeouts when you kill the server and the sockets don't get
# closed down correctly.
allow_reuse_address = True
request_queue_size = 10
def __init__(self, port):
self.host = os.uname()[1]
self.port = port
SocketServer.TCPServer.__init__(self, (self.host,self.port), MyTCPHandler)
logging.info( "Server has been started on {h}:{p}".format(h=self.host,p=self.port) )
class MyTCPHandler(SocketServer.BaseRequestHandler):
"""
The RequestHandler class for our server.
It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def handle(self):
# self.request is the TCP socket connected to the client
# max length is here 1024 chars
self.data = self.request.recv(1024).strip()
logging.info( "received: {d}".format(d=self.data) )
# here you may execute different functions according to the
# request string
# here: just send back the same data, but upper-cased
self.request.sendall(self.data.upper())
PORT = 8887
if __name__ == "__main__":
# Create the server, binding to localhost on port 8887
#server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
server = MyServer( PORT )
# Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()
client.py
import socket
import sys
import logging
FORMAT = '[%(asctime)-15s] %(message)s'
logging.basicConfig(format=FORMAT, level=logging.DEBUG)
HOST, PORT = "workstation04", 8887
logging.info( "connect to server {h}:{p}".format(h=HOST,p=PORT ) )
# read command line
data = " ".join(sys.argv[1:])
# Create a socket (SOCK_STREAM means a TCP socket)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# Connect to server and send data
sock.connect((HOST, PORT))
sock.sendall(data + "\n")
# Receive data from the server and shut down
received = sock.recv(1024)
finally:
sock.close()
logging.info( "Sent: {}".format(data) )
logging.info( "Received: {}".format(received) )
The output looks something like:
server side:
> python server.py
[2015-05-28 11:17:49,263] Server has been started on disasterarea:8887
[2015-05-28 11:17:50,972] received: my message
client side:
[2015-05-28 11:17:50,971] connect to server disasterarea:8887
[2015-05-28 11:17:50,972] Sent: my message
[2015-05-28 11:17:50,972] Received: MY MESSAGE
You can run several clients (from different consoles) in parallel. You may implement a request processor on the server side which processes the incoming requests and executes certain functions.
Alternatively, you may use the python module ParallelPython which executes python code locally on a multicore system or on a cluster and clusters. Check the http examples.
I had to force pip to install this module:
pip install --allow-external pp --allow-unverified pp pp
Here are the "sender" and "receiver" I am using.
sender.py
import time
import zmq
context = zmq.Context()
sender = context.socket(zmq.PUSH)
sender.connect("tcp://127.0.0.1:5557")
c = 0
while True:
sender.send_json(c)
print "Sent {}".format(c)
c += 1
time.sleep(1)
reciever.py
import zmq
context = zmq.Context()
receiver = context.socket(zmq.PULL)
receiver.connect("tcp://127.0.0.1:5557")
while True:
m = receiver.recv_json()
print m
When I start the receiver then start the sender nothing is written to stdout on the receiver's cmd (I am trying to get this to work on windows 7). I've added inbound and outbound exceptions to the firewall for port 5557 and running netstat -an doesn't show anything running on port 5557. Lastly I am using zmq 2.2.0.
In your sender.py you should write sender.bind, not sender.connect.