📄 servicemain.cs
字号:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.IO;
using IMLibrary;
using System.Data.SqlClient;
namespace LanMsgUpdateService
{
public partial class ServiceMain : ServiceBase
{
public ServiceMain()
{
InitializeComponent();
}
#region 用户变量区域
/// <summary>
/// 服务器侦听端口
/// </summary>
private int ListenPort = 5678;
/// <summary>
/// 升级文件的字节数组
/// </summary>
byte[] fileBuf;
/// <summary>
/// 文件长度
/// </summary>
byte[] fileLen;
/// <summary>
/// 文件名
/// </summary>
string FileName = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "LanMsgUpdate.exe";
/// <summary>
/// 客户端最新文件版本号
/// </summary>
string version = "1.0.0.1";
/// <summary>
/// 最大网络传输单元
/// </summary>
uint MTU = 1000;
#endregion
#region 服务启动与停止
protected override void OnStart(string[] args)
{
this.version =LanMsgUpdateService.Settings1.Default.Version;
this.MTU = LanMsgUpdateService.Settings1.Default.MTU;
this.stratListen();//当WINDOWS SERVICE启动时开始侦听来自客户端的请求
}
protected override void OnStop()
{
this.stopServer();
}
#endregion
#region 当WINDOWS SERVICE启动时开始侦听来自客户端的请求
/// <summary>
/// 开始侦听来自客户端的请求
/// </summary>
private void stratListen()
{
try
{
this.sockUDP1.Listen(ListenPort);
if (this.readUpdateFile())
this.WirteLog("服务启动成功,升级文件版本号:"+ this.version +",升级数据大小:"+ this.fileBuf.Length.ToString() +"字节,最大网络传输单元MTU="+ this.MTU.ToString ());
else
this.WirteLog("文件初始化失败");
}
catch
{
this.WirteLog("服务启动失败");
}
}
#endregion
#region 停止当前WINDOWS SERVICE时关闭sock的侦听,释放占用的端口资源,防止下次启动服务时系统发生错误
private void stopServer ()
{
try
{
this.sockUDP1.CloseSock ( );
this.fileBuf = null;
this.WirteLog("服务停止成功");
}
catch
{
this.WirteLog("服务停止失败");
}
}
#endregion
private void sockUDP1_DataArrival(byte[] Data, System.Net.IPAddress Ip, int Port)//UDP数据到达事件
{
this.DataArrival(Data, Ip, Port);
}
private void DataArrival(byte[] Data, System.Net.IPAddress Ip, int Port) //当有数据到达后的处理过程
{
if (Data[0] != 255) return;//将非法用户的数据抛弃
int cnt = 0;//记录接收到的数据包大小
cnt = Data.Length;//获取接收到的数据包大小
if (cnt < 3) return;//如果收到的数据小于3,个字节则视为非法用户抛弃
try
{
byte[] buffer = new byte[cnt - 2];//申明一个字节数组,用于保存去除第一个字节码(即LanMsg协议编码)的其它数据(即消息实体)
Buffer.BlockCopy(Data, 2, buffer, 0, cnt - 2);//去除前两个字节码(即LanMsg协议编码)的其它数据为消息实体,将其保存于Buffer字节数组
switch (Data[1])//取得第一个字节码,即LanMsg协议编码,根据编码判断用户发过来的请求为何种类型
{
case 1://发送文件数据块
this.sendFileData(new DataArrivalEventArgs(buffer,Ip,Port));
break;
case 2://用户要求获得升级文件包的大小
this.sendFileLen(new DataArrivalEventArgs(Ip, Port));
break;
case 3://判断文件版本号
this.getVersion(new DataArrivalEventArgs(buffer, Ip, Port));
break;
}
}
catch
{
this.WirteLog("系统收到数据无法识别的消息类型。非法用户--"+ Ip.ToString() +":"+ Port.ToString());
}
}
#region 获得客户端版本号
/// <summary>
/// 获得客户端版本号
/// </summary>
/// <param name="e"></param>
private void getVersion(DataArrivalEventArgs e)
{
string Version =this.version ;
try
{
Version = TextEncoder.bytesToText(e.Data);//获得客户端文件版本号
}
catch { this.WirteLog("错误的版本数据!"); };
if (this.version != Version)//如果有最新版本,则告诉用户升级
{
this.sendFileLen(e);//向用户发送升级包数据大小
}
}
#endregion
#region 向用户发送升级包数据大小
/// <summary>
/// 向用户发送升级包数据大小
/// </summary>
/// <param name="e"></param>
private void sendFileLen(DataArrivalEventArgs e)
{
this.sendMsgToOneUser(2, this.fileLen, e.IP, e.Port);
}
#endregion
#region 向用户发送升级包数据
/// <summary>
/// 向用户发送升级包数据
/// </summary>
/// <param name="e"></param>
private void sendFileData(DataArrivalEventArgs e)
{
int currPos = IMLibrary.TextEncoder.bytesToInt(e.Data);//获得要发送文件的起始位置
if (currPos >= this.fileBuf.Length) return;
byte[] buffer = new byte[this.MTU];//要发送的缓冲区
if (currPos + this.MTU > this.fileBuf.Length)//如果发送
buffer = new byte[this.fileBuf.Length - currPos];
Buffer.BlockCopy(this.fileBuf, currPos, buffer, 0, buffer.Length );//将其保存于Buffer字节数组
IMLibrary.sendFileInfo fileInfo = new sendFileInfo(1,currPos + buffer.Length ,buffer );
this.sendMsgToOneUser(1, IMLibrary.Serializers.ObjToByte(fileInfo), e.IP, e.Port);
}
#endregion
#region 升级文件数据初始化
/// <summary>
/// 升级文件数据初始化
/// </summary>
/// <returns></returns>
private bool readUpdateFile()
{
System.IO.FileInfo f = new FileInfo(FileName);
if (!f.Exists) return false;
int fileLen =(int ) f.Length;
this.fileBuf = new byte[fileLen];
System.IO.FileStream fStream = new System.IO.FileStream(f.FullName, FileMode.Open, FileAccess.Read, FileShare.Read);
int ReadCount = fStream.Read(this.fileBuf, 0, fileLen);//将要发送的文件块数据存入发送缓冲区
fStream.Close();
if (ReadCount != fileLen)
return false;
else
{
this.fileLen = IMLibrary.TextEncoder.intToBytes (this.fileBuf.Length) ;//将文件大小存入字节数组
return true;
}
}
#endregion
#region 发送消息给一个用户sendMsgToOneUser(Byte msgInfo ,byte[] msgContent, System.Net.IPAddress Ip, int Port)
/// <summary>
/// 发送消息给一个用户
/// </summary>
/// <param name="msgInfo">消息类型</param>
/// <param name="msgContent">消息内容</param>
/// <param name="Ip">接收者IP</param>
/// <param name="Port">接收者端口</param>
public void sendMsgToOneUser(Byte msgInfo ,byte[] msgContent, System.Net.IPAddress Ip, int Port)//给一个用户发送消息
{
byte[] buf = new byte[msgContent.Length + 2];
buf[0] = 255;//合法用户标识
buf[1] = msgInfo;//消息类型
Buffer.BlockCopy(msgContent, 0, buf, 2, msgContent.Length);
IMLibrary.SockUDP sockTemp = new SockUDP();
sockTemp.Send(Ip, Port, buf);
sockTemp.Dispose();
}
#endregion
#region 将消息写入日志文件 WirteLog(string str)
/// <summary>
/// LanMsg写日志函数
/// </summary>
/// <param name="str">要写入的日志内容字符串</param>
private void WirteLog(string str)
{
FileStream fs = new FileStream(AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "log.txt", FileMode.OpenOrCreate, FileAccess.Write);
StreamWriter _streamWriter = new StreamWriter(fs);
_streamWriter.BaseStream.Seek(0, SeekOrigin.End);
_streamWriter.WriteLine(str + " " + DateTime.Now.ToString() + "\n");
_streamWriter.Flush();
_streamWriter.Close();
fs.Close();
}
#endregion
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -