C# 制作Windows服务安装包
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客户端:

没问题。大概就是这样样子,如果大家觉得有什么地方不妥,或者有好的建议或者意见的话希望能够告诉我。谢谢。
C# 制作Windows服务安装包的更多相关文章
- 如何制作windows服务安装包
以下转自:http://blog.csdn.net/chainan1988/article/details/7087006 Window服务的安装有两个方式: 一.命令安装 通过命令 ...
- 用VS制作的windows服务安装包 安装完后如何让服务自动启动
vs 服务做成安装包,如何安装以后启动服务,只要在类名为projectinstaller的类中重写commit事件即可 public override void Commit(IDic ...
- 使用NISI制作.Net程序服务安装包
1.开篇之前先说一说NISI是什么. NSIS(Nullsoft Scriptable Install System)是一个开源的 Windows 系统下安装程序制作程序.它提供了安装.卸载.系统设置 ...
- IS2009制作Oracle 静默安装包(一)感谢空白先生特许授权
原文:IS2009制作Oracle 静默安装包(一)感谢空白先生特许授权 上一篇: MyEclipse中消除frame引起的“the file XXX can not be found.Please ...
- IS2009制作Oracle 静默安装包(二) 感谢空白先生特许授权
原文:IS2009制作Oracle 静默安装包(二) 感谢空白先生特许授权 上一篇: IS2009制作Oracle 静默安装包(一)感谢空白先生特许授权本文经原作者特许授权于海洋女神发布,转载请务必注 ...
- 制作iis自动安装包
原文:制作iis自动安装包 MS 一直没有提供可独立安装的 IIS 安装包,Windows 的缺省安装没有安装它,通常要到控制面板的"添加/删除 Windows 程序"中去选择安装 ...
- 制作linux内核安装包
实验基于Centos 6.2 升级linux内核 直接在一个有编译环境的设备上,编译升级内核很简单. make menuconfig 或者 拷贝现有系统的.config文件 修改.config文件 ...
- NSIS:制作软件升级安装包
原文 NSIS:制作软件升级安装包 相信不是每个人写的软件都只发布一次就可以了,肯定要有修改和维护的情况发生.在这种情况下,您可能就需要一个软件的升级安装包了. 现在,我们就来一步步把这个安装包做 ...
- Advanced Installer 制作.NetWeb部署安装包
原文:Advanced Installer 制作.NetWeb部署安装包 因为是.Net的Web应用程序,所以想用Advanced Installer 调用Dll实现安装部署. 因为我需要自己定制参数 ...
随机推荐
- 如何使用Ubuntu打电话
在这个视频,我们学习如何使用Ubuntu打电话.Ubuntu手机的很多用户谁是不是很熟悉. 特别是,他什么都无所谓的物理按键(菜单键.home纽带.回车键).然后用户如何控制手机它?Ubuntu手机凭 ...
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(18)-过滤器的使用和批量删除数据(伪删除和直接删除)
原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(18)-过滤器的使用和批量删除数据(伪删除和直接删除) ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) ...
- 准备战争“软测试”之DB基础知识
"数据库"东西这个陌生和数据,进入提高班,从第二年开始接触,的项目还是自考的学习加起来也有3遍了.这仅仅是一个開始,软考又要对数据库进行全面的分析,那么如今就让我们再一次剖析它吧! ...
- POJ1201-Intervals(差动限制)
Intervals Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 20786 Accepted: 7866 Descri ...
- 项目开发经常使用PHP功能
日期操作 为了便于存储.比较和交付.我们通常使用strtotime()功能转换的日期UNIX时间戳.有仅用于在显示给用户时date()成经常使用的时间格式. strtotime() 函数将不论什么英 ...
- 搭建一个三台服务器的Memcached集群
关于memcached的基础知识可以查看博客其他博文,这里只记录了搭建的过程,谢谢! 1.分别在三台服务器上安装Memcached并启动 第一.由于memcached是基于libevent的事件处理, ...
- Django----模板
为了将html页面和python代码分离开来,有必要介绍一下模板的作用,Django中自带很多模板. 以下一个html模板文件: <html> <head><title& ...
- 【iOS】iOS它Container View获得ViewController
近期使用Container View来在主View Controller建立自己的子Controller,但是遇到问题.不知道怎样用代码获取Controller View附带的View Control ...
- 一步一步写算法(之挑选最大的n个数)
原文:一步一步写算法(之挑选最大的n个数) [ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 从一堆数据中挑选n个最大的数,这个问题是网上流传的 ...
- AngularJS html5Mode与ASP.NET MVC路由
AngularJS html5Mode与ASP.NET MVC路由共存 前言 很久之前便听说AngularJS,非常酷,最近也比较火,我也在持续关注这个技术,只是没有认真投入学习.前不久公司找我们部门 ...