Hot questions for Using ZeroMQ in visual studio 2013

Top 10 C/C++ Open Source / ZeroMQ / visual studio 2013

Question:

I'm trying to build this simple ZeroMQ server in C++ on Visual Studio 2013.

#include "stdafx.h"
#include "zmq.hpp"
#include <string>
#include <iostream>
#include <windows.h>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    // Prepare context and socket
    zmq::context_t ctx(1);
    zmq::socket_t sckt(ctx, ZMQ_REP);
    sckt.bind("tcp://*:5555");

    while (true) {
        zmq::message_t request;

        // Wait for next request from client
        sckt.recv(&request);
        std::cout << "Received Hello" << endl;
        Sleep(1);

        // Send reply back to client
        zmq::message_t reply(5);
        memcpy((void*)reply.data(), "World", 5);
        sckt.send(reply);
    }
    return EXIT_SUCCESS;
}

However, I'm getting error LNK2019 when I try to build the VS project. Below is the compiler output:

1>ZeroMQServer.obj : error LNK2019: unresolved external symbol __imp__zmq_errno referenced in function "public: __thiscall zmq::error_t::error_t(void)" (??0error_t@zmq@@QAE@XZ)
1>ZeroMQServer.obj : error LNK2019: unresolved external symbol __imp__zmq_strerror referenced in function "public: virtual char const * __thiscall zmq::error_t::what(void)const " (?what@error_t@zmq@@UBEPBDXZ)
1>ZeroMQServer.obj : error LNK2019: unresolved external symbol __imp__zmq_ctx_new referenced in function "public: __thiscall zmq::context_t::context_t(int,int)" (??0context_t@zmq@@QAE@HH@Z)
1>ZeroMQServer.obj : error LNK2019: unresolved external symbol __imp__zmq_ctx_set referenced in function "public: __thiscall zmq::context_t::context_t(int,int)" (??0context_t@zmq@@QAE@HH@Z)
1>ZeroMQServer.obj : error LNK2019: unresolved external symbol __imp__zmq_ctx_destroy referenced in function "public: void __thiscall zmq::context_t::close(void)" (?close@context_t@zmq@@QAEXXZ)
1>ZeroMQServer.obj : error LNK2019: unresolved external symbol __imp__zmq_msg_init referenced in function "public: __thiscall zmq::message_t::message_t(void)" (??0message_t@zmq@@QAE@XZ)
1>ZeroMQServer.obj : error LNK2019: unresolved external symbol __imp__zmq_msg_init_size referenced in function "public: __thiscall zmq::message_t::message_t(unsigned int)" (??0message_t@zmq@@QAE@I@Z)
1>ZeroMQServer.obj : error LNK2019: unresolved external symbol __imp__zmq_msg_send referenced in function "public: bool __thiscall zmq::socket_t::send(class zmq::message_t &,int)" (?send@socket_t@zmq@@QAE_NAAVmessage_t@2@H@Z)
1>ZeroMQServer.obj : error LNK2019: unresolved external symbol __imp__zmq_msg_recv referenced in function "public: bool __thiscall zmq::socket_t::recv(class zmq::message_t *,int)" (?recv@socket_t@zmq@@QAE_NPAVmessage_t@2@H@Z)
1>ZeroMQServer.obj : error LNK2019: unresolved external symbol __imp__zmq_msg_close referenced in function "public: __thiscall zmq::message_t::~message_t(void)" (??1message_t@zmq@@QAE@XZ)
1>ZeroMQServer.obj : error LNK2019: unresolved external symbol __imp__zmq_msg_data referenced in function "public: void * __thiscall zmq::message_t::data(void)" (?data@message_t@zmq@@QAEPAXXZ)
1>ZeroMQServer.obj : error LNK2019: unresolved external symbol __imp__zmq_socket referenced in function "public: __thiscall zmq::socket_t::socket_t(class zmq::context_t &,int)" (??0socket_t@zmq@@QAE@AAVcontext_t@1@H@Z)
1>ZeroMQServer.obj : error LNK2019: unresolved external symbol __imp__zmq_close referenced in function "public: void __thiscall zmq::socket_t::close(void)" (?close@socket_t@zmq@@QAEXXZ)
1>ZeroMQServer.obj : error LNK2019: unresolved external symbol __imp__zmq_bind referenced in function "public: void __thiscall zmq::socket_t::bind(char const *)" (?bind@socket_t@zmq@@QAEXPBD@Z)
1>D:\[ Source Code ]\C++\ZeroMQServer\Debug\ZeroMQServer.exe : fatal error LNK1120: 14 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

I have installed the ZeroMQ binary v4.0.4 and updated the VS project properties to point to ZeroMQ's include and lib paths. Specifically, this is what I have updated in the project properties (I suspect some of these settings may be redundant):

  1. Configuration Properties > VC++ Directories > Include Directories: Added '$(ZEROMQ_HOME)\include'
  2. Configuration Properties > VC++ Directories > Library Directories: Added '$(ZEROMQ_HOME)\lib'
  3. Configuration Properties > C/C++ > General > Additional Include Directories: Added '$(ZEROMQ_HOME)\include'
  4. Configuration Properties > Linker > Input > Additional Dependencies: Added 'libzmq-v120-mt-4_0_4.lib;libzmq-v120-mt-gd-4_0_4.lib'

I'm on Win 7, 64-bit Edition. Please help me resolve this.


Answer:

According to the library names on zeromq.org, you are trying to link the same library twice: first with the release version, and then with the debug versions.

Remove libzmq-v120-mt-gd-4_0_4.lib from your Release configuration, and remove libzmq-v120-mt-4_0_4.lib from your Debug configuration.

Question:

I have recently started a new project with the Pupil eyetracker. To broadcast the tracking information to additional clients they use ZeroMQ. I have verified that their server is correctly running by trying their simple Python client example:

import zmq
import json

#network setup
port = "5000"
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect("tcp://127.0.0.1:"+port)

# recv all messages
socket.setsockopt(zmq.SUBSCRIBE, '')

while True:
    topic =  socket.recv_multipart()
    #msg = json.loads(topic)
    print  "\n\n",topic[0] #,":\n",msg

Since my project should be a C++ I have tried translating it in C++ using ZeroMQ examples like this:

#include "zmq.hpp"
#include <string>
#include <iostream>

int main()
{
    //  Prepare our context and socket
    zmq::context_t context(1);
    zmq::socket_t socket(context, ZMQ_SUB);

    std::cout << "Connecting to hello world server" << std::endl;
    socket.connect("tcp://127.0.0.1:5000");

    socket.setsockopt(ZMQ_SUBSCRIBE, "");

    //  Do 100 requests, waiting each time for a response
    for (int request_nbr = 0; request_nbr != 100; request_nbr++) {

        //  Get the message.
        zmq::message_t msg;
        socket.recv(&msg);
        std::cout << "Received World " << msg.data() << std::endl;
    }
    return 0;
}

Unfortunately this does not work, the C++ client just hangs at socket.recv(&msg); waiting for a message it never receives.

For the project I am using Visual Studio 2013 and the ZeroMQ library libzmq-v120-mt-4_0_4.lib which came with the ZeroMQ installation (I did not compile it). To set it up I used this tutorial, not pasting it whole because I find it a bit irrelevant.

The configuration I use is x64 whereas Pupil's is 32bit, I think, but this should be irrelevant for ZeroMQ if I am not mistaken.

Pupil uses pyzmq which should be compatible with 4.04 zmq lib.


Answer:

For some reason, still unknown to me, the wrapper zmq.hpp is not working in my case. Using a solution from the book which does not use this helper solcer the issue for me

int main(int argc, char *argv[])
{
    void *context = zmq_ctx_new();

    //  Socket to talk to server
    void *subscriber = zmq_socket(context, ZMQ_SUB);
    int rc = zmq_connect(subscriber, "tcp://127.0.0.1:5000");
    assert(rc == 0);

    rc = zmq_setsockopt(subscriber, ZMQ_SUBSCRIBE, "", strlen(""));
    assert(rc == 0);

    //  Process 100 updates
    int update_nbr;
    long total_temp = 0;
    for (update_nbr = 0; update_nbr < 100; update_nbr++) {
        char msg[256];
        rc = zmq_recv(subscriber, msg, 256, 0);
        std::cout << "Received World " << msg << std::endl;
    }

    zmq_close(subscriber);
    zmq_ctx_destroy(context);
    return 0;
}

Question:

I'm trying to get ZeroMQ to work with my C++ project. I want to do the ZeroMQ Hello World tutorial, shown below:

//  Hello World server
#include <zmq.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>

int main (void)
{
    //  Socket to talk to clients
    void *context = zmq_ctx_new ();
    void *responder = zmq_socket (context, ZMQ_REP);
    int rc = zmq_bind (responder, "tcp://*:5555");
    assert (rc == 0);

    while (1) {
        char buffer [10];
        zmq_recv (responder, buffer, 10, 0);
        printf ("Received Hello\n");
        sleep (1);          //  Do some 'work'
        zmq_send (responder, "World", 5, 0);
    }
    return 0;
}

However, whenever I try to compile and run it, Visual Studio says it can't find zmq.h or any of the ZeroMQ methods I am using. I already installed ZeroMQ from http://zeromq.org/distro:microsoft-windows, what else do I have to do to get it to work?


Answer:

Including the headers:


  • Right click Project -> Properties -> C/C++ -> General
  • Edit 'Additional Include Directories'
  • Add C:\Program Files\ZeroMQ 4.0.4\include
  • Right click 'Header Files' -> Add -> Existing Item -> C:\Program Files\ZeroMQ 4.0.4\include\zmq.h

Adding the library dir:


  • Right click Project -> Properties -> Linker -> General
  • Edit 'Additional Library Directories'
  • Add C:\Program Files\ZeroMQ 4.0.4\lib\

Linking to the proper library:


  • Right click Project -> Properties -> General
  • Check "Platform Toolset", notice the version number (ex: v120)
  • Configuration Properties -> Linker -> Input
  • Edit 'Additional Dependencies'
  • Add appopriate toolset library (ex: libzmq-v120-mt-gd-4_0_4.lib) "-gd-" is the debug version

Ensure your app is 64-bit


  • Build -> Configuration Manager
  • Active solution platform -> New...
  • Select x64
  • Copy settings from Win32
  • Right click Project -> Properties -> Linker -> All Options
  • Edit "Output File" set to ".\x64\Debug\whatever.exe"

Include the pre-compiled dll as a resource for distribution


  • Right click Project -> Properties -> Build Events -> Post-Build Event
  • Edit "Command Line"
  • insert copy command

ex:

copy /Y "C:\Program Files\ZeroMQ 4.0.4\bin\libzmq-v120-mt-gd-4_0_4.dll" "$(OutDir)"

Question:

I'm trying to use a zeromq socket as a raw TCP client socket in C++. I have a TCP server in a different program which I would like to send data to. When I connect my Zeromq client to the server, I am able to receive data from the server but unable to send data to the TCP server. When sending I get the following error: Unhandled error, zmq::error_t Have any idea how to make it work?

zmq::context_t *ctx = new zmq::context(100, 100);
void *raw_socket = new zmq::socket_t(*ctx, ZMQ_STREAM);
zmq::socket_t *socket = static_cast<zmq::socket_t*>(raw_socket);

socket->connect("tcp://127.0.0.1:5555");

char message[] = "HELLO, WORLD!"
socket->send(message, strlen(message), ZMQ_SNDMORE)

Answer:

When you send or receive anything on a ZMQ_STREAM type socket the first data frame should be an identifier that indicates where the subsequent frames should go or where they came from.

When using the ZMQ_STREAM socket as a server (i.e you call bind on the socket) then you can just extract this identity frame with recv and resend it when you respond.

When used as a client (i.e you call connect on the socket) then you need to obtain the identity from the socket, you can do this via getsockopt with the ZMQ_IDENTITY flag.

The identity size is limited to a maximum of 255 bytes.

// get the id after you've called connect
std::size_t id_size = 256;
char id[ 256 ];
socket->getsockopt( ZMQ_IDENTITY, &id, &id_size );

// send the id frame
socket->send(id, id_size, ZMQ_SNDMORE);

// then your data
char message[] = "HELLO, WORLD!";
socket->send(message, strlen(message), ZMQ_SNDMORE);

The documentation on ZMQ_STREAM goes into more detail about how you'll be notified and control connections, disconnections etc.

Question:

I'm building zeromq 4.0.5. I need a 64-bit static build. I'm using VS2013. When I go into the configuration manager and change the platform to x64 the platform for libzmq remains Win32. If I manually change that one to x64 and close the dialog, it is back at Win32 when I open it again. Why? How do I get it to x64?


Answer:

I resolved my issue by editing the project file (.vcxproj). I went through made an x64 entry for every win32 entry.

For example, I found this entry:

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='StaticRelease|Win32'" Label="Configuration">
    <ConfigurationType>StaticLibrary</ConfigurationType>
    <CharacterSet>MultiByte</CharacterSet>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <PlatformToolset>v120</PlatformToolset>
</PropertyGroup>

So I added this entry:

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='StaticRelease|x64'" Label="Configuration">
    <ConfigurationType>StaticLibrary</ConfigurationType>
    <CharacterSet>MultiByte</CharacterSet>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <PlatformToolset>v120</PlatformToolset>
</PropertyGroup>

There were probably around a dozen entries that needed to be added. No changes other than Win32->x64 were made for the entries.