NetMQ學習一

1:zeromq是什麼

NetMQ (ZeroMQ to .Net),ZMQ號稱史上最快中間件。
它對socket通信進行了封裝,使得我們不需要寫socket函數調用就能完成複雜的網絡通信。
它跟Socket的區別是:普通的socket是端到端的(1:1的關係),而ZMQ卻是可以N:M的關係,人們對BSD套接字的瞭解較多的是點對點的連接,點對點連接需要顯式地建立連接、銷燬連接、選擇協議(TCP/UDP)和處理錯誤等,而ZMQ屏蔽了這些細節,讓你的網絡編程更爲簡單。
它是一個消息處理隊列庫,可在多個線程、內核和主機盒之間彈性伸縮。和一般意義上的消息隊列產品不同的是,它沒有消息隊列服務器,而更像是一個網絡通信庫。從網絡通信的角度看,它處於會話層之上,應用層之下,屬於傳輸層。

2:zeromq的消息模型

zeromq將消息通信分爲4種模型,分別是一對一結對模型(Exclusive-Pair)、請求迴應模型(Request-Reply)、發佈訂閱模型(Publish-Subscribe)、推拉模型(Push-Pull)。這4種模型總結出了通用的網絡通信模型,在實際中可以根據應用需要,組合其中的2種或多種模型來形成自己的解決方案。

2.1 一對一結對模型 Exclusive-Pair

最簡單的1:1消息通信模型,用來支持傳統的 TCP socket模型,主要用於進程內部線程間通信。可以認爲是一個TCP Connection,但是TCP Server只能接受一個連接。採用了lock free實現,速度很快。數據可以雙向流動,這點不同於後面的請求響應模型。(不推薦使用,沒有例子)

2.2 請求迴應模型 Request-Reply

由請求端發起請求,然後等待迴應端應答。一個請求必須對應一個迴應,從請求端的角度來看是發-收配對,從迴應端的角度是收-發對。跟一對一結對模型的區別在於請求端可以是1~N個。
請求端和迴應端都可以是1:N的模型。通常把1認爲是server,N認爲是ClientZeroMQ可以很好的支持路由功能(實現路由功能的組件叫作Device),把1:N擴展爲N:M(只需要加入若干路由節點)。從這個模型看,更底層的端點地址是對上層隱藏的。每個請求都隱含有迴應地址,而應用則不關心它。通常把該模型主要用於遠程調用及任務分配等。

2.3 發佈訂閱模型 Publisher-Subscriber

發佈端單向分發數據,且不關心是否把全部信息發送給訂閱端。如果發佈端開始發佈信息時,訂閱端尚未連接上來,則這些信息會被直接丟棄。訂閱端未連接導致信息丟失的問題,可以通過與請求迴應模型組合來解決。訂閱端只負責接收,而不能反饋,且在訂閱端消費速度慢於發佈端的情況下,會在訂閱端堆積數據。該模型主要用於數據分發。天氣預報、微博明星粉絲可以應用這種經典模型。 

2.4 推拉模型 Push-Pull

Server端作爲Push端,而Client端作爲Pull端,如果有多個Client端同時連接到Server端,則Server端會在內部做一個負載均衡,採用平均分配的算法,將所有消息均衡發佈到Client端上。與發佈訂閱模型相比,推拉模型在沒有消費者的情況下,發佈的消息不會被消耗掉;在消費者能力不夠的情況下,能夠提供多消費者並行消費解決方案。該模型主要用於多任務並行。

3:zeromq的優勢

  • TCP:ZeroMQ基於消息,消息模式,而非字節流。
  • XMPP:ZeroMQ更簡單、快速、更底層。Jabber可建在ZeroMQ之上。
  • AMQP:完成相同的工作,ZeroMQ要快100倍,而且不需要代理(規範更簡潔——少278頁)
  • IPC:ZeroMQ可以跨多個主機盒,而非單臺機器。
  • CORBA:ZeroMQ不會將複雜到恐怖的消息格式強加於你。
  • RPC:ZeroMQ完全是異步的,你可以隨時增加/刪除參與者。
  • RFC 1149:ZeroMQ比它快多了!
  • 29west LBM:ZeroMQ是自由軟件!
  • IBM低延遲:ZeroMQ是自由軟件!
  • Tibco:仍然是自由軟件!
4:實現代碼

對NetMQ進行封裝,使用
<package id="AsyncIO" version="0.1.26.0" targetFramework="net452" />
<package id="NetMQ" version="4.0.0.1" targetFramework="net452" />
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MessageQueueUseNetMQ
{
    public interface IMyPublisher:IDisposable
    {
        void Publish(string topicName, string data);
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MessageQueueUseNetMQ
{
    public interface IMySubscriber:IDisposable
    {
        event Action<string,string> Notify;

        void RegisterSubscriber(List<string> topics);

        void RegisterSubscriberAll();

        void RemoveSubscriberAll();
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NetMQ;
using NetMQ.Sockets;

namespace MessageQueueUseNetMQ.Implement
{
    public class MyPublisher:IMyPublisher
    {
        private object _lockObj=new object();
        private PublisherSocket _publisher = null;

        public MyPublisher(string endpoint)
        {
            _publisher=new PublisherSocket();
            _publisher.Options.SendHighWatermark = 1000;
            _publisher.Bind(endpoint);
        }

        public void Dispose()
        {
            lock (_lockObj)
            {
                _publisher.Close();
                _publisher.Dispose();
            }
        }

        public void Publish(string topicName, string data)
        {
            lock (_lockObj)
            {
                _publisher.SendMoreFrame(topicName).SendFrame(data);
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NetMQ;
using NetMQ.Sockets;

namespace MessageQueueUseNetMQ.Implement
{
    public class MySubscriber : IMySubscriber
    {
        private SubscriberSocket _subSocket = null;
        private string _endpoint = null;
        public MySubscriber(string endpoint)
        {
            _subSocket = new SubscriberSocket();
            _endpoint = endpoint;
        }

        public void Dispose()
        {
            InnerStop();
        }

        public event Action<string, string> Notify = delegate { };

        public void RegisterSubscriber(List<string> topics)
        {
            InnerRegisterSubscriber(topics);
        }

        public void RegisterSubscriberAll()
        {
            InnerRegisterSubscriber();

        }

        public void RemoveSubscriberAll()
        {
            InnerStop();
        }

        private void InnerRegisterSubscriber(List<string> topics=null)
        {
            InnerStop();
            _subSocket = new SubscriberSocket();
            _subSocket.Options.ReceiveHighWatermark = 1000;
            _subSocket.Connect(_endpoint);
            if (topics == null)
            {
                _subSocket.SubscribeToAnyTopic();
            }
            else
            {
                topics.ForEach(item=>_subSocket.Subscribe(item));
            }
            Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    string messageTopicReceived = _subSocket.ReceiveFrameString();
                    string messageReceived = _subSocket.ReceiveFrameString();
                    Notify(messageTopicReceived, messageReceived);
                }
            });
        }

        private void InnerStop()
        {
            _subSocket.Close();
        }


    }
}
測試代碼

publisher
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using MessageQueueUseNetMQ;
using MessageQueueUseNetMQ.Implement;

namespace publisher
{
    /// <summary>
    /// MainWindow.xaml 的交互邏輯
    /// </summary>
    public partial class MainWindow : Window
    {
        private IMyPublisher _myPublisher = null;
        public MainWindow()
        {
            InitializeComponent();
            _myPublisher=new MyPublisher(IpAddressCommonStr.Publisher_IP_Address);
        }

        private void button_Click(object sender, RoutedEventArgs e)
        {
            string record = String.Format("{0}\t{1}", System.DateTime.Now, this.textBox.Text.Trim());
            _myPublisher.Publish("publisher",record);
            this.listBox.Items.Add(record);
        }
    }
}
subsriber
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using MessageQueueUseNetMQ;
using MessageQueueUseNetMQ.Implement;

namespace subscriber
{
    /// <summary>
    /// MainWindow.xaml 的交互邏輯
    /// </summary>
    public partial class MainWindow : Window
    {
        private IMySubscriber _mySubscriber = null;
        public MainWindow()
        {
            InitializeComponent();
            _mySubscriber=new MySubscriber(IpAddressCommonStr.Subscriber_IP_Address);
            _mySubscriber.RegisterSubscriberAll();
            _mySubscriber.Notify += OnmySubscriber_Notify;
            
        }

        private void OnmySubscriber_Notify(string arg1, string arg2)
        {
            this.listBox.Dispatcher.BeginInvoke((Action) (() => this.listBox.Items.Add(arg2)));
        }
    }
}
測試效果









發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章