ZeroMQ基本模式

最近看了一下ZeroMQ,把一些只是记录下来,以供后面复习。
当然最好的学习文档还是官方的手册zguide

1,请求应答模式

Req-Rep
请求应答模式是一种常用的通信模式,每次请求和应答都是有顺序要求的,每个请求都要有一个应答。
如果一次发送两条请求,那么就会返回-1.

代码如下:
服务端.cs

 		static void Main(string[] args)
        {
            if(args == null || args.Length < 1)
            {
                args = new string[] { "World" };
            }

            string name = args[0];

            // Create
            using (var context = new ZContext())
            using (var responder = new ZSocket(context, ZSocketType.REP))
            {
                // Bind
                responder.Bind("tcp://*:5555");

                while(true)
                {
                    // Receive
                    using (ZFrame request = responder.ReceiveFrame())
                    {
                        Console.WriteLine("Received {0}",request.ReadString());

                        // Do some work
                        Thread.Sleep(1);

                        // Send
                        responder.Send(new ZFrame(name));
                    }
                }
            }
        }

客户端.cs

		static void Main(string[] args)
        {

            if(args == null || args.Length < 1)
            {
                args = new string[] { "tcp://127.0.0.1:5555" };
            }

            string endpoint = args[0];

            // Create
            using (var context = new ZContext())
            using (var requester = new ZSocket(context, ZSocketType.REQ))
            {
                // Connect
                requester.Connect(endpoint);

                for(int n = 0; n < 10; ++n)
                {
                    string requestText = "Hello";
                    Console.Write("Sending {0}", requestText);

                    // Send
                    requester.Send(new ZFrame(requestText));

                    // Receive
                    using (ZFrame reply = requester.ReceiveFrame())
                    {
                        Console.WriteLine(" Receive: {0} {1} !", requestText, reply.ReadString());
                    }
                }
            }

            Console.ReadKey();
        }

几点说明

  1. 代码比较简单,只是说清楚请求应答模式,客户端你可以增长到成百上千个也能稳定的执行。
    ZeroMQ是一个工具,通过它你可以来打造一艘航空母舰。
  2. 只是这样不是一个可靠的连接,如果中间重启服务端,那客户端并不能正确的接收数据。
  3. 对于传输的数据,ZeroMQ出了长度,其他的并不知道。这就需要你自己定义协议来保证数据的解析。
  4. 对于字符串,ZeroMQ不会带有字符串结束标志。
2,发布订阅模式

Pub-Sub
上图可以很明白的理解发布订阅模式,这种模式是异步的。这种情况下,不知道接收端何时开始接收到消息的,即便先启动订阅端,因为订阅端连接到发布端也是需要时间的(这段时间,发布端已经发送了消息)。

发布端.cs

 		static void Main(string[] args)
        {

            // Create
            using (var context = new ZContext())
            using (var pubScoket = new ZSocket(context, ZSocketType.PUB))
            {
                // 绑定当个地址
                string address = "tcp://*:5566";
                Console.WriteLine("Publisher.Bind'ing on {0}", address);
                pubScoket.Bind(address);

                // 绑定到多个地址
                // ……

                while (true)
                {
                    string data = "发送内容";

                    // 发送内容
                    using (var updateFrame = new ZFrame(data))
                    {
                        pubScoket.Send(updateFrame);
                    }
                }
            }
        }

订阅端.cs

        static void Main(string[] args)
        {

            // 初始化Socket
            using (var context = new ZContext())
            using (var subScoket = new ZSocket(context, ZSocketType.SUB))
            {

                // 连接到发布端
                string address = "tcp://*:5556";

                subScoket.Connect(address);

                *// 发送订阅请求
                string subCode = "subCode";
                subScoket.Subscribe(subCode);
                
				// 接收发布端发来的消息
                for (int i = 0; i < 20; i++)
                {
                    using (var replyFrame = subScoket.ReceiveFrame())
                    {
                        string reply = replyFrame.ReadString();
                        // 处理消息
                    }
                }

            }
        }

几点说明

  1. 订阅端可以同时连接多个服务端,交叉接收服务端的消息(公平排队)
  2. 如果没有订阅者,则优雅的丢掉消息。
  3. 从ZeroMQ v3.x开始,使用连接协议(tcp:// 或者 ipc:// )则在发布端进行过滤;使用epgm:// 协议则在订阅端进行过滤。在ZeroMQ v2.x 中,所有过滤都在订阅端进行。
3,并行管道模式

Parallel Pipeline
从图中可以看出任务是并行在执行,并且工作节点是可以动态增加的。任务发布节点和统计节点相对固定的。
任务发布.cs

        static void Main(string[] args)
        {
            // Task Ventilator
            // Sends batch of tasks to workers via that socket

            using(var context = new ZContext())
            using (var sender = new ZSocket(context, ZSocketType.PUSH))
            using (var sink = new ZSocket(context, ZSocketType.PUSH))
            {
                sender.Bind("tcp://*:5557");
                sink.Connect("tcp://127.0.0.1:5558");

				*//wait
                Console.WriteLine("Press Enter when the workers are ready……");
                Console.ReadKey(true);
                Console.WriteLine("Sending tasks to workers……");

                // The first message is "0" and signals start of batch
                sink.Send(new byte[] { 0x00 }, 0, 1);

                // Initialize random number generator
                var rnd = new Random();

                // Send 100 tasks
                int i = 0;
                long total_msec = 0; //Total expected cost in msecs
                for (; i < 100; i++)
                {
                    // Random workload from 1 to 100msecs
                    int workload = rnd.Next(100) + 1;
                    total_msec += workload;
                    byte[] action = BitConverter.GetBytes(workload);
                    Console.WriteLine("{0}", workload);
                    sender.Send(action, 0, action.Length);
                }

                Console.WriteLine("Total expected cost: {0} ms", total_msec);
            }
        }

工作节点.cs

        static void Main(string[] args)
        {
            //
            // Task worker
            // Connects PULL socket to tcp://127.0.0.1:5557
            // Collects workloads from ventilator via that socket
            // Connects PUSH socket to tcp://127.0.0.1:5558
            // Sends results to sink via that socket
            //

            using (var context = new ZContext())
            using (var pull = new ZSocket(context, ZSocketType.PULL))
            using (var sink = new ZSocket(context, ZSocketType.PUSH))
            {
                pull.Connect("tcp://127.0.0.1:5557");
                sink.Connect("tcp://127.0.0.1:5558");

                // Process tasks forever
                while (true)
                {
                    // Receive one Task
                    var replyBytes = new byte[4];
                    pull.ReceiveBytes(replyBytes, 0, replyBytes.Length);
                    // Show progress
                    int workload = BitConverter.ToInt32(replyBytes, 0);
                    Console.WriteLine("{0}.", workload);
                    // Do the work
                    Thread.Sleep(workload);
                    // Send results to sink
                    sink.Send(new byte[0], 0, 0);    
                }
            }
        }

统计节点.cs

		static void Main(string[] args)
        {
            // Task sink
            // Binds PULL socket to tcp://127.0.0.1:5558
            // Collects results from workers via that socket
            //

            using (var context = new ZContext())
            using (var sink = new ZSocket(context, ZSocketType.PULL))
            {
                sink.Bind("tcp://127.0.0.1:5558");

                // wait for start of batch
                sink.ReceiveFrame();

                // start our clock now
                var stopwatch = new Stopwatch();
                stopwatch.Start();

                // process 100 confirmations
                for (int i = 0; i < 100; i++)
                {
                    sink.ReceiveFrame();

                    if ((i / 10) * 10 == i)
                        Console.Write(":");
                    else
                    {
                        Console.Write(".");
                    }
                }

                // Calculate and report duration of batch
                stopwatch.Stop();
                Console.WriteLine("Total elapsed time: {0} ms", stopwatch.ElapsedMilliseconds);
            }
        }

总结,这个只是入门,并不能应用到实际的项目中,ZeroMQ是一组API,使用它可以构建一个复杂的系统,可扩展性强,在多线程应用中也会更为复杂。
可以发现,ZeroMQ应用程序总是从创建 ZContext 开始,然后创建套接字。ZContext是单个进程中所有套接字的容器,使得消息能够在线程间以最快的速度传输。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值