ZeroMq PUB/SUB pattern not working properly - c++

My Requirements:
High throughput, atleast 5000 messages per second
Order of delivery not important
Publisher, as obvious, should not wait for a response and should not care if a Subscriber is listening or not
Background:
I am creating a new thread for every message because if I dont, the messages generation part will out-speed the sending thread and messages get lost, so a thread for each message seems to be the right approach
Problem:
The problem is that somehow the threads that are started to send out the zMQ message are not being terminated (not exiting/finishing). There seems to be a problem in the following line:
s_send(*client, request.str());
because if I remove it then the threads terminate fine, so probably its this line which is causing problems, my first guess was that the thread is waiting for a response, but does a zmq_PUB wait for a response?
Here is my code:
void *SendHello(void *threadid) {
long tid;
tid = (long) threadid;
//cout << "Hello World! Thread ID, " << tid << endl;
std::stringstream request;
//writing the hex as request to be sent to the server
request << tid;
s_send(*client, request.str());
pthread_exit(NULL);
}
int main() {
int sequence = 0;
int NUM_THREADS = 1000;
while (1) {
pthread_t threads[NUM_THREADS];
int rc;
int i;
for (i = 0; i < NUM_THREADS; i++) {
cout << "main() : creating thread, " << i << endl;
rc = pthread_create(&threads[i], NULL, SendHello, (void *) i);
pthread_detach(threads[i]);
sched_yield();
if (rc) {
cout << "Error:unable to create thread," << rc << endl;
exit(-1);
}
}
//usleep(1000);
sleep(1);
}
pthread_exit(NULL);
//delete client;
return 0;
}
My Question:
Do I need to tweak zMQ sockets so that the PUB doesnt wait for a reply what am I doing wrong?
Edit:
Adding client definition:
static zmq::socket_t * s_client_socket(zmq::context_t & context) {
std::cout << "I: connecting to server." << std::endl;
zmq::socket_t * client = new zmq::socket_t(context, ZMQ_SUB);
client->connect("tcp://localhost:5555");
// Configure socket to not wait at close time
int linger = 0;
client->setsockopt(ZMQ_LINGER, &linger, sizeof (linger));
return client;
}
zmq::context_t context(1);
zmq::socket_t * client = s_client_socket(context);

but does a zmq_PUB wait for a response?
No, this could be the case if your socket wasn't a PUB socket and you hit the high-water mark, but this isn't the case. Do the messages get sent?

Related

ZeroMQ handling interrupt in multithreaded application

Graceful exit in ZeroMQ in multithreaded environment
Specs : ubuntu 16.04 with c++11,libzmq : 4.2.3
Sample code
static int s_interrupted = 0;
static void s_signal_handler (int signal_value)
{
s_interrupted = 1;
//some code which will tell main thread to exit
}
static void s_catch_signals (void)
{
struct sigaction action;
action.sa_handler = s_signal_handler;
action.sa_flags = 0;
sigemptyset (&action.sa_mask);
sigaction (SIGINT, &action, NULL);
sigaction (SIGTERM, &action, NULL);
}
static void Thread((zsock_t *pipe, void *)
{
zmq::context_t context(1);
zmq::socket_t requester1(context,ZMQ_DEALER);
zmq::socket_t requester2(context,ZMQ_DEALER);
requester1.connect(address1);
requester2.connect(address2);
zmq_pollitem_t items []=
{{requester1,0,ZMQ_POLLIN,0},
{requester2,0,ZMQ_POLLIN,0}};
while(true)
{
zmq::message_t message;
zmq::poll (items, 2, -1);
if (items [0].revents & ZMQ_POLLIN)
{
requester1.recv(&message);
}
if (items [1].revents & ZMQ_POLLIN)
{
requester2.recv(&message);
}
}
}
int main()
{
.
//some code
.
zactor_t *actor = zactor_new (Threaded, nullptr);
s_catch_signals();
.
//continue
.
//wait till thread finishes to exit
return 0;
}
Now when the interrupt occurs it will call the signal handler from the main thread. I somehow need to tell the thread (poller) to exit from the signal handler. Any ideas how to achieve this?
From ZMQ documentation you have 2 "idiomatic" way of dealing with this :
Polling on a pipe, and writing on the pipe in the signal handler.
Catching exception thrown in recv when a signal is sent.
After testing it, seems that zmq::poll does not throw an exception on SIGINT.
Therefore the solution seem to be to use a socket dedicated to closing.
The solution looks like this :
#include <iostream>
#include <thread>
#include <signal.h>
#include <zmq.hpp>
zmq::context_t* ctx;
static void s_signal_handler (int signal_value)
{
std::cout << "Signal received" << std::endl;
zmq::socket_t stop_socket(*ctx, ZMQ_PAIR);
stop_socket.connect("inproc://stop_address");
zmq::message_t msg("0", 1);
stop_socket.send(msg);
std::cout << "end sighandler" << std::endl;
}
static void s_catch_signals (void)
{
struct sigaction action;
action.sa_handler = s_signal_handler;
action.sa_flags = 0;
sigemptyset (&action.sa_mask);
sigaction (SIGINT, &action, NULL);
sigaction (SIGTERM, &action, NULL);
}
void thread(void)
{
std::cout << "Thread Begin" << std::endl;
zmq::context_t context (1);
ctx = &context;
zmq::socket_t requester1(context,ZMQ_DEALER);
zmq::socket_t requester2(context,ZMQ_DEALER);
zmq::socket_t stop_socket(context, ZMQ_PAIR);
requester1.connect("tcp://127.0.0.1:36483");
requester2.connect("tcp://127.0.0.1:36483");
stop_socket.bind("inproc://stop_address");
zmq_pollitem_t items []=
{
{requester1,0,ZMQ_POLLIN,0},
{requester2,0,ZMQ_POLLIN,0},
{stop_socket,0,ZMQ_POLLIN,0}
};
while ( true )
{
// Blocking read will throw on a signal
int rc = 0;
std::cout << "Polling" << std::endl;
rc = zmq::poll (items, 3, -1);
zmq::message_t message;
if(rc > 0)
{
if (items [0].revents & ZMQ_POLLIN)
{
requester1.recv(&message);
}
if (items [1].revents & ZMQ_POLLIN)
{
requester2.recv(&message);
}
if(items [2].revents & ZMQ_POLLIN)
{
std::cout << "message stop received " << std::endl;
break;
}
}
}
requester1.setsockopt(ZMQ_LINGER, 0);
requester2.setsockopt(ZMQ_LINGER, 0);
stop_socket.setsockopt(ZMQ_LINGER, 0);
requester1.close();
requester2.close();
stop_socket.close();
std::cout << "Thread end" << std::endl;
}
int main(void)
{
std::cout << "Begin" << std::endl;
s_catch_signals ();
zmq::context_t context (1);
zmq::socket_t router(context,ZMQ_ROUTER);
router.bind("tcp://127.0.0.1:36483");
std::thread t(&thread);
t.join();
std::cout << "end join" << std::endl;
}
Note that if you do not want to share the context to the signal handler you could use "ipc://..." .
If you wish to preserve the feel of ZMQ's Actor model in handling signals, you could use the signalfd interface on Linux: signalfd manpage. That way you could use zmq poll to wait for the signal to be delivered, instead of having a signal handler.
It has the added advantage that when handling a signal delivered through a file descriptor, you can call any function you like, because you're handling it synchronously, not asynchronously.

C++ thread-per-request chat on linux with sockets and multiple clients

we are learning how to work with sockets and threads and are trying to make a simple chat program. Multiple clients can successfully connect and all of them can receive messages, but only the first connecting client can send messages.
So client nr 1 completely works, and all others can only receive but not send to the server.
All threads are running like we think they should, but only the first receiving thread is able to read from the receive queue.
with netstat we can see that the message queue of the second client is full
screenshot from netstat
#include <iostream>
#include "socket.hpp"
#include <string>
#include <queue>
#include <unistd.h>
using namespace std;
int clients[100];//All Clientnumbers
int i=0;//Number of connected Clients
Socket* sockArray[100];
Socket* sockArray2[100];
queue<string> nachrichten;//message queue
void *empfangen(void* x);
void *tpr(void* servsockp);
int main()
{
cout << "Hello, World! Server startet" << endl;
ServerSocket servSock(6200, 1000);//start Serversocket
ServerSocket *servsockp = &servSock;
pthread_t tpr_starter;//new thread that creates tpr
pthread_create(&tpr_starter, NULL, tpr,(void*)servsockp);
while(true) //if there are messages in the queue send them to all clients
{
if(nachrichten.size()!=0)
{
for (int y = 0; y < i; y++)
{
try
{
cout<< "Gesendet: " << nachrichten.front() <<clients[0]<<clients[1]<<i<< endl;
(*sockArray[y]).send(nachrichten.front());
} catch (SocketException e) {
cout << e.getError() << endl;
}
}
nachrichten.pop();
}
}
pthread_join(tpr_starter, NULL);
}
void*tpr(void* servsockp)//open socket for every request, start new receiving thread
{
while(true)
{
clients[i]= (*(ServerSocket*)(servsockp)).accept();
int*x =new int(i);
Socket *sock = new Socket(clients[i]);
sockArray[i]=sock;
sockArray2[i]=sock;
i++;
sleep(2);
pthread_t rec;
pthread_create (&rec, NULL, empfangen, (void*)x);
}
}
void *empfangen(void* x)//listening on new socket, put received messages in queue
{
int number=*(int*)x;
cout <<"Receiving/thread started on Socket Nr: "<< number<<endl;
while(true){
try {
string nachricht = (*sockArray2)[number].recv();
if(nachricht=="")
{
break;
}
cout <<"Received: "<< nachricht << endl;
nachrichten.push(nachricht);
}catch(SocketException e){
cout << e.getError()<<endl;
}
}
}
Can anyone tell if we are on the right way or if we are doing something completely wrong?
Thank you!
Today my professor found the solution:
(*sockArray2)[number].recv();
this line is absolutely wrong, it has to be
sockArray2[number]->recv();

"Connection was broken" error with UDT (UDP-based data transfer protocol)

I am programming a real-time game in which I need reliable UDP, so I've chosen to work with UDT (UDP-based data transfer protocol - http://sourceforge.net/projects/udt/).
The clients (on browsers) send real-time messages to my server via CGI scripts. The problem is that there are some messages that are being lost, and I don't know why because the server says that it sent all the messages successfully to the corresponding clients, but sometimes the client doesn't receive the message.
In my debug file, I've found that when a message is not received by the client, its script says:
error in recv();
recv: Connection was broken.
I would like to get some help on how the server shall know if the client got its message; should I send a NACK or something from the client side? I thought that UDT should do that for me. Can someone clarify this situation?
The relevant sections of the communication parts of my code are bellow, with some comments:
server's relevant code:
//...
void send_msg_in(player cur, char* xml){
/*this function stores the current message, xml, in a queue if xml!=NULL, and sends the 1st message of the queue to the client*/
/*this function is called when the player connects with the entering xml=NULL to get the 1st message of the queue,
or with xml!=NULL when a new message arrives: in this case the message is stored in the queue, and then the message will be sent in the appropriate time, i.e. the messages are ordered.*/
char* msg_ptr=NULL;
if (xml!=NULL){ //add the message to a queue (FIFO), the cur.xml_msgs
msg_ptr=(char*) calloc(strlen(xml)+1, sizeof(char));
strcpy(msg_ptr, xml);
(*(cur.xml_msgs)).push(msg_ptr);
} //get the 1st message of the queue
if (!(*(cur.xml_msgs)).empty()){
xml=(*(cur.xml_msgs)).front();
}
if (cur.get_udt_socket_in()!=NULL){
UDTSOCKET cur_udt = *(cur.get_udt_socket_in());
// cout << "send_msg_in(), cur_udt: " << cur_udt << endl;
//send the "xml", i.e. the 1st message of the queue...
if (UDT::ERROR == UDT::send(cur_udt, xml, strlen(xml)+1, 0)){
UDT::close(cur_udt);
cur.set_udt_socket_in(NULL);
}
else{ //if no error this else is reached
cout << "TO client:\n" << xml << "\n"; /*if there is no error,
i.e. on success, the server prints the message that was sent.*/
// / \
// /_!_\
/*the problem is that
the messages that are lost don't appear on the client side,
but they appear here on the server! */
if (((string) xml).find("<ack.>")==string::npos){
UDT::close(cur_udt);
cur.set_udt_socket_in(NULL); //close the socket
}
(*(cur.xml_msgs)).pop();
}
}
}
//...
client's relevant code:
//...
#define MSGBUFSIZE 1024
char msgbuf[MSGBUFSIZE];
UDTSOCKET client;
ofstream myfile;
//...
main(int argc, char *argv[]){
//...
// connect to the server, implict bind
if (UDT::ERROR == UDT::connect(client, (sockaddr*)&serv_addr, sizeof(serv_addr))){
cout << "error in connect();" << endl;
return 0;
}
myfile.open("./log.txt", ios::app);
send(xml);
char* cur_xml;
do{
cur_xml = receive(); //wait for an ACK or a new message...
myfile << cur_xml << endl << endl; // / \
/* /_!_\ the lost messages don't appear on the website
neither on this log file.*/
} while (((string) cur_xml).find("<ack.>")!=string::npos);
cout << cur_xml << endl;
myfile.close();
UDT::close(client);
return 0;
}
char* receive(){
if (UDT::ERROR == UDT::recv(client, msgbuf, MSGBUFSIZE, 0)){
// / \
/* /_!_\ when a message is not well received
this code is usually reached, and an error is printed.*/
cout << "error in recv();" << endl;
myfile << "error in recv();" << endl;
myfile << "recv: " << UDT::getlasterror().getErrorMessage() << endl << endl;
return 0;
}
return msgbuf;
}
void* send(string xml){
if (UDT::ERROR == UDT::send(client, xml.c_str(), strlen(xml.c_str())+1, 0)){
cout << "error in send();" << endl;
myfile << "error in send();" << endl;
myfile << "send: " << UDT::getlasterror().getErrorMessage() << endl << endl;
return 0;
}
}
Thank you for any help!
PS. I tried to increase the linger time on close(), after finding the link http://udt.sourceforge.net/udt4/doc/opt.htm, adding the following to the server's code:
struct linger l;
l.l_onoff = 1;
l.l_linger = ...; //a huge value in seconds...
UDT::setsockopt(*udt_socket_ptr, 0, UDT_LINGER, &l, sizeof(l));
but the problem is still the same...
PPS. the other parts of the communication in the server side are: (note: it seams for me that they are not so relevant)
main(int argc, char *argv[]){
char msgbuf[MSGBUFSIZE];
UDTSOCKET serv = UDT::socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in my_addr;
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(PORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
memset(&(my_addr.sin_zero), '\0', sizeof(my_addr.sin_zero));
if (UDT::ERROR == UDT::bind(serv, (sockaddr*)&my_addr, sizeof(my_addr))){
cout << "error in bind();";
return 0;
}
UDT::listen(serv, 1);
int namelen;
sockaddr_in their_addr;
while (true){
UDTSOCKET recver = UDT::accept(serv, (sockaddr*)&their_addr, &namelen);
if (UDT::ERROR == UDT::recv(recver, msgbuf, MSGBUFSIZE, 0)){
//this recv() function is called only once for each aqccept(), because the clients call CGI scripts via a browser, they need to call a new CGI script with a new UDT socket for each request (this in in agreement to the clients' code presented before).
cout << "error in recv();" << endl;
}
char* player_xml = (char*) &msgbuf;
cur_result = process_request((char*) &msgbuf, &recver, verbose); //ACK
}
}
struct result process_request(char* xml, UDTSOCKET* udt_socket_ptr, bool verbose){
//parse the XML...
//...
player* cur_ptr = get_player(me); //searches in a vector of player, according to the string "me" of the XML parsing.
UDTSOCKET* udt_ptr = (UDTSOCKET*) calloc(1, sizeof(UDTSOCKET));
memcpy(udt_ptr, udt_socket_ptr, sizeof(UDTSOCKET));
if (cur_ptr==NULL){
//register the player:
player* this_player = (player*) calloc(1, sizeof(player));
//...
}
}
else if (strcmp(request_type.c_str(), "info_waitformsg")==0){
if (udt_ptr!=NULL){
cur_ptr->set_udt_socket_in(udt_ptr);
if (!(*(cur_ptr->xml_msgs)).empty()){
send_msg_in(*cur_ptr, NULL, true);
}
}
}
else{ //messages that get instant response from the server.
if (udt_ptr!=NULL){
cur_ptr->set_udt_socket_out(udt_ptr);
}
if (strcmp(request_type.c_str(), "info_chat")==0){
info_chat cur_info;
to_object(&cur_info, me, request_type, msg_ptr); //convert the XML string values to a struct
process_chat_msg(cur_info, xml);
}
/* else if (...){ //other types of messages...
}*/
}
}
void process_chat_msg(info_chat cur_info, char* xml_in){
player* player_ptr=get_player(cur_info.me);
if (player_ptr){
int i=search_in_matches(matches, cur_info.match_ID);
if (i>=0){
match* cur_match=matches[i];
vector<player*> players_in = cur_match->followers;
int n=players_in.size();
for (int i=0; i<n; i++){
if (players_in[i]!=msg_owner){
send_msg_in(*(players_in[i]), xml, flag);
}
}
}
}
}
Looking at the UDT source code at http://sourceforge.net/p/udt/git/ci/master/tree/udt4/src/core.cpp, the error message "Connection was broken" is produced when either of the Boolean flags m_bBroken or m_bClosing is true and there is no data in the receive buffer.
Those flags are set in just a few cases:
In sections of code marked "should not happen; attack or bug" (unlikely)
In deliberate close or shutdown actions (don't see this happening in your code)
In expiration of a timer that checks for peer activity (the likely culprit)
In that source file at line 2593 it says:
// Connection is broken.
// UDT does not signal any information about this instead of to stop quietly.
// Application will detect this when it calls any UDT methods next time.
//
m_bClosing = true;
m_bBroken = true;
// ...[code omitted]...
// app can call any UDT API to learn the connection_broken error
Looking at the send() call, I don't see anywhere that it waits for an ACK or NAK from the peer before returning, so I don't think a successful return from send() on the server side is indicative of successful receipt of the message by the client.
You didn't show the code on the server side that binds to the socket and listens for responses from the client; if the problem is there then the server might be happily sending messages and never listening to the client that is trying to respond.
UDP is not a guaranteed-transmission protocol. A host will send a message, but if the recipient does not receive it, or if it is not received properly, no error will be raised. Therefore, it is commonly used in applications that require speed over perfect delivery, such as games. TCP does guarantee delivery, because it requires that a connection be set up first, and each message is acknowledged by the client.
I would encourage you to think about whether you actually need guaranteed receipt of that data, and, if you do, consider using TCP.

Make socket server accept multiple clients

I'd like to change the socket class I am using to accept an infinite amount of clients. At the moment it allows one client, and once that client disconnect the server exits.
#include "stdafx.h"
#include "mySocket.h"
#include "myException.h"
#include "myHostInfo.h"
void main()
{
#ifdef WINDOWS_XP
// Initialize the winsock library
WSADATA wsaData;
try
{
if (WSAStartup(0x101, &wsaData))
{
myException* initializationException = new myException(0,"Error: calling WSAStartup()");
throw initializationException;
}
}
catch(myException* excp)
{
excp->response();
delete excp;
exit(1);
}
#endif
// get local server information
myHostInfo uHostAddress;
string localHostName = uHostAddress.getHostName();
string localHostAddr = uHostAddress.getHostIPAddress();
cout << "------------------------------------------------------" << endl;
cout << " My local host information:" << endl;
cout << " Name: " << localHostName << endl;
cout << " Address: " << localHostAddr << endl;
cout << "------------------------------------------------------" << endl;
// open socket on the local host
myTcpSocket myServer(PORTNUM);
cout << myServer;
myServer.bindSocket();
cout << endl << "server finishes binding process... " << endl;
myServer.listenToClient();
cout << "server is listening to the port ... " << endl;
// wait to accept a client connection.
// processing is suspended until the client connects
cout << "server is waiting for client connecction ... " << endl;
myTcpSocket* client; // connection dedicated for client communication
string clientHost; // client name etc.
client = myServer.acceptClient(clientHost);
cout << endl << "==> A client from [" << clientHost << "] is connected!" << endl << endl;
while(1)
{
//Send message to the client
client->sendMessage(std::string("Test"));
// receive from the client
string clientMessageIn = "";
int numBytes = client->recieveMessage(clientMessageIn); //Get message from client, non-blocking using select()
if ( numBytes == -99 ) break;
if(clientMessageIn != "")
{
std::cout << "received: " << clientMessageIn << std::endl; //What did we receive?
/* Do somethign with message received here */
}
}
#ifdef WINDOWS_XP
// Close the winsock library
try
{
if (WSACleanup())
{
myException* cleanupException = new myException(0,"Error: calling WSACleanup()");
throw cleanupException;
}
}
catch(myException* excp)
{
excp->response();
delete excp;
exit(1);
}
#endif
}
How do I change the main() function so that it is constantly waiting for new clients to connect, and once they do, create a new thread for him (the client), or a new handler socket (whatever that may be).
I did find this thread to be informative, but I lack the required knowledge of sockets to actually implement it in the above code.
The answer states When doing socket communication, you basically have a single listener socket for all incoming connections, and multiple handler sockets for each connected client.
So I am guessing in my code;
myTcpSocket myServer(PORTNUM);
myServer.bindSocket();
myServer.listenToClient();
Would be the listener socket
But where/how would I fork the client who is connecting off to a handler socket ?
I am sorry for not being able to show more effort on my part, I don't like coming across as lazy. But for all the hours I have searched and the trial and error resulting from that, I don't have much to show for it.
The idea is simple, you just wait for incoming connections, and once accepted, pass the socket to a thread.
You need to pass the new socket returned from accept to the new thread; you could either spawn a new thread everytime and pass the socket via argument or add the socket to a shared queue used by a bunch of worker threads.
Here's some code for a simple proxy I wrote, it uses boost for the threads and a simple OOP wrapper around the socket functions.
The main thread - it creates 4 worker threads which idle and wait for
the semaphore to be signalled. It pushes all accepted connections to a global queue:
// Global variables
const size_t MAX_THREADS = 4;
queue<Socket> socketBuffer; // Holds new accepted sockets
boost::mutex queueGuard; // Guards the socketBuffer queue
semaphore queueIndicator; // Signals a new connection to the worker threads
bool ctrlc_pressed = false;
// Inside the main function...
boost::thread_group threads;
for(int i = 0; i < MAX_THREADS; i++)
{
threads.create_thread(boost::bind(&threadHandleRequest, i+1));
}
while(!ctrlc_pressed)
{
// wait for incoming connections and pass them to the worker threads
Socket s_connection = s_server.accept();
if(s_connection.valid())
{
boost::unique_lock<boost::mutex> lock(queueGuard);
socketBuffer.push(s_connection);
queueIndicator.signal();
}
}
threads.interrupt_all(); // interrupt the threads (at queueGuard.wait())
threads.join_all(); // wait for all threads to finish
s_server.close();
And the thread code:
bool threadHandleRequest(int tid)
{
while(true)
{
// wait for a semaphore counter > 0 and automatically decrease the counter
try
{
queueIndicator.wait();
}
catch (boost::thread_interrupted)
{
return false;
}
boost::unique_lock<boost::mutex> lock(queueGuard);
assert(!socketBuffer.empty());
Socket s_client = socketBuffer.front();
socketBuffer.pop();
lock.unlock();
// Do whatever you need to do with the socket here
}
}
Hope that helps :)
When doing socket communication, you basically have a single listener
socket for all incoming connections, and multiple handler sockets for
each connected client.
That's the point. You need a separate thread for the listener socket. When it receives an incoming request, it starts another thread for a handler socket (which will create and send the response), and starts listening again (you need a loop).
I would definitely use threads instead of forking. AFAIK on Windows only cygwin is able to fork, but I would not use cygwin for such a program.

How can I receive multipart messages with ZeroMQ?

I can't get ZeroMQ C++ wrapper to receive multipart messages. The same code using C version works just fine, but it leads to an exception with no explanations at all with C++. The multipart handling code is as follows:
int _tmain(int argc, _TCHAR* argv[])
{
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_REP);
socket.bind("tcp://*:5555");
while(true) {
// the following two lines lead to exception
zmq::message_t request;
socket.recv(&request);
//zmq_msg_t message;
//zmq_msg_init (&message);
//zmq_recv (socket, &message, 0);
}
return 0;
}
It is extremely simple; this version does not work. but if I comment out the first two lines in the while loop and uncomment the currently commented (C version) code, it works.
This is Windows XP sp3, Zeromq 2.1.1 and Visual Studio 2010 Express.
If I send single part messages, both versions work fine.
What am I doing wrong?
I'm also a newbie in ZMQ and I too had to struggle a lot in order to understand multipart messaging using REP/REQ in ZeroMQ. I had to go through multiple resources and stitch data in order to understand this. I think this answer will help many seekers in the near future that's why I am sharing the client and server code here. I have tested this code and it is working perfectly fine. However, being a newbie there are chances that I would have missed something vital. Please share your valuable inputs.
Server Code
void
serverMultipartREPREQ()
{
try
{
zmq::context_t context(1);
zmq::socket_t socket(context, ZMQ_REP);
socket.bind("tcp://*:5556");
std::cout << "Listening at port 5556..." << std::endl;
zmq::message_t reply;
socket.recv(reply, zmq::recv_flags::none);
auto rep = std::string(static_cast<char*> (reply.data()), reply.size());
std::cout << "Received: " << rep << std::endl;
while(1)
{
if (input == "exit")
break;
for (int j = 0; j < 3; ++j)
{
std::string s("Message no - " + std::to_string(j));
zmq::message_t message(s.length());
memcpy(message.data(), s.c_str(), s.length());
std::cout << "Sending: " << s << std::endl;
if (j != 2)
socket.send(message, zmq::send_flags::sndmore);
else
socket.send(message, zmq::send_flags::none);
}
}
}
catch (const zmq::error_t& ze)
{
std::cout << "Exception: " << ze.what() << std::endl;
}
Sleep(5000);
}
Client code
void
clientMultipartREQREP()
{
try
{
zmq::context_t context(1);
std::cout << "Connecting to socket at 5556" << std::endl;
zmq::socket_t socket(context, ZMQ_REQ);
socket.connect("tcp://localhost:5556");
std::cout << "Connected to socket at 5556" << std::endl;
std::string msg("Hii this is client...");
zmq::message_t message(msg.length());
memcpy(message.data(), msg.c_str(), msg.length());
socket.send(message, zmq::send_flags::none); // send to server (request message)
while (true)
{
__int64 more = 1;
if (more)
{
zmq::message_t message;
socket.recv(message, zmq::recv_flags::none);
auto rep = std::string(static_cast<char*> (message.data()), message.size());
std::cout << "Reading from client: " << rep << std::endl;
size_t size = sizeof(__int64);
socket.getsockopt(ZMQ_RCVMORE, &more, &size); // if msg is not the last one then more = 1 else more = 0
}
else
{
std::cout << "Done..." << std::endl;
break;
}
}
}
catch (const zmq::error_t& ze)
{
std::cout << "Exception: " << ze.what() << std::endl;
}
Sleep(5000);
}
Probably C version of code doesn't work either, but you don't check the return code of zmq_recv, so you don't notice it. Also, when receiving miltipart messages you should check if there are more message parts to be received through the socket, like this:
int64_t more = 0;
size_t more_size = sizeof(more);
socket.getsockopt(ZMQ_RCVMORE, &more, &more_size);
if (more != 0)
{
//has more parts
}
Also, take a look at ZmqMessage C++ library designed specifically for Sending and receiving ZeroMQ multipart messages.
I decided to use the C version of the code. In general all examples seem to be in C anyway.