📄 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;
using System.Net;
using System.DirectoryServices;
namespace LanMsgService
{
public partial class ServiceMain : ServiceBase
{
public ServiceMain()
{
InitializeComponent();
}
#region 用户变量区域
/// <summary>
/// 服务器侦听端口
/// </summary>
private int ListenPort = 3211;
/// <summary>
/// 部门集合
/// </summary>
private IMLibrary.DepartmentCollections deps=new DepartmentCollections();
/// <summary>
/// 所有在线与不在线用户的基本信息集合,设计为:1个用户的信息数据占不到100字节内存,10个用户为1kb内存,100个用户为10kb内存,...,100万个用户为100Mb内存,
/// 1000万个用户为1Gb内存,16G内存服务器支持1亿5千万用户。
/// </summary>
private IMLibrary.UserInfo[] systemUsers;
/// <summary>
/// 应用程序配置器
/// </summary>
private LanMsgService.Properties.Settings settings = new LanMsgService.Properties.Settings();
/// <summary>
/// 当前应用版本
/// </summary>
private IMLibrary.versionDepAndUser VersionDepAndUser = new versionDepAndUser();
#endregion
#region 服务启动与停止
protected override void OnStart(string[] args)
{
this.WirteLog(string.Format("服务正在启动。。。\nSQL数据库连接字符串:'{0}',Oracle数据库连接字符串:'{1}',组织机构版本:{2},系统用户数据版本:{3}"
,settings.SQLConnectionString,settings.OracleConnectionString,settings.departmentVersion,settings.usersVersion ));
////初始化数据库连接字符串
IMLibrary.SqlData.DataAccess.ConnectionString = settings.SQLConnectionString ;
//IMLibrary.OracleData.DataAccess.ConnectionString = settings.OracleConnectionString;
this.updateDepCollections();//初始化部门列表
this.updateUserCollections();// 初始化用户列表
this.updateDepAndUserVersion();//初始化组织机构、用户版本
this.stratListen();//当WINDOWS SERVICE启动时开始侦听来自客户端的请求
this.timersCheckOnlineUserState.Enabled = true;
}
protected override void OnStop()
{
stopServer();
this.timersCheckOnlineUserState.Enabled = false;
}
#endregion
#region 当WINDOWS SERVICE启动时开始侦听来自客户端的请求
/// <summary>
/// 开始侦听来自客户端的请求
/// </summary>
private void stratListen()
{
try
{
this.sockUDPDialog.Listen(ListenPort);//启动对话服务UDP端口
this.sockUDPManager.Listen(ListenPort + 1);//启动管理服务UDP端口
this.sockUDPTransmit.Listen(ListenPort + 2);//启动数据包转发服务UDP端口
this.WirteLog("服务启动成功");
}
catch
{
this.WirteLog("服务启动失败");
}
}
#endregion
#region 停止当前WINDOWS SERVICE时关闭sock的侦听,释放占用的端口资源,防止下次启动服务时系统发生错误
private void stopServer ()
{
try
{
this.sockUDPDialog.CloseSock();
this.sockUDPManager.CloseSock();
this.sockUDPTransmit.CloseSock();
this.WirteLog("服务停止成功");
}
catch
{
this.WirteLog("服务停止失败");
}
}
#endregion
#region 检测用户是否离线timersCheckOnlineUserState_Elapsed
private void timersCheckOnlineUserState_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
for (uint index=1;index<systemUsers.Length;index++)
{
if (systemUsers[index].State != 0 && systemUsers[index].tempState == 0)//如果用户已经离线,则设置其状态等于0
{
systemUsers[index].State = 0;//标记用户不在线
tellAllUserOneIsNotOnline(systemUsers[index].UserID);
}
else
systemUsers[index].tempState = 0;//假设用户不在线
}
}
#endregion
#region 告诉所有用户某用户已经离线
/// <summary>
/// 告诉所有用户某用户已经离线
/// </summary>
/// <param name="userID">用户ID</param>
private void tellAllUserOneIsNotOnline(string userID)
{
byte[] buf = IMLibrary.TextEncoder.textToBytes(userID);
for (uint index = 1; index < systemUsers.Length; index++)
{
if (systemUsers[index].State != 0)
{
this.sendMsgToOneUser(12, buf, systemUsers[index].IP, systemUsers[index].Port);//告诉用户的在线好友,用户已经离线
System.Threading.Thread.Sleep(10);
}
}
}
#endregion
#region UDP数据到达事件
private void sockUDP1_DataArrival(byte[] Data, System.Net.IPAddress Ip, int Port)//UDP数据到达事件
{
this.DataArrival(Data, Ip, Port);
}
//private delegate void DataArrivaldelegate(byte[] Data, System.Net.IPAddress Ip, int 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 0://处理用户登录过程
this.onUserLogin(new DataArrivalEventArgs(buffer, Ip, Port));//触发用户登录事件
break;
case 2://用户询问自己是否在线,并更改其在线状态
this.onUserOnlineChanageState(new DataArrivalEventArgs(buffer, Ip, Port));//触发用户在线状态更新事件
break;
case 5://用户要求发送部门信息数据
this.onSendDeps(new DataArrivalEventArgs(buffer, Ip, Port));
break;
case 6://用户要求发送用户信息数据
this.onSendUsers(new DataArrivalEventArgs(buffer, Ip, Port));
break;
case 7://用户转发消息
this.onTransmitMsg(new DataArrivalEventArgs(buffer, Ip, Port));
break;
case 8://用户需要修改密码
this.onUserChangePassword(new DataArrivalEventArgs(buffer, Ip, Port));
break;
case 10://收到 WebService 消息
this.onWebServiceMsg(new DataArrivalEventArgs(buffer, Ip, Port));
break;
}
}
catch
{
// this.WirteLog("系统收到数据无法识别的消息类型。非法用户--"+ Ip.ToString() +":"+ Port.ToString());
}
}
#endregion
#region 处理收到来自于桌面或WEB应用程序发送的 WebService 消息
/// <summary>
/// 处理收到来自于桌面或WEB应用程序发送的 WebService 消息
/// </summary>
/// <param name="e"></param>
private void onWebServiceMsg(DataArrivalEventArgs e)
{
IMLibrary.WebServiceMsg msg=IMLibrary.Serializers.ByteToObj (e.Data) as IMLibrary.WebServiceMsg ;
if (msg == null) return;//抛掉非法的webService消息
IMLibrary.clientMsg cMsg = new clientMsg(msg.msgContent,msg.sendUserId);
byte[] msgContent = IMLibrary.Serializers.ObjToByte(cMsg);
if (msg.usersId == "")//表示消息发送给所有的人
{
for (uint index = 1; index < systemUsers.Length;index ++ )
if(systemUsers[index].State!=0)//如果用户在线,则发送消息
this.sendMsgToOneUser(msg.msgInfo, msgContent, systemUsers[index].IP, systemUsers[index].Port);
}
else//表示消息发送给指定的人
{
string[] userID = msg.usersId.Split(';');//多个用户用分号隔开
for (int i = 0; i < userID.Length; i++)
{
IMLibrary.UserInfo user = this.findUser(userID[i]);
if (user != null)//如果此用户存在
if (user.State != 0)//如果用户在线则将消息发送给用户
this.sendMsgToOneUser(msg.msgInfo, msgContent, user.IP, user.Port);
}
}
this.WirteLog("收到"+ msg.sendUserId +" 发送的 WebService 消息。接收者:"+ msg.usersId);
}
#endregion
#region 用户修改密码请求
/// <summary>
/// 用户修改密码请求
/// </summary>
/// <param name="e"></param>
private void onUserChangePassword(DataArrivalEventArgs e)
{
IMLibrary.ServerMsg msg = IMLibrary.Serializers.ByteToObj(e.Data) as IMLibrary.ServerMsg;
if (msg == null) return;
string[] user = IMLibrary.TextEncoder.bytesToText(msg.msgContent).Split('|');
string userID = user[0];
string oldPassword = user[1];
string newPassword = user[2];
byte[] buf=new byte[1];
if (IMLibrary.DNS.ChangePassword(userID, oldPassword, newPassword, "gz.com"))
{
sendMsgToOneUser(24, buf, e.IP, e.Port); //告诉用户密码修改成功
System.Threading.Thread.Sleep(100);
sendMsgToOneUser(24, buf, e.IP, e.Port); //告诉用户密码修改成功
System.Threading.Thread.Sleep(250);
sendMsgToOneUser(24, buf, e.IP, e.Port); //告诉用户密码修改成功
System.Threading.Thread.Sleep(500);
sendMsgToOneUser(24, buf, e.IP, e.Port); //告诉用户密码修改成功
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -