上文詳細討論了MQ的使用方法,MQ做爲一種信息存儲機制,將消息存儲到了隊列中,這樣在作分佈式架構時能夠考慮將消息傳送到MQ服務器上,而後開發相應的服務組件獲取MQ中的消息,自動獲取傳送的消息,將消息發送給處理的程序。那麼上文就MQ作了詳細的討論,並無介紹有關服務組件的內容,也就是說若是咱們開發的程序想要實現自動的消息接收和推送的服務的話,這裏就必須考慮使用Windows Service來實現了,Windows Service是一種實時運行的組件,能夠實時處理消息,該篇文章將會討論Windows Service的開發方法。
1、WS理論篇
MQ和WS技術相結合其實就能夠看作是一個簡單的ESB程序,這樣能夠經過調用服務來實現消息中間件的處理功能,能夠開發包括消息推送、接收、處理的應用程序。WS是在Windows操做系統中才會有的,是集成到系統中的,一個WS在開啓後會一直運行,直到中止該WS。在具體的項目中開發的WS是做爲組件存在的,也就是說系統中的某部分須要實時運行,這時候能夠考慮開發WS組件。web
1.1 windows service VS web service
那麼這裏須要思考一個問題,windows Service和web Service它們兩個都是服務,可是服務的對象是不一樣的。在web應用程序中web service是一個行業的信息服務標準,它爲web應用程序之間架設了一個橋樑,使得應用程序之間能夠互相的交流通訊,也就是說web service是在web分佈式應用中必然會用到的技術。
相較下來windows Service就比較狹窄了,它只能在windows system中運行,能夠爲windows的應用提供功能服務上的支持,在開發windows Service時經常會考慮兩種狀況,一是運行的組件考慮須要實時運行,另外是組件能夠須要被多個程序調用,好比常常在開發中用到的sql server,它有不少子程序,這些程序之間會共用某個功能,因此此時就把它作成了一個服務。
1.2 ws開發
ws的組成是比較簡單的,由於它自己固有的屬性不多,大部分功能是經過調用其它的類庫或者組件來組合功能,具體的ws的組成以下導圖所示:
在開發ws時會有兩個大的部分,分別是Service和Installer,Service是服務的內部功能邏輯,也就是服務的本體,服務要作的操做都是寫到裏面的;Installer是服務的安裝部分,也就是配置了該服務在windows中顯示的屬性。
Service:繼承自ServiceBase,其中包括服務全部的運行內容,開發界面相似於winForm中的自定義控件的開發,可以添加系統控件及第三方控件。
Installer:分爲兩種,其中的serviceProcessInstaller配置服務的被調用的用戶類型,serviceInstaller配置服務自己屬性,如服務名稱、服務啓動方法等。
2、WS Demo
上文對WS的基本內容作了詳細的瞭解,經過理論來指導實踐,這樣在開發的時候思路纔可以很清晰,關於WS的理論部分這裏再也不詳細的討論,接下來咱們開發一個簡單的WS Demo。
上篇文章詳細討論了MQ的開發方法,並開發了一個簡單的MQ項目,這裏就繼續使用上文的MQ的項目來開發一個對MQ消息處理的WS組件,該組件主要是負責處理消息隊列中的信息,獲取消息,並把消息的主題內容保存到文本中。
具體程序的分佈圖以下所示:
2.1 服務代碼
上面的程序分佈圖是結合上文的MQ來繪製的詳細的架構圖,其中的數據發送部分的程序在上文已經有介紹,這裏再也不詳細討論,下面的代碼就是演示了分佈圖中的Service Handle data和Save data部分的功能,具體功能以下代碼:sql
- using System;
- using System.IO;
- using System.ServiceProcess;
- using System.Threading;
- using System.Timers;
- using System.Messaging;
-
-
- namespace WindowsService1
- {
- public partial class Service1 : ServiceBase
- {
-
- private MessageQueue queue;
- public Service1()
- {
- InitializeComponent();
-
-
- string strpath = ".\\Private$\\EKTestQueue";
-
- queue= new MessageQueue(strpath);
-
- queue.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
- }
-
-
-
-
-
-
- protected override void OnStart(string[] args)
- {
-
- Thread.Sleep(30000);
- }
-
-
-
-
- protected override void OnStop()
- {
- }
-
-
-
- private void GetAndWriteMessage()
- {
-
- var ms=queue.Receive();
-
- if (ms!=null)
- {
- this.AddTextLine(ms.Body.ToString());
- }
- }
-
-
-
-
-
- private void AddTextLine(string line)
- {
- try
- {
-
- FileStream file=new FileStream("D:\\Message.txt",FileMode.OpenOrCreate,FileAccess.ReadWrite);
-
- StreamWriter writer=new StreamWriter(file);
- writer.BaseStream.Seek(0, SeekOrigin.End);
- writer.WriteLine(line+"\r\n");
- writer.Flush();
- writer.Close();
- file.Close();
- file.Dispose();
- }
- catch (Exception ex)
- {
- throw new Exception(ex.Message);
- }
- }
-
-
- private void timer1_Elapsed(object sender, ElapsedEventArgs e)
- {
- GetAndWriteMessage();
- }
- }
- }
using System;
using System.IO;
using System.ServiceProcess;
using System.Threading;
using System.Timers;
using System.Messaging;
namespace WindowsService1
{
public partial class Service1 : ServiceBase
{
//declare a MQ
private MessageQueue queue;
public Service1()
{
InitializeComponent();
//create a path for queue
string strpath = ".\\Private$\\EKTestQueue";
//create a messagequeue and assign a path for this queue
queue= new MessageQueue(strpath);
//the queue formatter that can get queuebody based on the formatter
queue.Formatter = new XmlMessageFormatter(new Type[] { typeof(string) });
}
/// <summary>
/// service start event
/// when we start this service then it will run this method
/// </summary>
/// <param name="args"></param>
protected override void OnStart(string[] args)
{
//used to debug the code when start this service
Thread.Sleep(30000);
}
/// <summary>
/// service stop event
/// </summary>
protected override void OnStop()
{
}
/// <summary>
/// get message from queue and save the message to file
/// </summary>
private void GetAndWriteMessage()
{
//recevie a new one MQ
var ms=queue.Receive();
//save the data to file
if (ms!=null)
{
this.AddTextLine(ms.Body.ToString());
}
}
/// <summary>
/// save the MQ message to file
/// </summary>
/// <param name="line">the message that want save</param>
private void AddTextLine(string line)
{
try
{
//save the message to Message.txt file
FileStream file=new FileStream("D:\\Message.txt",FileMode.OpenOrCreate,FileAccess.ReadWrite);
StreamWriter writer=new StreamWriter(file);
writer.BaseStream.Seek(0, SeekOrigin.End);
writer.WriteLine(line+"\r\n");
writer.Flush();
writer.Close();
file.Close();
file.Dispose();
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
private void timer1_Elapsed(object sender, ElapsedEventArgs e)
{
GetAndWriteMessage();
}
}
}
上面的代碼主要是在服務中添加了信息處理的模塊,這樣就可以實現時時獲取queue中的數據並對數據進行操做。
Note1:在服務的OnStart事件中添加了Thread.Sleep(3000)是爲了調試服務啓動代碼而存在的,由於服務啓動的時候是很快的也就是說咱們在調試代碼時常常會將項目附加到服務中,可是這時候服務是已經啓動的了,是沒有辦法調試它的,因此咱們添加了改行代碼,這樣就能夠延遲服務的啓動時間,給咱們製造了充足的時間將代碼附加到服務中來調試服務的啓動代碼。
Note2:Timer控件,該控件必定要是System.Timers.Timer控件,由於在添加時可能會誤添加爲在Thread命名空間下載Timer控件,這樣就會致使服務在啓動時出錯,不能正常註冊該控件。
2.2 服務調試
在開發完成服務後不可以直接運行使用,而是要將服務安裝到系統的Services中才可以查看服務是否正常運行,由於服務不一樣於通常的應用程序,想要使用服務就必須將服務安裝到系統當中。另外服務的調試也是很麻煩的一件事,由於服務不一樣於應用程序,想要調試它就不能採用普通的調試方法了,這裏介紹一種附加進程的調試方法,還有其它如寫日誌等的調試方法,能夠查看網上的文章來詳細瞭解。
windows
2.2.1 安裝服務
首先要打開控制檯並進入到C:/Windows/Microsoft.Net/Framework/v4.0.30319中,運行InstallUtil.exe工具,並添加相應的開發的服務程序,而後回車運行就能夠安裝,以下所示:服務器
C:/Windows/Microsoft.Net/Framework/v4.0.30319>InstallUtil.exe C:\Code\WindowsService1\WindowsService1\bin\Debug\WindowsService1.exe
安裝完成後查看Services工具中的服務以下圖所示:
架構
安裝後服務顯示的名稱是根據ServiceInstaller的屬性來控制的,在開發時指定了ServiceName屬性名稱爲Jack's Service因此安裝後顯示的服務名稱如上圖所示。
2.2.2 將WS附加到進程
首先打開Tools下面的Attach to Process窗體,而後在程序中找到該服務,具體以下面兩張圖所示:
找到後雙擊該程序便可將添加源碼到服務,這時候就可以對服務的代碼進行調試了。
Note3:在附加進程時,所附加的進程名稱是和服務的程序名稱相一致的,並非和Services工具中的名稱一致。由於該服務程序的名稱爲WindowsServices1因此咱們要把代碼附加到該服務中,如上圖所示。
2.2.3 刪除服務
在不使用服務後也能夠刪除服務,刪除方法相似於服務的安裝,具體方法以下所示:app
C:/Windows/Microsoft.Net/Framework/v4.0.30319>InstallUtil.exe/u C:\Code\WindowsService1\WindowsService1\bin\Debug\WindowsService1.exe
分佈式
結語
文章主要介紹了WS的基本構成,並經過一個具體的示例來演示開發WS時須要注意的地方,最後介紹了一種WS的調試方法,很簡單,可是新手會有不少問題,具體的問題具體分析,能夠留言討論。
WS在分佈式開發中擁有重要做用,它可以協調各個程序以前的交互功能,能夠做爲程序的通訊橋樑,可是WS自己有不少侷限性,它只能運行在Windows系統中,另外WS的代碼調試一直慘遭詬病,須要開發人員一次次的安裝、附加進程、刪除的操做,很耗費時間,因此在作分佈式開發時必定要慎重考慮使用WS。
版權聲明:本文爲博主原創文章,未經博主容許不得轉載。ide