【C#网络编程】NetMQ使用示例(二)

示例-05 - ManualThreadingDemo

2f47b4a1d0a34198ac26ea774b53dad0.png

b512dfcd8fce733b459cb76724fcf294.png

手工多线程(客户端副本)demo

源码

using System;
using System.Threading;
using System.Threading.Tasks;
using NetMQ;
using NetMQ.Sockets;


namespace ManualThreadingDemo //手动线程 
{ 
    public class Program
    {
        public void Run()
        {//当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本
         //,而不会影响其它线程所对应的副本。从线程的角度看,目标变量就像是线程的本地变量,这也是类名中“Local”所要表达的意思。
         //   ThreadLocal是线程局部变量,而线程局部变量在多线程场景中应用广泛。


            //NOTES
            //1. Use ThreadLocal<DealerSocket> where each thread has
            //  its own client DealerSocket to talk to server
            //2. Each thread can send using it own socket
            //3. Each thread socket is added to poller
            //1. 使用每个线程都有的 ThreadLocal<DealerSocket>
            // 它自己的客户端 DealerSocket 与服务器对话
            //2。每个线程都可以使用自己的套接字发送
            //3. 每个线程套接字都添加到轮询器
            ThreadLocal<DealerSocket> clientSocketPerThread = 
                new ThreadLocal<DealerSocket>(); //每个线程客户端套接字  经销商套接字
            int delay = 3000;
            Poller poller = new Poller();//套接字轮询器


            using (NetMQContext ctx = NetMQContext.Create())
            {
                using (var server = ctx.CreateRouterSocket())//服务器端  路由器套接字  
                {
                    server.Bind("tcp://127.0.0.1:5556");


                    //start some threads, each with its own DealerSocket
                    //to talk to the server socket. Creates lots of sockets, 
                    //but no nasty race conditions no shared state, each 
                    //thread has its own socket, happy days
                    //启动一些线程,每个线程都有自己的 DealerSocket 与服务器套接字对话。创建很多套接字,
                    //但没有讨厌的竞争条件   没有共享状态, 每个线程都有自己的套接字,快乐的日子
                    for (int i = 0; i < 3; i++)
                    {
                        Task.Factory.StartNew((state) =>
                        {
                            DealerSocket client = null;//客户端套接字


                            if (!clientSocketPerThread.IsValueCreated)//未在当前线程创建客户端套接字
                            {
                                client = ctx.CreateDealerSocket();//创建一个客户端套接字
                                client.Connect("tcp://127.0.0.1:5556");
                                client.ReceiveReady += Client_ReceiveReady;//绑定接收就绪事件处理方法
                                clientSocketPerThread.Value = client;//设置当前线程客户端套接字副本
                                poller.AddSocket(client);//添加到轮询器
                            }
                            else
                            {
                                client = clientSocketPerThread.Value;//已经创建郭当前线程的客户端套接字,直接获取它
                            }


                            while (true)//该线程客户端重复发送字符串 client i 给服务器
                            {
                                var messageToServer = new NetMQMessage(); //创建消息
                                messageToServer.AppendEmptyFrame();//空帧
                                messageToServer.Append(state.ToString());//字符串
                                client.SendMessage(messageToServer);//客户端发送给服务器时自带 地址。路由器套接字
                                Thread.Sleep(delay);
                            }


                        },string.Format("client {0}", i), TaskCreationOptions.LongRunning);
                    }


                    //start the poller  开启轮询任务
                    Task task = Task.Factory.StartNew(poller.Start);


                    //服务器循环
                    while (true)
                    {
                        var clientMessage = server.ReceiveMessage(); //接收每个线程的客户端发来的消息
                        Console.WriteLine("========================");
                        Console.WriteLine(" INCOMING CLIENT MESSAGE ");
                        Console.WriteLine("========================");
                        for (int i = 0; i < clientMessage.FrameCount; i++)
                        {
                            Console.WriteLine("Frame[{0}] = {1}", i,
                                clientMessage[i].ConvertToString());
                        }


                        if (clientMessage.FrameCount == 3)
                        {
                            var clientAddress = clientMessage[0];
                            var clientOriginalMessage = clientMessage[2].ConvertToString();
                            string response = string.Format("{0} back from server {1}",
                                clientOriginalMessage, DateTime.Now.ToLongTimeString());
                            var messageToClient = new NetMQMessage();
                            messageToClient.Append(clientAddress);//服务器发送给客户端时手动添加地址到消息。
                            messageToClient.AppendEmptyFrame();
                            messageToClient.Append(response);
                            server.SendMessage(messageToClient);
                        }
                    }
                }
            }
        }


        void Client_ReceiveReady(object sender, NetMQSocketEventArgs e)
        {
            bool hasmore = false;
            e.Socket.Receive(out hasmore);
            if (hasmore)
            {
                string result = e.Socket.ReceiveString(out hasmore);
                Console.WriteLine("REPLY " + result);
            }
        }


        [STAThread]
        public static void Main(string[] args)
        {
            Program p = new Program();
            p.Run();
        }
    }
}


示例-06 - Divide And Conquer

ffc4cb301ffd90eda9ae017cb75e782c.png

65fcf8f66c7f89185af489ae4ffa1fc6.png

推拉模型demo

运行演示

源码

#Ventilator 
using System;
using NetMQ;


  
namespace Ventilator//任务分发
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Task Ventilator
            // Binds PUSH socket to tcp://localhost:5557
            // Sends batch of tasks to workers via that socket
            //将 PUSH 套接字绑定到 tcp://localhost:5557 通过该套接字向工作人员发送一批任务
            Console.WriteLine("====== VENTILATOR ======");
           
            using (NetMQContext ctx = NetMQContext.Create())
            {
                //用于发送消息的套接字  Push套接字
                using (var sender = ctx.CreatePushSocket())//Push1
                {
                    sender.Bind("tcp://*:5557");


                    using (var sink = ctx.CreatePushSocket())//Push2
                    {
                        sink.Connect("tcp://localhost:5558");//连接 5558 PullSocket


                        Console.WriteLine("Press enter when worker are ready");
                        Console.ReadLine();
                        
                        //the first message it "0" and signals start of batch
                        //see the Sink.csproj Program.cs file for where this is used
                        Console.WriteLine("Sending start of batch to Sink");    
                        sink.Send("0");//Push2发送






                        Console.WriteLine("Sending tasks to workers");


                        //initialise random number generator
                        Random rand= new Random(0);


                        // 预期成本 Ms
                        int totalMs = 0;
                        
                        //send 100 tasks (workload for tasks, is just some random sleep time that
                        //the workers can perform, in real life each work would do more than sleep
                        for (int taskNumber = 0; taskNumber < 100; taskNumber++)
                        {
                            //从 1 到 100 毫秒的随机工作负载
                            int workload = rand.Next(0, 100);
                            totalMs += workload;
                            Console.WriteLine("Workload : {0}", workload);
                            sender.Send(workload.ToString()); //Push1发送
                        }
                        Console.WriteLine("Total expected cost : {0} msec", totalMs);
                        Console.WriteLine("Press Enter to quit");
                        Console.ReadLine();
                    }
                }
            }
        }
    }
}
#Worker 
using System;
using System.Threading;
using NetMQ;




namespace Worker  //工作线程
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Task Worker
            // Connects PULL socket to tcp://localhost:5557
            // collects workload for socket from Ventilator via that socket
            // Connects PUSH socket to tcp://localhost:5558
            // Sends results to Sink via that socket
            Console.WriteLine("====== WORKER ======");




            using (NetMQContext ctx = NetMQContext.Create())
            {
                //用于发送消息的套接字
                using (var receiver = ctx.CreatePullSocket())
                {
                    receiver.Connect("tcp://localhost:5557");


                    //用于发送消息的套接字
                    using (var sender = ctx.CreatePushSocket())
                    {
                        sender.Connect("tcp://localhost:5558");


                        //永远处理任务
                        while (true)
                        {
                            //workload from the vetilator is a simple delay
                            //to simulate some work being done, see
                            //Ventilator.csproj Proram.cs for the workload sent
                            //In real life some more meaningful work would be done
                            string workload = receiver.ReceiveString();


                            //simulate some work being done
                            Thread.Sleep(int.Parse(workload));


                            //send results to sink, sink just needs to know worker
                            //is done, message content is not important, just the precence of
                            //a message means worker is done. 
                            //See Sink.csproj Proram.cs 
                            Console.WriteLine("Sending to Sink");
                            sender.Send(string.Empty);
                        }
                    }


                }
            }


        }
    }
}
#Sink 
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using NetMQ;




namespace Sink
{
    public class Program//推拉模型
    {
        public static void Main(string[] args)
        {


            // Task Sink
            // Bindd PULL socket to tcp://localhost:5558
            // Collects results from workers via that socket
            //将 PULL 套接字绑定到 tcp://localhost:5558 通过该套接字从workers那里收集结果 
            Console.WriteLine("====== SINK ======");
           
            using (NetMQContext ctx = NetMQContext.Create())
            {
                //接收消息的套接字
                using (var receiver = ctx.CreatePullSocket())
                {
                    receiver.Bind("tcp://localhost:5558");


                    //等待批处理开始(参见 Ventilator.csproj Program.cs)
                    var startOfBatchTrigger = receiver.ReceiveString();//批处理触发器的开始 。Ventilator的sink 发来 0. 
                    Console.WriteLine("Seen start of batch");


                    //计时 
                    Stopwatch watch = new Stopwatch();
                    watch.Start();


                    for (int taskNumber = 0; taskNumber < 100; taskNumber++)
                    {
                        var workerDoneTrigger = receiver.ReceiveString();//worker 发来 空帧
                        if (taskNumber % 10 == 0)//十分之一
                        {
                            Console.Write(":");
                        }
                        else
                        {
                            Console.Write(".");//十分之九
                        }
                    }
                    watch.Stop();
                    //计算和报告批处理的持续时间
                    Console.WriteLine();
                    Console.WriteLine("Total elapsed time {0} msec", watch.ElapsedMilliseconds);
                    Console.ReadLine();
                }
            }
        }
    }
}

The End

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值