.net下的面向工控领域的远程方法调用(RMI)中间件,客户端协议栈应答端实现

远程方法调用,在服务器端执行完毕后,其反馈结果也必然是,按照字节流的方式返回,服务器端按照通信协议,做封包处理,而客户端的应答处理部分,从通信连接会话上,接收到待解析的字节流数据,负责解析,转化成客户端可执行的结构体数据。

解包过程时,需要从外到内逐级向下,上级解包状态决定了下级解包时,调用的消息处理器。

下面是同步调用过程的客户端协议拆包过程:

1      通信协议包格式

用于对客户端和服务器端通信时,数据传输过程中的数据包的封装处理,只负责具体的数据

包传输,此为整个封包的最外层包装。


起始标记位


包体长度


加密标记


数据包内容


4Byte


Int32


1Byte


字节流


用于标记数据包的开始,

0x02,0x03,0xFF,0xFF


用于标记数据包的长度,LittleEndian


0x00,不加密

0x01,加密


所有数据的内容,需要下面的“数据包内容协议格式定义”进一步处理

拆包代码,此处拆包代码引入了底层的通信组件,Trace.Common.Communication.dll,在其他文章处有介绍,

 /// <summary>
    /// RMI应答消息解析器
    /// </summary>
    public class RMIClientDataOutputFilter : Trace.Common.Communication.Message.BaseOutPutMessageFilter<RMIClientDataRequest, RMIClientDataResponse>
    {
        private IMessageFilterHelper messageFilterHelper = null;
        /// <summary>
        /// 包头
        /// </summary>
        private byte[] start = new byte[] { 0x02, 0x03, 0xFF, 0xFF };
        /// <summary>
        /// 应答处理上下文
        /// </summary>
        private List<RMIResponseContext> responseContextList = new List<RMIResponseContext>();
        /// <summary>
        /// 应答上下文处理锁
        /// </summary>
        private object responseContextLock = new object();
        public RMIClientDataOutputFilter()
        {
            messageFilterHelper = new MessageFilterFixStartLengthHelper(start, 4, 60000);
        }
        /// <summary>
        /// 将通信流压入待处理的解析器
        /// </summary>
        /// <param name="sessionID">会话ID</param>
        /// <param name="buffer"></param>
        protected override void InputBufferData(string sessionID, byte[] buffer)
        {
            messageFilterHelper.InputBufferData(buffer);
        }
        /// <summary>
        /// 拆包
        /// </summary>
        /// <returns></returns>
        protected override RMIClientDataResponse GetNextResponse()
        {
            byte[] tempBuffer = messageFilterHelper.GetNextData();
            if (tempBuffer == null || tempBuffer.Length == 0)
            {
                return null;
            }
            RMIClientDataResponse response = new RMIClientDataResponse();
            try
            {
                response = this.Response(tempBuffer, response);
            }
            catch (Exception ex)
            {
                response.Exception = ex;
            }
            return response;
        }
        /// <summary>
        /// 应答解析处理
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="response"></param>
        /// <returns></returns>
        private RMIClientDataResponse Response(byte[] buffer, RMIClientDataResponse response)
        {
            PackDataOutputFilter packDataOutputFilter = new PackDataOutputFilter();
            packDataOutputFilter.SetBuffer(buffer);
            if (packDataOutputFilter.RMIDataBlockFlag == RMIDataBlockFlag.AllBlock)//整包传输
            {
                this.AllBlockDataPro(packDataOutputFilter);
            }
            else if (packDataOutputFilter.RMIDataBlockFlag == RMIDataBlockFlag.AllBlockACK
                || packDataOutputFilter.RMIDataBlockFlag == RMIDataBlockFlag.AllBlockNAK)//整包传输成功\失败确认
            {
                this.AllBlockConfirm(packDataOutputFilter);
            }

            else if (packDataOutputFilter.RMIDataBlockFlag == RMIDataBlockFlag.SplitBlock)//分包传输
            {

            }
            else if (packDataOutputFilter.RMIDataBlockFlag == RMIDataBlockFlag.SplitBlockACK
                || packDataOutputFilter.RMIDataBlockFlag == RMIDataBlockFlag.SplitBlockNAK)//分包传输成功、失败确认
            {

            }
            return response;
        }
        /// <summary>
        /// 整包数据确认
        /// </summary>
        /// <param name="packDataOutputFilter"></param>
        private void AllBlockConfirm(PackDataOutputFilter packDataOutputFilter)
        {
            AllBlockConfirmOutputFilter allBlockConfirmOutputFilter = new AllBlockConfirmOutputFilter();
            allBlockConfirmOutputFilter.SetBuffer(packDataOutputFilter.LeftBuffer);
            if (packDataOutputFilter.RMIDataBlockFlag == RMIDataBlockFlag.AllBlockNAK)//整包传输失败确认
            { 

            }
        }
        /// <summary>
        /// 整包数据处理
        /// </summary>
        /// <param name="packDataOutputFilter"></param>
        private void AllBlockDataPro(PackDataOutputFilter packDataOutputFilter)
        {
            AllBlockDataOutputFilter allBlockDataOutputFilter = new AllBlockDataOutputFilter();
            allBlockDataOutputFilter.SetBuffer(packDataOutputFilter.LeftBuffer);
            if (allBlockDataOutputFilter.RMIVersion == RMIVersion.Version1)//版本1处理器
            {
                this.ExcuteContentVersion1(allBlockDataOutputFilter.LeftBuffer);
            }
        }
        /// <summary>
        /// 版本1,执行体数据处理
        /// </summary>
        /// <param name="excuteBuffer">执行体数据</param>
        private RMIResponseContext ExcuteContentVersion1(byte[] excuteBuffer)
        {
            RMIResponseContext context;
            ResponseDataOutputFilterVersion1 responseDataOutputFilterVersion1 = new ResponseDataOutputFilterVersion1();
            responseDataOutputFilterVersion1.SetBuffer(excuteBuffer);
            if (responseDataOutputFilterVersion1.RMIResponseType == RMIResponseType.SyncRequestResponse)//同步应答
            {
                context = new RMISyncResponseContext();
                context.RequestObjCallID = responseDataOutputFilterVersion1.RequestObjCallID;
                context.RequestMethodID = responseDataOutputFilterVersion1.RequestMethodID;
                SyncResponseOutputFilterVersion1 syncResponseOutputFilterVersion1 = new SyncResponseOutputFilterVersion1();
                syncResponseOutputFilterVersion1.SetBuffer(responseDataOutputFilterVersion1.LeftBuffer);
                context.ResponseStatus = syncResponseOutputFilterVersion1.ResponseStatus;
                if (syncResponseOutputFilterVersion1.ResponseStatus == RMIResponseStatus.IsResult)//同步应答返回结果
                {
                    SyncResponseOutputFilterVersion1IsResult syncResponseOutputFilterVersion1IsResult = new SyncResponseOutputFilterVersion1IsResult(responseDataOutputFilterVersion1.SerializeType);
                    syncResponseOutputFilterVersion1IsResult.SetBuffer(syncResponseOutputFilterVersion1.LeftBuffer);
                }
                else if (syncResponseOutputFilterVersion1.ResponseStatus == RMIResponseStatus.IsNull)//空的返回
                {
                    SyncResponseOutputFilterVersion1IsNull syncResponseOutputFilterVersion1IsNull = new SyncResponseOutputFilterVersion1IsNull();
                    syncResponseOutputFilterVersion1IsNull.SetBuffer(syncResponseOutputFilterVersion1.LeftBuffer);
                }
                else if (syncResponseOutputFilterVersion1.ResponseStatus == RMIResponseStatus.Exception)//异常返回
                {
                    SyncResponseOutputFilterVersion1IsException syncResponseOutputFilterVersion1IsException = new SyncResponseOutputFilterVersion1IsException(responseDataOutputFilterVersion1.SerializeType);
                    syncResponseOutputFilterVersion1IsException.SetBuffer(syncResponseOutputFilterVersion1.LeftBuffer);
                }
            }
            else if (responseDataOutputFilterVersion1.RMIResponseType == RMIResponseType.ASyncRequestResponse)//异步应答
            {
                

1.1    数据包内容协议格式定义:


包唯一ID


包标记


数据块内容


数据包校验位


GUI(16Byte)


1Byte


字节流


1Byte


当前传输数据包的唯一ID


0x00,表示整包传输,

0x01,表示分包传输

0x02,表示整包传输确认

0x03,表示分包传输确认

0x04,表示整包传输失败

0x05,表示分包传输失败


需要下面进一步处理


校验和,对数据包内容中的所有数据,进行校验和

1.1.1    整包传输数据块协议


版本号


命令状态


执行体


Int32


Byte


字节流


用于标记处理数据的版本


0x00,请求命令

0x01,应答命令


需要到“执行体协议”进一步处理

此处按照整包数据块,协议解析代码,

  /// <summary>
    /// 包体数据解析
    /// </summary>
    public class PackDataOutputFilter : IRMISplitResponseOutputFilter
    {
        private Guid packID;
        /// <summary>
        /// 数据包唯一ID
        /// </summary>
        public Guid PackID
        {
            get
            {
                return packID;
            }
        }
        private RMIDataBlockFlag rMIDataBlockFlag;
        /// <summary>
        /// 包标记
        /// </summary>
        public RMIDataBlockFlag RMIDataBlockFlag
        {
            get
            {
                return this.rMIDataBlockFlag;
            }
        }
        private byte[] leftBuffer;
        /// <summary>
        /// 剩余数据
        /// </summary>
        public byte[] LeftBuffer
        {
            get
            {
                return this.leftBuffer;
            }
        }
       /// <summary>
       /// 包体数据解析
       /// </summary>
       /// <param name="buffer"></param>
        public void SetBuffer(byte[] buffer)
        {
            this.CheckSum(buffer);
            Trace.Common.Communication.MessageStatck.MessageStatckSplit messageStatckSplit = new Trace.Common.Communication.MessageStatck.MessageStatckSplit(buffer);
            Guid tempPackID;
            if (messageStatckSplit.PopGUID(out tempPackID) == false)
            {
                throw new Exception("获取数据包唯一ID失败");
            }
            this.packID = tempPackID;
            byte bRMIDataBlockFlag;
            if (messageStatckSplit.PopByte(out bRMIDataBlockFlag) == false)
            {
                throw new Exception("获取包标记失败");
            }
            this.rMIDataBlockFlag = (RMIDataBlockFlag)bRMIDataBlockFlag;
            this.leftBuffer = messageStatckSplit.GetLeftDataBuffer();
        }
        /// <summary>
        /// 进行校验和处理
        /// </summary>
        /// <param name="dataBuffer">体数据</param>
        /// <returns></returns>
        public void CheckSum(byte[] dataBuffer)
        {
            int len = dataBuffer.Length;
            byte tempCheck = dataBuffer[len - 1];
            byte checkSum = 0x00;
            for (int i = 0; i < len-1; i++)
            {
                checkSum += dataBuffer[i];
            }
            if (tempCheck != checkSum)
            {
                throw new Exception("数据包校验失败");
            }
        }
    }
 /// <summary>
    /// 整数据块解析处理
    /// </summary>
    public class AllBlockDataOutputFilter : IRMISplitResponseOutputFilter
    {
        private RMIVersion rmiVersion;
        /// <summary>
        /// 版本号
        /// </summary>
        public RMIVersion RMIVersion
        {
            get
            {
                return rmiVersion;
            }
        }
        private RMICommand rmiCommand;
        /// <summary>
        /// 命令状态
        /// </summary>
        public RMICommand RMICommand
        {
            get
            {
                return rmiCommand;
            }
        }
        private byte[] leftBuffer;
        /// <summary>
        /// 剩余数据
        /// </summary>
        public byte[] LeftBuffer
        {
            get
            {
                return this.leftBuffer;
            }
        }
        /// <summary>
        /// 数据解析处理
        /// </summary>
        /// <param name="buffer"></param>
        public void SetBuffer(byte[] buffer)
        {
            Trace.Common.Communication.MessageStatck.MessageStatckSplit messageStatckSplit = new Trace.Common.Communication.MessageStatck.MessageStatckSplit(buffer);
            Int32 versionCode;
            if (messageStatckSplit.PopInt32(out versionCode) == false)
            {
                throw new Exception("获取版本代码失败");
            }
            this.rmiVersion = (RMIVersion)versionCode;
            byte bCommand;
            if (messageStatckSplit.PopByte(out bCommand) == false)
            {
                throw new Exception("获取命令状态失败");
            }
            this.rmiCommand = (RMICommand)bCommand;
            this.leftBuffer = messageStatckSplit.GetLeftDataBuffer();
        }
    }

1      服务端版本1,执行体协议

1.1    函数反馈应答


启用的序列化协议


客户端请求对象ID


客户端调用过程ID


应答方式


具体的应答处理


1Byte


GUID(16Byte)


GUID(16Byte)


1Byte


字节流


0x00,Json序列化,

0x01,ProtoBuf序列化


用于标记客户端发起请求的对象


用于标记客户端发起请求的调用函数


用于标记服务器端的应答方式,

0x01, 同步请求应答

0x02,订阅回调

0x03,异步请求应答

到执行体部分了,拆包协议处理,

/// <summary>
    /// 执行体数据消息解析器
    /// </summary>
    public class ResponseDataOutputFilterVersion1:IRMISplitResponseOutputFilter
    {
        private RMISerializeType serializeType;
        /// <summary>
        /// 序列化方式
        /// </summary>
        public RMISerializeType SerializeType
        {
            get
            {
                return serializeType;
            }
        }

        private Guid requestObjCallID;
        /// <summary>
        /// 原始请求对象ID
        /// </summary>
        public Guid RequestObjCallID
        {
            get
            {
                return requestObjCallID;
            }
        }

        private Guid requestMethodID;
        /// <summary>
        /// 原始请求方法ID
        /// </summary>
        public Guid RequestMethodID
        {
            get
            {
                return this.requestMethodID;
            }
        }

        private RMIResponseType responseType;
        /// <summary>
        /// 应答方式
        /// </summary>
        public RMIResponseType RMIResponseType
        {
            get
            {
                return responseType;
            }
        }

        private byte[] leftBuffer;
        /// <summary>
        /// 剩余字节数量
        /// </summary>
        public byte[] LeftBuffer
        {
            get
            {
                return leftBuffer;
            }
        }
        /// <summary>
        /// 执行体协议应答解析处理
        /// </summary>
        /// <param name="buffer">执行体数据包</param>
        public void SetBuffer(byte[] buffer)
        {
            Trace.Common.Communication.MessageStatck.MessageStatckSplit messageStatckSplit = new Trace.Common.Communication.MessageStatck.MessageStatckSplit(buffer);
            byte bSerializeType;
            if (messageStatckSplit.PopByte(out bSerializeType) == false)
            {
                throw new Exception("获取启用的序列化协议失败");
            }
            this.serializeType = (RMISerializeType)bSerializeType;
            Guid tempObjID;
            if (messageStatckSplit.PopGUID(out tempObjID) == false)
            {
                throw new Exception("获取请求对象ID失败");
            }
            this.requestObjCallID = tempObjID;
            Guid tempMethodID;
            if (messageStatckSplit.PopGUID(out tempMethodID) == false)
            {
                throw new Exception("获取调用过程ID失败");
            }
            this.requestMethodID = tempMethodID;
            byte bResponseType;
            if (messageStatckSplit.PopByte(out bResponseType) == false)
            {
                throw new Exception("获取应答方式失败");
            }
            this.responseType = (RMIResponseType)bResponseType;
            this.leftBuffer = messageStatckSplit.GetLeftDataBuffer();
        }
    }

1.1.1    客户端同步请求应答


应答状态


返回数据


1Byte


字节流


用于标记应答的信息流状态

0x00 空的返回

0x01 存在数据

0x02 异常信息

 /// <summary>
    /// 同步应答解析处理器
    /// </summary>
    public class SyncResponseOutputFilterVersion1 : IRMISplitResponseOutputFilter
    {
        private RMIResponseStatus responseStatus=RMIResponseStatus.UnKnow;
        /// <summary>
        /// 应答状态
        /// </summary>
        public RMIResponseStatus ResponseStatus
        {
            get
            {
                return responseStatus;
            }
        }
        private byte[] leftBuffer;
        /// <summary>
        /// 剩余字节数量
        /// </summary>
        public byte[] LeftBuffer
        {
            get
            {
                return leftBuffer;
            }
        }
         /// <summary>
        /// 执行体协议应答解析处理
        /// </summary>
        /// <param name="buffer">执行体数据包</param>
        public void SetBuffer(byte[] buffer)
        {
            Trace.Common.Communication.MessageStatck.MessageStatckSplit messageStatckSplit = new Trace.Common.Communication.MessageStatck.MessageStatckSplit(buffer);
            byte bResponseStatus;
            if (messageStatckSplit.PopByte(out bResponseStatus) == false)
            {
                throw new Exception("获取应答状态失败");
            }
            this.responseStatus = (RMIResponseStatus)bResponseStatus;
            this.leftBuffer = messageStatckSplit.GetLeftDataBuffer();
        }
    }

1.1.1.1             存在数据


返回类型全名字节流长度


返回类型全名字节流


返回序列化内容字节流长度


返回序列化内容字节流


Int32


字节流


Int32


字节流


用于标记返回类型全名字节流长度


用于描述返回类型全名对应的字符串,UTF8编码后的字节流


用于标记返回序列化内容字节流长度


将返回内容进行序列化后,并经UTF8编码后的字节流

 /// <summary>
    /// 同步应答解析,反馈数据
    /// </summary>
    public class SyncResponseOutputFilterVersion1IsResult : IRMISplitResponseOutputFilter
    {
        private RMISerializeType serializeType;
        /// <summary>
        /// 序列化方式
        /// </summary>
        /// <param name="serializeType"></param>
        public SyncResponseOutputFilterVersion1IsResult(RMISerializeType serializeType)
        {
            this.serializeType = serializeType;
        }
        private object data;
        /// <summary>
        /// 反馈回的应答数据
        /// </summary>
        public object Data
        {
            get
            {
                return data;
            }
        }
        /// <summary>
        /// 正常数据解析处理
        /// </summary>
        /// <param name="buffer">执行体数据包</param>
        public void SetBuffer(byte[] buffer)
        {
            Trace.Common.Communication.MessageStatck.MessageStatckSplit messageStatckSplit = new Trace.Common.Communication.MessageStatck.MessageStatckSplit(buffer);
            IRMISerializble serialize = null;
            if (serializeType == RMISerializeType.Json)
            {
                serialize = new RMIJsonSerialize();
            }
            int readPaTypeLen = 0;
            if (messageStatckSplit.PopInt32(out readPaTypeLen) == false)
            {
                throw new Exception("返回类型长度获取失败");
            }
            string paTypeName;
            if (messageStatckSplit.PopUTF8String(out paTypeName, readPaTypeLen) == false)
            {
                throw new Exception("返回类型获取失败");
            }
            Type paType = Type.GetType(paTypeName);
            int contentLength = 0;
            if (messageStatckSplit.PopInt32(out contentLength) == false)
            {
                throw new Exception("返回内容长度获取失败");
            }
            if (contentLength > 0)
            {
                byte[] paBuffer = messageStatckSplit.PopBytes(contentLength);
                this.data = serialize.DeSerializeByUTF8(paType, paBuffer);
            }
        }
    }
时间: 2024-10-07 05:26:59

.net下的面向工控领域的远程方法调用(RMI)中间件,客户端协议栈应答端实现的相关文章

工控领域组态软件开发感触

从2001年进入工控领域以来,前后7年多的时间开发了诸如二型计量监控系统.焦炉四大机车自动化系统.烧结配水监控系统.隧道广告影像系统.通用组态软件.嵌入式系统组态软件(基于WINCE系统).LED视频影像系统和ICU病室输液管理等系统.其中焦炉四大机车自动化系统获得了国家专利,而隧道广告影像系统目前发展势头良好,在北京地铁(2号线.4号线),深圳地铁(罗宝线)都已实施安装,未来上海和国外也将安装该系统. 开发这些系统最大的感触就是,初次开发相对比较容易,但是后续系统扩展,维护相对较难,在系统架构

基于HTML5的Web SCADA工控移动应用

在电力.油田燃气.供水管网等工业自动化领域Web SCADA的概念已经提出了多年,早先年的Web SCADA前端技术大部分还是基于Flex.Silverlight甚至Applet这样的重客户端方案,在HTML5流行前VML和SVG算是真正纯种Web方案也是有不少应用,近些年随着HTML5的流行,加上移动终端对HTML5支持的普及,越来越多新项目开始采用真正纯HTML5的方案,更具体的说大数据量应用性能高于SVG的Canvas方案,已经逐渐成为当今Web SCADA前端技术的首选标配方案. htt

基于HT for Web的Web SCADA工控移动应用

在电力.油田燃气.供水管网等工业自动化领域Web SCADA的概念已经提出了多年,早先年的Web SCADA前端技术大部分还是基于Flex.Silverlight甚至Applet这样的重客户端方案,在HTML5流行前VML和SVG算是真正纯种Web方案也是有不少应用,近些年随着HTML5的流行,加上移动终端对HTML5支持的普及,越来越多新项目开始采用真正纯HTML5的方案,更具体的说大数据量应用性能高于SVG的Canvas方案,已经逐渐成为当今Web SCADA前端技术的首选标配方案. 最近客

工控信息网络隐患多 电网安防须步步为营

随着工业以太网的快速发展,工控系统网络信息安全问题日渐显露.以太网可能会遇到包括病毒感染.非法操作等网络安全隐患;而软件的漏洞.错误配置或者网络管理的失误也会造成工控网络异常;另外,工业控制系统网络与其他网络连接时缺乏安全边界控制,也是常见的安全隐患.2010年的震网病毒就是例证,最近的"棱镜门"事件又再次为信息网络安全敲响了警钟,对此,我们应当如何应对,这些安全隐患究其根底原因何在?另外,工信部451号文件(即<关于加强工业控制系统信息安全管理的通知>)已出台近两年,为何

工控安全入门之Modbus(转载)

工控安全这个领域比较封闭,公开的资料很少.我在读<Hacking Exposed Industrial Control Systems>,一本16年的书,选了的部分章节进行翻译,以其抛砖引玉. MODBUS Modbus是20世纪70年代后期由Modicon(现为施耐德电气)为了配合其可编程逻辑控制器(PLC)一起使用,创建的基于串行的控制协议.Modbus是最常见的工业控制协议,主要是因为Modbus是一种开放的简单而强大的协议,可以在没有任何版税的情况下开放使用.自从引入Modbus以来,

工控系统的指纹识别技术

转载:灯塔实验室 当前,指纹识别技术已被或坏或好的广泛应用于ICT(信息和通信技术)系统.攻击者通过扫描网络获取设备指纹来关联漏洞入侵系统,安全防护者则利用设备指纹来发现系统的脆弱性,检测系统的网络异常.在工业控制系统(ICS)中,指纹识别技术亦用于发现ICS系统脆弱性,检测攻击行为等方向.本文主要关注工控安全领域指纹识别技术. 指纹识别是什么 在ICT领域里,指纹识别是利用不同信息描述运行于网络中的设备或者软件的一种技术.我们了解最多的是设备指纹,被用来远程识别设备的硬件,操作系统,运行软件(

两款工控控件对比评测:Iocomp和ProEssentials

对于程序员来说,要凭一己之力开发出漂亮逼真的工控仪表和工控图表是非常耗时间和精力的,那么使用专业的第三方控件就是不错的选择,不仅节约开发时间,降低了项目风险,最重要的是第三方控件写的程序更专业,工控图表图像更精细.笔者认为最好用的工控控件当属 Iocomp 和 ProEssentials.下面笔者对这两个工控控件进行了简单的对比评测: Iocomp工控仪表 Iocomp公司可以说是工业仪表盘控件的龙头老大,在国内工业自动化集成商中,尤其是OPC项目,采用Iocomp产品进行仪表设计的项目越来越多

工控安全入门之Ethernet/IP

这一篇依然是协议层面的,协议层面会翻译三篇,下一篇是电力系统中用的比较多的DNP3.这一篇中大部分引用的资料都可以访问到,只有一篇reversemode.com上的writeup(http://reversemode.com/downloads/logix_report_basecamp.pdf)需要身份认证才能下载,如果有朋友能下载求分享. Ethernet/IP 与Modbus相比,EtherNet/IP 是一个更现代化的标准协议.由工作组ControlNetInternational与OD

工业控制系统信息安全与信息安全、功能安全的区别【转自工控工程网】

随着互联网的飞速发展,我国对于传统IT信息安全问题已有相关标准.法规,工业控制系统信息安全是否能依照而行?而在工业控制领域,一直以来备受关注的功能安全问题又与信息安全问题有着怎样的区别与联系?机械工业仪器仪表综合技术经济研究所所长欧阳劲松在接受记者采访时就以上问题进行了详细解读:   工业控制系统信息安全与传统IT信息安全的区别 传统IT信息安全一般是要实现三个目标,即保密性.完整性和可用性,通常都将保密性放在首位,并配以必要的访问控制,以保护用户信息的安全,防止信息盗取事件的发生.完整性放在第