I am currently working on a project that requires me to connect two terminals via ZMQ sockets, and my current solution does so via the PUB-SUB Socket functionality. However, when I run the programs, while the publisher sends the messages, the subscriber never receives any of the messages. I've tried changing the IP address between them, and trying to "brute force send" message between the sub and the pub, but to no avail.
Reduced form of the code:
Server.cpp:
#include <zmq.h>
const char* C_TO_S = "tcp://127.0.0.1:5557";
const char* S_TO_C = "tcp://127.0.0.1:5558";
int main() {
zmq::context_t context(1);
zmq::socket_t pub(context, ZMQ_PUB);
zmq::socket_t sub(context, ZMQ_SUB);
int sndhwm = 0;
sub.connect(C_TO_S);
pub.bind(S_TO_C);
sub.setsockopt(ZMQ_SUBSCRIBE, &sndhwm, sizeof(sndhwm));
//cout << C_TO_S << endl;
while(true) {
zmq::message_t rx_msg;
sub.recv(&rx_msg);
cout << "b\n";
// other code goes here
}
}
Client.cpp:
#incldue <zmq.h>
const char* C_TO_S = "tcp://127.0.0.1:5557";
const char* S_TO_C = "tcp://127.0.0.1:5558";
void network_thread() {
zmq::context_t context(1);
zmq::socket_t pub(context, ZMQ_PUB);
zmq::socket_t sub(context, ZMQ_SUB);
int sndhwm = 0;
sub.connect(S_TO_C);
pub.connect(C_TO_S);
sub.setsockopt(ZMQ_SUBSCRIBE, &sndhwm, sizeof(sndhwm));
while (true) {
cout << pub.send("a", strlen("a"), 0);
cout << "AA\n";
}
// Other code that doesn't matter
}
The main in Client.cpp calls network_thread in a separate thread, and then spams the publisher to send the message "a" to the server. However, the server does not get any message from the client. If the server got any message, it would print out "b", however it never does that. I also know that the publisher is sending messages because it prints out "1" upon execution.
Also, assume that the client subscriber and the server publisher has a purpose. While they don't work atm either, a fix to the other set should translate into a fix of those.
I have tried changing the port, spamming send messages, etc. Nothing resulted in the server receiving any messages.
Any help would be appreciated, thank you.
You set a message filter option on the SUB socket. This means that you will only receive messages that begin with the bytes set by the filter.
This code:
int sndhwm = 0;
sub.setsockopt(ZMQ_SUBSCRIBE, &sndhwm, sizeof(sndhwm));
Sets the filter to sizeof(sndhwm) bytes with value 0x00. But your message does not begin with this number of 0x00 bytes. Hence the message is ignored by the SUB socket.
You should remove the setsockopt call.
If your intent was to clear the message filter, you can do this with:
sub.setsockopt(ZMQ_SUBSCRIBE, nullptr, 0);
Related
I have the following C++ code that sends a zmq packet of 10 bytes to a ZMQ Pull Source in GNU Radio Companion.
#include <iostream>
#include <zmq.h>
using namespace std;
int main()
{
void *send_context, *responder;
unsigned short gnu_trigger[10];
string trig_addr = "tcp://127.0.0.1:4500";
int rc;
/* Bind ZMQ address for transmitting data */
send_context = zmq_ctx_new();
responder = zmq_socket(send_context, ZMQ_PUSH);
rc = zmq_bind(responder, trig_addr.c_str());
while(1)
{
cout << "Sending trigger to gnuradio\n";
memset(gnu_trigger, 0x0, sizeof(unsigned short) * 10);
gnu_trigger[0] = 1;
rc = zmq_send(responder, &gnu_trigger, sizeof(gnu_trigger), 0);
cout << "Sent trigger to gnuradio\n";
sleep(1);
}
zmq_close(responder);
zmq_ctx_destroy(send_context);
return 0;
}
If I remove/comment the cout statements before and after sending the ZMQ packets, the packet is not transmitted. However, if the cout statements are enabled, the packet is sent successfully.
Why does this happen?
Zmq is asynchronous so messages aren't sent when you call zmq_send and are sent at some point in the future. As your program ends immediately after calling zmq_send zmq doesn't have time to send the messages.
Adding the print statements slows your program down enough to allow zmq time to send the messages.
You should call zmq_close and zmq_term before exiting your program.
I am new to ZMQ and already did the tutorials about the publish subscribe pattern. But for my application they don't quite apply. I have two types of applications. Application one can create connections to multiple "Applications two"s over network and send them data.
I tried implementing this with the Publish/Subscribe pattern, but instead of the subscriber connecting to the publisher the publisher connects to the subscribers.
Publisher:
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_PUB);
socket.connect("tcp://localhost:5555");
std::string text = "Hello World";
zmq::message_t message(text.size());
memcpy(message.data(), text.c_str(), text.size());
socket.send(message);
Subscriber:
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_SUB);
socket.bind("tcp://*:5555");
const char* filter = "Hello ";
socket.setsockopt(ZMQ_SUBSCRIBE, filter, strlen(filter));
zmq::message_t request;
socket.recv(&request);
std::string message = std::string(static_cast<char*>(request.data()), request.size());
std::cout << "Message received!" << std::endl;
std::cout << message << std::endl;
The publisher finnishes without error, but the subscriber is stuck in the recv(). And yes I am starting them in the right order (subscriber first)
I found the solution myself:
The problem is, that the publisher send the message, before the subscriber was ready to receive.
A simple
zmq_sleep(1)
before the
socket.send(message);
did the job.
I'm trying to build a WebSocket server with POCO.
My Server should send data to the client and all the time within a time intervall. And when the client sends some data, the sever should manipulate the data it send to the client.
My handleRequest method within my WebSocketRequestHandler:
void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
{
WebSocket ws(request, response);
char buffer[1024];
int flags = 0;
int n = 0;
do {
// recieving message
n = ws.receiveFrame(buffer, sizeof(buffer), flags);
// ... do stuff with the message
// sending message
char* msg = (char *) "Message from server"; // actually manipulated, when message recieved
n = sizeof(msg);
ws.sendFrame(msg, strlen(msg), WebSocket::FRAME_TEXT);
sleep(1); // time intervall sending messages
} while (n > 0 || (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE);
}
The problem is, that the method get stucked in we.recieveFrame() until it gets a frame.
So how can i solve this, that receiveFrame() is not blocking the loop.
Is the a better way to solve this complete problem?
Thanks.
You should set a receive timeout.
ws.setReceiveTimeout(timeout);
So, you will get a Poco::TimeoutException each timeout microseconds and you can do all you need, included send data by that websocket.
ws.setReceiveTimeout(1000000);//a second
do{
try{
int n = ws.receiveFrame(buffer, sizeof(buffer), flags);
//your code to manipulate the buffer
}
catch(Poco::TimeoutException&){
....
}
//your code to execute each second and/or after receive a frame
} while (condition);
Use a std::thread or pthread and call the blocking function in the thread's function
I've programmed a simple c++ client which should communicate with another program using a listener thread (a downloaded EchoServer in Java) over the local loop on Ubuntu 14.04. However, there's a problem in the following situation:
Client connects to server
Server sends greeting message
Client receives message and sends a new message to server
Client waits for an answer; the main thread sleeps and the listener thread waits for an answer using recv()
In the next step, the server should receive the message sent by the server, but it doesn't. Instead it first receives the message once the client terminates.
I think that the problem is that the client blocks resources and thus not allowing the server to receive the message, but I'm not sure. Unfortunately I don't have the option to test this on two separate machines.
Code snippets:
// main method
int main(void) {
Client client("127.0.0.1", 13050);
std::cout << client.open() << std::endl;
client.attachListener(foo);
usleep(1000 * 1000 * 2);
std::cout << client.send("hello") << std::endl;
usleep(1000 * 1000 * 5);
}
// send method
int Client::send(const char* msg) {
return write(sockfd, msg, strlen(msg));
}
// listener function
void* Client::listen() {
char buffer[256];
unsigned int receive_size = 0;
while(true) {
receive_size = 0;
while((receive_size = recv(sockfd, &buffer, 256, 0)) > 0) {
buffer[receive_size] = '\0';
msgHandler(buffer);
bzero(&buffer, 256);
}
if(receive_size == 0) {
msgHandler("Server disconnected");
} else if(receive_size == 1) {
msgHandler("Connection failure!");
}
}
return NULL;
}
Output:
1
Welcome to the Java EchoServer. Type 'bye' to close.
6
The EchoServer implementations typically want to see a newline on the message you send before they'll echo it back. Instead of client.send("hello") try client.send("hello\n").
Also, though this isn't really necessary for an application you're just experimenting with, you might want to turn off the Nagle algorithm on your client socket so that small messages get sent immediately. Add code like this just after the point where you call connect with client socket:
int flag = 1;
int res = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof flag);
if (res < 0) // handle setsockopt failure here...
This code requires these header files:
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
Here is ZeroMq C++ code for simple request - reply where both exchange messages alternatively.
But error occures when messages are only sent continuously ....
Reply code :
include zmq.hpp
include string
include iostream
include unistd.h
include ctime
int main () {
// Prepare our context and socket
zmq::context_t context (1);
zmq::socket_t socket (context, ZMQ_REP);
socket.bind ("tcp://*:5557");
zmq::message_t reply (5);
memcpy ((void *) reply.data (), "World", 5);
zmq::message_t request;
// Wait for next request from client
socket.recv (&request);
///////////////// """observe_line_1"""
std::cout << "Received Hello" << std::endl;
while (true)
{
// Send reply back to client
socket.send (reply);
}
return 0;
}
Request code :
include zmq.hpp
include string
include iostream
include ctime
int main ()
{
zmq::context_t context (1);
zmq::socket_t socket (context, ZMQ_REQ);
socket.connect ("tcp://localhost:5557");
zmq::message_t request (6);
memcpy ((void *) request.data (), "Hello", 5);
zmq::message_t reply;
socket.send(request);
//////////////////////////////////////////"""observe_line_2"""
for (int request_nbr = 0; request_nbr != 1000; request_nbr++)
{
socket.recv (&reply);
std::cout << "Received World " << request_nbr << std::endl;
}
return 0;
}
Output
After executing Reqply then executing request then following error occurs
terminate called after throwing an instance of 'zmq::error_t'
what(): Operation cannot be accomplished in current state
Aborted
Point to be observed
when "observe_line_1" is inside the for loop below it and "observe_line_2" is inside while loop below it and executed then the code is executed succesfully without any errors ????
Sending multiple replies for one request is not allowed by the REQ-REP model.
The REQ-REP socket pair is in lockstep. The client issues zmq_send() and then zmq_recv(), in a loop (or once if that's all it needs). Doing any other sequence (e.g., sending two messages in a row) will result in a return code of -1 from the send or recv call. Similarly, the service issues zmq_recv() and then zmq_send() in that order, as often as it needs to.
reference, alternative socket types, maybe this can help
Actually you can send more than one message in row, as long as you send data with flags=zmq::SNDMORE.