C# 製作Windows服務安裝包

       這兩天公司要用C#寫一個windows服務,做成安裝安裝包。製作的過程中遇到了一些問題,寫完之後總結一下。如果以後在用到的話可以可以參考一下,而且由於原來沒有做過,不知道這樣做是對是不對,請各位看官如果發現有不當之處請指教。

      開始的時候我的開發工具VS 2012,需要用InstallShield,沒鬧明白,時間緊迫沒有搞,改用vs2010。

      首先創建一個windows服務:

 

      添加安裝程序:     

      設置服務的屬性:  

             這裏面簡單設置一下服務的屬性,ServiceName就是服務的名稱,DispalyName是在本地服務列表中現實的名稱,如果DispalyName沒有設置,那麼默認爲ServiceName。StartType是服務的啓動方式,Automatic爲服務開機啓動,Manual是手動。設置如下:

            

            OK下面開始搞一下服務的邏輯部分

          服務邏輯:

                         

          就是寫一個Soket服務端,在Service1.cd文件中有如下代碼段:

           

1         protected override void OnStart(string[] args)  2         {  3   4         }  5   6         protected override void OnStop()  7         {  8   9         }

          從字面理解也很容易,一個是服務啓動時候一個是服務停止時候調用的方法,

    我定義了一個處理Socket的幫助類SocketHandle.cs 

  1 using System;    2 using System.Collections.Generic;    3 using System.Linq;    4 using System.Text;    5 using System.Net.Sockets;    6 using System.Net;    7 using System.Threading;    8     9 namespace SocketServer   10 {   11     class SocketHandle   12     {   13         private static Socket serverSocket;   14         int pointInt = 8888;   15         private static byte[] result = new byte[1024];   16         private static SocketHandle socketHandle;   17    18         public SocketHandle()   19         {   20    21         }   22    23         public static SocketHandle getInstance()   24         {   25             if (socketHandle == null)   26             {   27                 socketHandle = new SocketHandle();   28             }   29    30             return socketHandle;   31         }   32    33         public void InitSocketServer()   34         {   35             IPAddress localIp = GetLocalIP();   36             if (localIp == null)   37             {   38                 localIp = IPAddress.Parse("127.0.0.1");   39             }   40             try   41             {   42                 if (serverSocket == null)   43                 {   44                     serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);                     45                     serverSocket.Bind(new IPEndPoint(localIp, pointInt));   46                     serverSocket.Listen(10);   47                     Thread myThread = new Thread(ListenClientConnect);   48                     myThread.Start();    49    50                 }   51             }   52             catch (Exception ex)   53             {    54             }   55         }   56    57    58    59         /// <summary>     60         /// 監聽客戶端連接     61         /// </summary>     62         private static void ListenClientConnect()   63         {   64             while (true)   65             {   66                 try   67                 {   68                     Socket clientSocket = serverSocket.Accept();   69                     Thread receiveThread = new Thread(ReceiveMessage);   70                     receiveThread.Start(clientSocket);   71                 }   72                 catch (Exception ex)   73                 {    74                 }   75             }   76         }   77    78    79    80         /// <summary>     81         /// 接收消息     82         /// </summary>     83         /// <param name="clientSocket"></param>     84         private static void ReceiveMessage(object clientSocket)   85         {   86             Socket myClientSocket = (Socket)clientSocket;    87             byte[] bs = new byte[1024];   88             while (true)   89             {   90                 try   91                 {   92                     //通過clientSocket接收數據     93                     int receiveNumber = myClientSocket.Receive(result);   94                     string data = Encoding.ASCII.GetString(result, 0, receiveNumber);   95                     bs = Encoding.ASCII.GetBytes("Receive Data "+data);   96                 }   97                 catch (Exception ex)   98                 {   99                     myClientSocket.Shutdown(SocketShutdown.Both);  100                     myClientSocket.Send(bs, bs.Length, 0);  //返回信息給客戶端  101                     myClientSocket.Close();   102                     break;  103                 }  104                 myClientSocket.Send(bs, bs.Length, 0);  105                 myClientSocket.Close();  106                 break;  107             }  108   109         }  110   111         /// <summary>  112         /// 獲取本地IP地址  113         /// </summary>  114         /// <returns></returns>  115         private IPAddress GetLocalIP()  116         {  117             IPAddress localIp = null;  118             try  119             {  120                 IPAddress[] ipArray;  121                 ipArray = Dns.GetHostAddresses(Dns.GetHostName());  122   123                 localIp = ipArray.First(ip => ip.AddressFamily == AddressFamily.InterNetwork);  124             }  125             catch (Exception ex)  126             {   127             }  128   129             return localIp;  130         }  131     }  132 }

 

 

            在Service1.cs文件中寫成如下形式:

 1 using System;   2 using System.Collections.Generic;   3 using System.ComponentModel;   4 using System.Data;   5 using System.Diagnostics;   6 using System.Linq;   7 using System.ServiceProcess;   8 using System.Text;   9 using System.Threading;  10   11 namespace SocketServer  12 {  13     public partial class Service1 : ServiceBase  14     {  15         private Thread thread;  16   17         public Service1()  18         {  19             InitializeComponent();  20         }  21   22         /// <summary>  23         /// 服務啓動的時候,初始化socket服務。  24         /// </summary>  25         private void RequestHandle()  26         {  27             try  28             {  29                 SocketHandle socketHandle = SocketHandle.getInstance();  30                 socketHandle.InitSocketServer();  31             }  32             catch (Exception ex)  33             {   34             }  35         }  36   37         protected override void OnStart(string[] args)  38         {   39             thread = new Thread(new ThreadStart(this.RequestHandle));  40             thread.Start();  41         }  42   43         protected override void OnStop()  44         {    45             thread.Abort();  46         }  47     }  48 }

         OK,邏輯部分已經完成了,下面看關鍵的操作,將服務打包,首先在本解決方案中添加安裝部署項目,

  創建安裝項目以後是這個樣子的: 

在應用程序文件夾中添加項目輸出:

           選擇SocketServer作爲主輸出:

創建自定義操作:

選擇自定義操作進入到自定義操作界面,在自定義操作上選擇添加自定義操作:

     在彈出的選擇項目中的項對話框中選擇應用程序文件夾中選擇主輸出項目:

 

然後分別重新生成SocketServer和SocketSetUp項目,查看解決方案的屬性,

查看項目的配置,到對應的文件中去找安裝文件,如果是Debug那麼就去對應項目中的Debug目錄下去找生成的文件,我們的目錄是F:\SocketServer,所以得去F:\SocketServer\SocketSetUp\Debug目錄去找安裝文件。

 

下面安裝一下看一下結果。(/ □ \),在安裝的時候讓我填寫服務器名稱密碼什麼的

,按說我自己在電腦上裝東西應該不需要授權啊,回頭在看一下,問題出在安裝程序上,看到serviceProcessInstaller1的屬性的時候發現了授權的信息,Account這個選項中選擇LocalSystem應該就是本地安裝應該是權限最大的不需要額外授權。試試看吧。OK沒有問題,安裝成功。下面看一下咱們的邏輯是不是正確,先看已安裝程序中是不是存在SocketSetUp程序

沒問題,下面在看一下我們SocketServer Release服務是不是運行正常:

沒問題,查看8888端口是不是處於監聽狀態:

沒問題,運行一下Socket客戶端,看一下結果:

   沒問題,這樣就算成功了,但是有個問題,由於服務所要開放的端口很多時候都是需要用戶在安裝的時候指定,那好吧,現在將Socke服務端的端口由用戶指定。

   在安裝項目的視圖中選擇用戶界面,在啓動選項上右鍵添加對話框: 

 

在彈出的添加對話框中選擇文本框,設置文件框的屬性:

這樣文本框就添加完了,文本框屬性很簡單的可以看出來,只需要一個,其他的都隱藏就好了,下面就如何獲取用戶輸入的端口值,在自定義操作中的主輸出xxxxx的屬性選項卡中添加參數

下面只等着接收了,接收之後將指定的端口保存到本地的安裝目錄,這樣還需要設置一個安裝路徑的參數應該是這樣/Port="[PORT]" /targetdir="[TARGETDIR]/"

俺寫了一個XML的幫助類,用來保存端口:

 1 using System;   2 using System.Collections.Generic;   3 using System.Linq;   4 using System.Text;   5 using System.Xml;   6    7 namespace SocketServer   8 {   9     class XmlHandle  10     {  11         public void updatePort(string path, string port)  12         {  13             try  14             {  15                 XmlTextWriter xmlWriter = new XmlTextWriter(path + "\\server.config", Encoding.UTF8);  16                 xmlWriter.WriteStartDocument();  17                 xmlWriter.WriteStartElement("Server");  18   19                 xmlWriter.WriteStartElement("port", "");  20                 xmlWriter.WriteString(port);  21                 xmlWriter.WriteEndElement();  22   23                 xmlWriter.WriteEndDocument();  24                 xmlWriter.Close();  25             }  26             catch (Exception ex)  27             {  28   29             }  30         }  31   32   33         public static string getPort()  34         {  35             string port = "8888";  36             try  37             {  38                 XmlDocument doc = new XmlDocument();  39                 doc.Load(AppDomain.CurrentDomain.BaseDirectory + "\\server.config");  40   41                 XmlNode xnRoot = doc.SelectSingleNode("Server");  42                 XmlNodeList xnl = xnRoot.ChildNodes;  43                 foreach (XmlNode xn in xnl)  44                 {  45                     XmlElement xe = (XmlElement)xn;  46                     byte[] bts = Encoding.UTF8.GetBytes(xe.Name);  47                     if (xe.Name == "port")  48                     {  49                         port = xe.InnerText;  50                         byte[] bt = Encoding.UTF8.GetBytes(port);  51                         break;  52                     }  53                 }  54   55             }  56             catch (Exception ex)  57             {  58   59             }  60             return port;  61         }  62     }  63 }

在ProjectInstaller中處理其中的邏輯,如果需要安裝完成以後馬上運行,那麼就需要這樣:

 1 using System;   2 using System.Collections;   3 using System.Collections.Generic;   4 using System.ComponentModel;   5 using System.Configuration.Install;   6 using System.Linq;   7    8    9 namespace SocketServer  10 {  11     [RunInstaller(true)]  12     public partial class ProjectInstaller : System.Configuration.Install.Installer  13     {  14         string port = "";  15         public ProjectInstaller()  16         {   17             InitializeComponent();  18         }  19   20         protected override void OnBeforeInstall(IDictionary savedState)  21         {  22             //從用戶界面獲取的參數  23             port = Context.Parameters["Port"];  24         }  25   26         protected override void OnAfterInstall(IDictionary savedState)  27         {  28             string appPath = Context.Parameters["targetdir"];  29             XmlHandle xml = new XmlHandle();  30             xml.updatePort(appPath, port);  31             System.ServiceProcess.ServiceController sc = new System.ServiceProcess.ServiceController(serviceInstaller1.ServiceName);  32             if (sc != null)  33             {  34                 sc.Start();  35             }  36         }  37     }  38 }

這樣就在服務安裝以後服務就能啓動,但是在服務啓動的時候,需要從本地的配置中獲取端口號,那麼就需要在SocketHandle.cs中做一點點修改,改成如下的樣子:

  1 using System;    2 using System.Collections.Generic;    3 using System.Linq;    4 using System.Text;    5 using System.Net.Sockets;    6 using System.Net;    7 using System.Threading;    8     9 namespace SocketServer   10 {   11     class SocketHandle   12     {   13              14         private string pointStr = XmlHandle.getPort();   15         private static Socket serverSocket;   16         int pointInt = 8888;   17         private static byte[] result = new byte[1024];   18         private static SocketHandle socketHandle;   19    20         public SocketHandle()   21         {   22    23         }   24    25         public static SocketHandle getInstance()   26         {   27             if (socketHandle == null)   28             {   29                 socketHandle = new SocketHandle();   30             }   31    32             return socketHandle;   33         }   34    35         public void InitSocketServer()   36         {   37             IPAddress localIp = GetLocalIP();   38             if (localIp == null)   39             {   40                 localIp = IPAddress.Parse("127.0.0.1");   41             }   42             try   43             {   44                 if (serverSocket == null)   45                 {   46                     if (pointStr is string)   47                     {   48                         pointInt = Int32.Parse(pointStr);   49                     }     50                     serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);                     51                     serverSocket.Bind(new IPEndPoint(localIp, pointInt));   52                     serverSocket.Listen(10);   53                     Thread myThread = new Thread(ListenClientConnect);   54                     myThread.Start();    55    56                 }   57             }   58             catch (Exception ex)   59             {    60             }   61         }   62    63    64    65         /// <summary>     66         /// 監聽客戶端連接     67         /// </summary>     68         private static void ListenClientConnect()   69         {   70             while (true)   71             {   72                 try   73                 {   74                     Socket clientSocket = serverSocket.Accept();   75                     Thread receiveThread = new Thread(ReceiveMessage);   76                     receiveThread.Start(clientSocket);   77                 }   78                 catch (Exception ex)   79                 {    80                 }   81             }   82         }   83    84    85    86         /// <summary>     87         /// 接收消息     88         /// </summary>     89         /// <param name="clientSocket"></param>     90         private static void ReceiveMessage(object clientSocket)   91         {   92             Socket myClientSocket = (Socket)clientSocket;    93             byte[] bs = new byte[1024];   94             while (true)   95             {   96                 try   97                 {   98                     //通過clientSocket接收數據     99                     int receiveNumber = myClientSocket.Receive(result);  100                     string data = Encoding.ASCII.GetString(result, 0, receiveNumber);  101                     bs = Encoding.ASCII.GetBytes("Receive Data "+data);  102                 }  103                 catch (Exception ex)  104                 {  105                     myClientSocket.Shutdown(SocketShutdown.Both);  106                     myClientSocket.Send(bs, bs.Length, 0);  //返回信息給客戶端  107                     myClientSocket.Close();   108                     break;  109                 }  110                 myClientSocket.Send(bs, bs.Length, 0);  111                 myClientSocket.Close();  112                 break;  113             }  114   115         }  116   117         /// <summary>  118         /// 獲取本地IP地址  119         /// </summary>  120         /// <returns></returns>  121         private IPAddress GetLocalIP()  122         {  123             IPAddress localIp = null;  124             try  125             {  126                 IPAddress[] ipArray;  127                 ipArray = Dns.GetHostAddresses(Dns.GetHostName());  128   129                 localIp = ipArray.First(ip => ip.AddressFamily == AddressFamily.InterNetwork);  130             }  131             catch (Exception ex)  132             {   133             }  134   135             return localIp;  136         }  137     }  138 }

下面運行一下,在看一下結果:

在服務的安裝界面出現了添加端口的輸入框:

 

看端口:

沒問題,再看Socket客戶端:

沒問題。大概就是這樣樣子,如果大家覺得有什麼地方不妥,或者有好的建議或者意見的話希望能夠告訴我。謝謝。

下載地址:http://files.cnblogs.com/fantiantian/SocketServer.rar

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