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

 
 
分类: C#

C# 制作Windows服务安装包的更多相关文章

  1. 如何制作windows服务安装包

    以下转自:http://blog.csdn.net/chainan1988/article/details/7087006 Window服务的安装有两个方式: 一.命令安装          通过命令 ...

  2. 用VS制作的windows服务安装包 安装完后如何让服务自动启动

    vs 服务做成安装包,如何安装以后启动服务,只要在类名为projectinstaller的类中重写commit事件即可         public override void Commit(IDic ...

  3. 使用NISI制作.Net程序服务安装包

    1.开篇之前先说一说NISI是什么. NSIS(Nullsoft Scriptable Install System)是一个开源的 Windows 系统下安装程序制作程序.它提供了安装.卸载.系统设置 ...

  4. IS2009制作Oracle 静默安装包(一)感谢空白先生特许授权

    原文:IS2009制作Oracle 静默安装包(一)感谢空白先生特许授权 上一篇: MyEclipse中消除frame引起的“the file XXX can not be found.Please ...

  5. IS2009制作Oracle 静默安装包(二) 感谢空白先生特许授权

    原文:IS2009制作Oracle 静默安装包(二) 感谢空白先生特许授权 上一篇: IS2009制作Oracle 静默安装包(一)感谢空白先生特许授权本文经原作者特许授权于海洋女神发布,转载请务必注 ...

  6. 制作iis自动安装包

    原文:制作iis自动安装包 MS 一直没有提供可独立安装的 IIS 安装包,Windows 的缺省安装没有安装它,通常要到控制面板的"添加/删除 Windows 程序"中去选择安装 ...

  7. 制作linux内核安装包

    实验基于Centos 6.2 升级linux内核 直接在一个有编译环境的设备上,编译升级内核很简单. make menuconfig 或者 拷贝现有系统的.config文件 修改.config文件  ...

  8. NSIS:制作软件升级安装包

    原文 NSIS:制作软件升级安装包 相信不是每个人写的软件都只发布一次就可以了,肯定要有修改和维护的情况发生.在这种情况下,您可能就需要一个软件的升级安装包了.   现在,我们就来一步步把这个安装包做 ...

  9. Advanced Installer 制作.NetWeb部署安装包

    原文:Advanced Installer 制作.NetWeb部署安装包 因为是.Net的Web应用程序,所以想用Advanced Installer 调用Dll实现安装部署. 因为我需要自己定制参数 ...

随机推荐

  1. .NET缓存框架CacheManager---1、CacheManager的介绍

    在我们开发的很多分布式项目里面(如基于WCF服务.Web API服务方式),由于数据提供涉及到数据库的相关操作,如果客户端的并发数量超过一定的数量,那么数据库的请求处理则以爆发式增长,如果数据库服务器 ...

  2. HDU - 5008 Boring String Problem (后缀数组+二分法+RMQ)

    Problem Description In this problem, you are given a string s and q queries. For each query, you sho ...

  3. ASP.NET MVC+EF框架+EasyUI实现权限管理系列(5)-前台JqueryEasyUI前台实现

    原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(5)-前台JqueryEasyUI前台实现 ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇)   (1):框 ...

  4. BFS、双向BFS和A*

    BFS.双向BFS和A* Table of Contents 1. BFS 2. 双向BFS 3. A*算法 光说不练是无用的.我们从广为人知的POJ 2243这道题谈起:题目大意:给定一个起点和一个 ...

  5. UVA11983 - Weird Advertisement(扫描线)

    UVA11983 - Weird Advertisement(扫描线) 题目链接 题目大意:给你n个覆盖矩形,问哪些整数点是被覆盖了k次. 题目大意:这题和hdu1542是一个题型.可是这题求的是覆盖 ...

  6. hdu Max Sum Plus Plus(dp+滚动数组)

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1024 m为段,要深刻理解题意,并没有说是段与段要连接. 题解链接:http://blog.csdn.n ...

  7. linux_安装 redis

    Installation Download, extract and compile Redis with: $ wget http://download.redis.io/releases/redi ...

  8. Apache & WebDav 配置(一)

    (一)简单Apache服务器的搭建!用于文件de上传.下载.修改.删除! ---------- - Apache 1. 使用最广的 Web 服务器.支持各种脚本(PHP)的执行 2. Mac自带,只需 ...

  9. Html5 の 微信飞机大战

    (function () { var imageUrl = "images/"; //获取画布对象 var c = $("#game-box").get(0); ...

  10. Host和Server的开发

    Host和Server的开发 对于开发人员来说,代码就是最好的文档,如上一篇博文所说,下面我们就会基于Kanata项目的一些具体调用代码,来进一步深入理解OWIN的实现和作用. 今天我们先针对Host ...