package guide; import java.util.LinkedList; import java.util.Queue; import org.zeromq.*; import org.zeromq.ZMQ.PollItem; import org.zeromq.ZMQ.Socket; class ClientThread3 extends Thread { @Override public void run() { // Prepare our context and sockets try (ZContext context = new ZContext()) { Socket client = context.createSocket(SocketType.REQ); // Initialize random number generator client.connect("ipc://frontend.ipc"); // Send request, get reply while (true) { client.send("HELLO".getBytes(ZMQ.CHARSET), 0); byte[] data = client.recv(0); if (data == null) break; String reply = new String(data, ZMQ.CHARSET); try { Thread.sleep(1000); } catch (InterruptedException e) { } System.out.println( Thread.currentThread().getName() + " Client Sent HELLO" ); } } } } class WorkerThread3 extends Thread { @Override public void run() { // Prepare our context and sockets try (ZContext context = new ZContext()) { Socket worker = context.createSocket(SocketType.REQ); worker.connect("ipc://backend.ipc"); ZFrame frame = new ZFrame(lruqueue3.LRU_READY); // Tell backend we're ready for work frame.send(worker, 0); while (true) { ZMsg msg = ZMsg.recvMsg(worker); if (msg == null) break; msg.getLast().reset("OK".getBytes(ZMQ.CHARSET)); msg.send(worker); System.out.println( Thread.currentThread().getName() + " Worker Sent OK" ); } } } } //Our LRU queue structure, passed to reactor handlers class LRUQueueArg { Socket frontend; // Listen to clients Socket backend; // Listen to workers Queue workers; // List of ready workers }; //In the reactor design, each time a message arrives on a socket, the //reactor passes it to a handler function. We have two handlers; one //for the frontend, one for the backend: class FrontendHandler implements ZLoop.IZLoopHandler { @Override public int handle(ZLoop loop, PollItem item, Object arg_) { LRUQueueArg arg = (LRUQueueArg) arg_; ZMsg msg = ZMsg.recvMsg(arg.frontend); if (msg != null) { msg.wrap(arg.workers.poll()); msg.send(arg.backend); // Cancel reader on frontend if we went from 1 to 0 workers if (arg.workers.size() == 0) { PollItem poller = new PollItem(arg.frontend, ZMQ.Poller.POLLIN); loop.removePoller(poller); } } return 0; } } class BackendHandler implements ZLoop.IZLoopHandler { @Override public int handle(ZLoop loop, PollItem item, Object arg_) { LRUQueueArg arg = (LRUQueueArg) arg_; ZMsg msg = ZMsg.recvMsg(arg.backend); if (msg != null) { ZFrame address = msg.unwrap(); // Queue worker address for LRU routing arg.workers.add(address); // Enable reader on frontend if we went from 0 to 1 workers if (arg.workers.size() == 1) { PollItem poller = new PollItem(arg.frontend, ZMQ.Poller.POLLIN); loop.addPoller(poller, lruqueue3.handle_frontend, arg); } // Forward message to client if it's not a READY ZFrame frame = msg.getFirst(); if (new String(frame.getData(), ZMQ.CHARSET).equals(lruqueue3.LRU_READY)) msg.destroy(); else msg.send(arg.frontend); } return 0; } } public class lruqueue3 { public final static String LRU_READY = "\001"; protected final static FrontendHandler handle_frontend = new FrontendHandler(); protected final static BackendHandler handle_backend = new BackendHandler(); public static void main(String[] args) { // Prepare our context and sockets try (ZContext context = new ZContext()) { LRUQueueArg arg = new LRUQueueArg(); Socket frontend = context.createSocket(SocketType.ROUTER); Socket backend = context.createSocket(SocketType.ROUTER); arg.frontend = frontend; arg.backend = backend; frontend.bind("ipc://frontend.ipc"); backend.bind("ipc://backend.ipc"); int client_nbr; for (client_nbr = 0; client_nbr < 10; client_nbr++) new ClientThread3().start(); int worker_nbr; for (worker_nbr = 0; worker_nbr < 3; worker_nbr++) new WorkerThread3().start(); // Queue of available workers arg.workers = new LinkedList(); // Prepare reactor and fire it up ZLoop reactor = new ZLoop(context); reactor.verbose(true); PollItem poller = new PollItem(arg.backend, ZMQ.Poller.POLLIN); reactor.addPoller(poller, handle_backend, arg); reactor.start(); for (ZFrame frame : arg.workers) { frame.destroy(); } } System.exit(0); } }