Search code examples
c++linuxzeromqtcpdump

ZMQ push/pull pattern sends messages between two apps but tcpdump shows that source and destination of each packet are the same


I am learning ZMQ. I have created two simple applications that communicates to each other using pull/push pattern. I have created two tap interfaces on my Ubuntu. One of them has IP address 1.1.1.1 and the second tap has IP address 1.1.1.2. Each of these applications sends one string and write to stdout received string. All works as I want to, but when I run tcpdump I see that for each packet, source and destination addresses are the same. tcpdump shows also that ZMQ uses different ports that I set in my applications. This is my code for app 1:

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

using namespace std;
using namespace zmq;

int main()
{
    context_t zmq_context = context_t();

    socket_t zmq_send_socket = socket_t(zmq_context, ZMQ_PUSH);
    socket_t zmq_recv_socket = socket_t(zmq_context, ZMQ_PULL);

    string push_socat = "tcp://1.1.1.2:5001";
    string pull_socat = "tcp://1.1.1.1:5000";   

    zmq_send_socket.bind(push_socat.c_str());
    zmq_recv_socket.connect(pull_socat.c_str());
    
    while(1)
    {
        string msg = "app 1 sends";
        message_t received_message;
        if(msg.size())
        {
            message_t send_message(msg);
            zmq_send_socket.send(send_message, send_flags::dontwait);
        }
        auto result = zmq_recv_socket.recv(received_message, recv_flags::dontwait);
        if (result.has_value())
        {   
            cout<<received_message<<endl;                       
        }   
        std::this_thread::sleep_for(std::chrono::milliseconds(3000));           
    }   

}

This is my code for app 2:

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

using namespace std;
using namespace zmq;

    int main()
        {
            context_t zmq_context = context_t();
        
            socket_t zmq_send_socket = socket_t(zmq_context, ZMQ_PUSH);
            socket_t zmq_recv_socket = socket_t(zmq_context, ZMQ_PULL);
        
            string push_socat = "tcp://1.1.1.1:5000";
            string pull_socat = "tcp://1.1.1.2:5001";   
        
            zmq_send_socket.bind(push_socat.c_str());
            zmq_recv_socket.connect(pull_socat.c_str());
            
            while(1)
            {
                string msg = "app 2 sends";
                message_t received_message;
                if(msg.size())
                {
                    message_t send_message(msg);
                    zmq_send_socket.send(send_message, send_flags::dontwait);
                }
                auto result = zmq_recv_socket.recv(received_message, recv_flags::dontwait);
                if (result.has_value())
                {   
                    cout<<received_message<<endl;                       
                }   
                std::this_thread::sleep_for(std::chrono::milliseconds(3000));           
            }   
        
        }

The app 1 prints "app 2 sends" and the app 2 prints "app 1 sends".

Example output from tcpdump:

22:01:51.724290 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 77: 10.100.100.1.5000 > 10.100.100.1.45624: Flags [P.], seq 649:660, ack 1, win 512, options [nop,nop,TS val 62388355 ecr 62385355], length 11
22:01:51.724325 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 66: 10.100.100.1.45624 > 10.100.100.1.5000: Flags [.], ack 660, win 512, options [nop,nop,TS val 62388355 ecr 62388355], length 0
22:01:51.967303 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 79: 10.100.100.2.5001 > 10.100.100.2.41982: Flags [P.], seq 767:780, ack 1, win 512, options [nop,nop,TS val 2441785963 ecr 2441782963], length 13
22:01:51.967335 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 66: 10.100.100.2.41982 > 10.100.100.2.5001: Flags [.], ack 780, win 512, options [nop,nop,TS val 2441785963 ecr 2441785963], length 0
22:01:54.724516 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 77: 10.100.100.1.5000 > 10.100.100.1.45624: Flags [P.], seq 660:671, ack 1, win 512, options [nop,nop,TS val 62391355 ecr 62388355], length 11
22:01:54.724551 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 66: 10.100.100.1.45624 > 10.100.100.1.5000: Flags [.], ack 671, win 512, options [nop,nop,TS val 62391355 ecr 62391355], length 0
22:01:54.967509 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 79: 10.100.100.2.5001 > 10.100.100.2.41982: Flags [P.], seq 780:793, ack 1, win 512, options [nop,nop,TS val 2441788963 ecr 2441785963], length 13
22:01:54.967542 00:00:00:00:00:00 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 66: 10.100.100.2.41982 > 10.100.100.2.5001: Flags [.], ack 793, win 512, options [nop,nop,TS val 2441788963 ecr 2441788963], length 0

Do you have any idea why sorce and destination addresses are the same, and why I can see strange ports?


Solution

  • Your results you get are expected with your port setup.

    If you look at the bind/connect ports your push/pull pair of sockets both have the same IP address.

    App1
    
      zmq_send_socket.bind(tcp://1.1.1.2:5001)
    
    App2 
    
      zmq_recv_socket.connect(tcp://1.1.1.2:5001);
    

    The "strange" port come from the connect side of the tcp connection. The bind/listen side uses the port you specify (5000/5001) but the connect side will use an ephemeral port.