Skip to content

PUB socket does not send messages and fails silently when using a localhost address #212

@franceschiniandrea

Description

@franceschiniandrea

Description

I noted some weird behavior when running sockets that bind to a localhost port:

  • Binding to tcp://localhost:[port] binds, but a PUB socket on the other end does not receive any messages, while binding to tcp://127.0.0.1:[port] streams frames correctly
  • Binding to tcp://localhost:[port] while another socket is bound to the same port on 127.0.0.1 silently fails instead of throwing an Error

For anyone googling the error, substituting localhost with 127.0.0.1 solves the problem in my case.

Steps to replicate

  • Platform: W11
  • PUB socket in rust, SUB socket in python

Using the stock_broker example, substitute the address with localhost:

use rand::Rng;
use std::time::Duration;
use zeromq::*;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut rng = rand::thread_rng();
    let stocks: Vec<&str> = vec!["AAA", "ABB", "BBB"];
    println!("Starting server");
    let mut socket = zeromq::PubSocket::new();
    socket.bind("tcp://localhost:5556").await?;

    println!("Start sending loop");
    loop {
        for stock in &stocks {
            let price: u32 = rng.gen_range(1..100);
            let mut m: ZmqMessage = ZmqMessage::from(*stock);
            m.push_back(price.to_ne_bytes().to_vec().into());
            println!("Sending: {:?}", m);
            socket.send(m).await?;
        }
        tokio::time::sleep(Duration::from_secs(1)).await;
    }
}

The other hand of the connection (sorry for the python code, it's my main language and I used that to debug the issue)

import zmq
from zmq.asyncio import Context
from zmq.utils import win32
import msgspec

async def main():
    context = Context()
    sock = context.socket(zmq.SUB)
    sock.connect('tcp://localhost:5556')
    sock.subscribe(b"")
    
    while True: 
        print('Waiting for messages from socket...')
        envelope, msg = await sock.recv_multipart()
        print("received", msg)

if __name__ == "__main__": 
    with win32.allow_interrupt():
        import asyncio
        asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
        asyncio.run(main())

This end of the connection will not receive any events unless 127.0.0.1 is used.

Expected Behavior

  • I'm not sure if not being able to bind to localhost is expected - in that case I would add it to the docs (I could not find anything regarding it)
  • Even then, the socket should throw an error when binding to an existing port

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions