ZMQ [java]

java中ZMQ的用法

简介

ZMQ是基于C语言实现的消息队列, 可用TCP或UDP实现. JeroMQ是其java实现, 首先导入maven:

 <!-- https://mvnrepository.com/artifact/org.zeromq/jeromq -->
<dependency>
     <groupId>org.zeromq</groupId>
     <artifactId>jeromq</artifactId>
     <version>0.5.3</version>
</dependency>

使用

请求-响应模式

该模式由客户端和服务端组成, 必须是问了再答, 答了再问

  • 客户端: 发送 -> 接收 --> 发送 --> ...
  • 服务端: 接收 --> 发送 --> 接收 --> ...

服务端

服务端监听8888的tcp连接

public class Response {
    public static void main(String args[]) throws InterruptedException {
        ZMQ.Context context = ZMQ.context(1);     //I/O线程上下文的数量为1
        ZMQ.Socket socket = context.socket(ZMQ.REP);         //ZMQ.REP表示这是一个reponse类型的socket
        socket.bind("tcp://*:8888");                 //绑定到8888端口
        while (true) {
            byte[] request = socket.recv();
            if (new String(request).equals("END"))
                break;
            System.out.println("Response recv:\t" + new String(request));
            String response = "I got it";
            Thread.sleep(3000);
            socket.send(response.getBytes());
        }
        //关闭
        socket.close();
        context.term();
    }
}

客户端

public class Request {
    public static void main(String args[]) {
        ZMQ.Context context = ZMQ.context(1);     //I/O线程上下文的数量为1
        ZMQ.Socket socket = context.socket(ZMQ.REQ);         //ZMQ.REQ表示这是一个request类型的socket
        socket.connect("tcp://127.0.0.1:8888");      //连接到8888端口
        for (int i = 0; i < 10; i++) {
            long now = System.currentTimeMillis();
            String request = "hello, time is " + now;
            socket.send(request.getBytes());
            byte[] response = socket.recv();
            System.out.println("Request recv:\t" + new String(response));
        }
        socket.send("END".getBytes());

        //关闭
        socket.close();
        context.term();
    }
}

发布-订阅模式

该服务器一直发, 客户端订阅后就可以接受服务器消息了.

服务端(发布者)

服务端只需发送以Time和Order开头的消息

public class Server {
    public static void main(String[] args) {
        try (ZContext context = new ZContext()) {
            ZMQ.Socket publisher = context.createSocket(ZMQ.PUB); //publish类型
            publisher.bind("tcp://*:5555");

            Random random = new Random();
            while (true) {
                String update;
                //随机将update赋值为Time: 或Order: 开头的值
                if (random.nextInt(10) <= 5)
                    update = "Time: " + System.currentTimeMillis();
                else
                    update = "Order: " + System.currentTimeMillis();
                publisher.send(update); //发送
                System.out.println("SEND:[" + update + "]");
            }
        }
    }
}

客户端(订阅者)

客户端只订阅以Time开头的

public class Client {
    public static void main(String args[]) {
        try (ZContext context = new ZContext()) {
            ZMQ.Socket subscriber = context.createSocket(ZMQ.SUB); //subscribe类型
            subscriber.connect("tcp://localhost:5555");

            subscriber.subscribe("Time:".getBytes()); //只订阅Time: 开头的信息

            for (int i = 0; i < 1000; i++) {
                System.out.println(subscriber.recvStr()); //recvStr直接返回String,内部调用了recv,将byte数组转化为String
            }
        }

    }
}

router/dealer模式

Router和Dealer搭配使用时,必须都需要设置router id。发送给Router或Dealer的消息模型如下:

  • Router接收的消息模型:[router_id][空帧][数据帧]
  • Router发送的消息模型:[router_id][空帧][数据帧]
  • Router发送到网络上的数据:[router_id][数据帧]
  • Dealer接收的消息模型:[数据帧]
  • Dealer发送的消息模型:[空帧][数据帧]

Dealer就像是一个异步的REQ,而Router就像一个异步的REP。所以可以相互使用。Router做代理可以提供可靠的模式来分别识别客户端和后端服务器

import org.zeromq.SocketType;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;

public class Client {
    public static void main(String[] args) {
        try (ZContext context = new ZContext()) {
            // 创建ROUTER套接字作为服务端
            // 创建DEALER套接字作为客户端
            ZMQ.Socket client = context.createSocket(SocketType.DEALER);
            // 连接到服务端
            client.connect("tcp://localhost:5560");

            // 客户端发送多个请求
            client.setIdentity(new String("wang").getBytes());
            for (int i = 0; i < 3; i++) {
                client.send("Hello " + i);
            }
            while (true) {
                String message = client.recvStr();
                if (message == null) {
                    continue;
                }
                System.out.println("Received: " + message);
            }
        }
    }
}


import org.zeromq.SocketType;
import org.zeromq.ZContext;
import org.zeromq.ZMQ;
import org.zeromq.ZMsg;

public class Server {
    public static void main(String[] args) {
        try (ZContext context = new ZContext()) {
            // 创建ROUTER套接字作为服务端
            ZMQ.Socket server = context.createSocket(SocketType.ROUTER);
            // 绑定到端口5560
            server.bind("tcp://*:5560");

            // 服务端接收请求并发送回复

            int i = 0;
            server.setIdentity(new String("wang").getBytes());
            while (true) {
                ZMsg zMsg = ZMsg.recvMsg(server);
                if (zMsg == null) {
                    continue;
                }
                System.out.println("recv: " + zMsg);

                ZMsg zMsg1 = new ZMsg();
                zMsg1.add(new String("wang").getBytes());
                zMsg1.add("abc " + i++);
                zMsg1.send(server);
            }

        }
    }
}
recv: [ wang, Hello 0 ]
recv: [ wang, Hello 1 ]
recv: [ wang, Hello 2 ]
=================================
Received: abc 0
Received: abc 1
Received: abc 2
posted @ 2023-03-28 00:53  shmilyt  阅读(275)  评论(0编辑  收藏  举报