zeromq / cppzmq

Header-only C++ binding for libzmq
http://www.zeromq.org
MIT License
1.94k stars 757 forks source link

Connecting a socket to an address using 0.0.0.0 fails without an exception under Windows #527

Open CDixon0416 opened 2 years ago

CDixon0416 commented 2 years ago

During a port of a project from Centos 7 to Windows 10, I discovered some inconsistent behavior when connecting to a socket using a wildcard address and port. In the client code I manually connected to the port provided by the server code using 0.0.0.0 and no communication occurs, change the string to using localhost and the sockets communicate as expected.

This seems to be a problem that was already seen in libzmq https://github.com/zeromq/libzmq/pull/1920 and persists in cppzmq or at least in version 4.7.1 provided by vcpkg. While its not a huge problem it does mean windows code is required to parse out the port from socket.get(zmq::sockopt::last_endpoint) and change the connection string to use localhost or 127.0.0.1 with out any indicator of what the problem is.

Modified Client and Server code to replicate behavior:

//
//  Hello World client in C++
//  Connects REQ socket to tcp://localhost:5555
//  Sends "Hello" to server, expects "World" back
//
#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::socket_type::req);

    std::cout << "Connecting to hello world server..." << std::endl;
    // Manually change address to port provided by server
    socket.connect ("tcp://0.0.0.0:59474");

    //  Do 10 requests, waiting each time for a response
    for (int request_nbr = 0; request_nbr != 10; request_nbr++) {
        zmq::message_t request (5);
        memcpy (request.data (), "Hello", 5);
        std::cout << "Sending Hello " << request_nbr << "..." << std::endl;
        socket.send (request, zmq::send_flags::none);

        //  Get the reply.
        zmq::message_t reply;
        socket.recv (reply, zmq::recv_flags::none);
        std::cout << "Received World " << request_nbr << std::endl;
    }
    return 0;
}
//
//  Hello World server in C++
//  Binds REP socket to tcp://*:5555
//  Expects "Hello" from client, replies with "World"
//
#include <zmq.hpp>
#include <string>
#include <iostream>
#ifndef _WIN32
#include <unistd.h>
#else
#include <windows.h>

#define sleep(n)    Sleep(n)
#endif

int main () {
    //  Prepare our context and socket
    zmq::context_t context (2);
    zmq::socket_t socket (context, zmq::socket_type::rep);
    socket.bind ("tcp://*:*");

    while (true) {
        zmq::message_t request;

        // Print out actual address for client to use
        std::cout << socket.get(zmq::sockopt::last_endpoint) << std::endl;

        //  Wait for next request from client
        socket.recv (request, zmq::recv_flags::none);
        std::cout << "Received Hello" << std::endl;

        //  Do some 'work'
        sleep(1);

        //  Send reply back to client
        zmq::message_t reply (5);
        memcpy (reply.data (), "World", 5);
        socket.send (reply, zmq::send_flags::none);
    }
    return 0;
}
gummif commented 2 years ago

You can not connect to the any address on Windows (but happens to work and connects to localhost in Linux). Are you suggesting that this should throw an exception on Windows?

CDixon0416 commented 2 years ago

You can not connect to the any address on Windows (but happens to work and connects to localhost in Linux). Are you suggesting that this should throw an exception on Windows?

I think it makes sense, currently there is no indication that something is wrong with the socket it will still attempt to receive without throwing a "socket operation on non-socket error" which I would expect since the connection is invalid.

Or perhaps there needs to be clarification in the documentation somewhere since there is no indication this is not allowed. (At least that I could find)

I think it's an easy enough mistake to make to blindly trust the get(last_endpoint) is going to provide a valid address and be confused as to why it doesn't work under windows.