⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 servicemain.cs

📁 kuiMsg是一款用.net C# 开发的即时消息开源软件,适合.net即时消息软件开发者用。 主要功能: 支持文件传输(p2p); 支持GIF动画表情( 彻底消除闪屏 :) );
💻 CS
📖 第 1 页 / 共 3 页
字号:
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 + -