NetPushClient.cs 5.95 KB
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HslCommunication.Core.Net;
using System.Net;
using System.Net.Sockets;

namespace HslCommunication.Enthernet
{

    /// <summary>
    /// 发布订阅类的客户端,使用指定的关键订阅相关的数据推送信息
    /// </summary>
    /// <remarks>
    /// 详细的使用说明,请参照博客<a href="http://www.cnblogs.com/dathlin/p/8992315.html">http://www.cnblogs.com/dathlin/p/8992315.html</a>
    /// </remarks>
    /// <example>
    /// 此处贴上了Demo项目的服务器配置的示例代码
    /// <code lang="cs" source="TestProject\HslCommunicationDemo\FormPushNet.cs" region="FormPushNet" title="NetPushClient示例" />
    /// </example>
    public class NetPushClient : NetworkXBase
    {
        #region Constructor

        /// <summary>
        /// 实例化一个发布订阅类的客户端,需要指定ip地址,端口,及订阅关键字
        /// </summary>
        /// <param name="ipAddress">服务器的IP地址</param>
        /// <param name="port">服务器的端口号</param>
        /// <param name="key">订阅关键字</param>
        public NetPushClient( string ipAddress, int port, string key )
        {
            endPoint = new IPEndPoint( IPAddress.Parse( ipAddress ), port );
            keyWord = key;

            if (string.IsNullOrEmpty( key ))
            {
                throw new Exception( StringResources.Language.KeyIsNotAllowedNull );
            }
        }

        #endregion

        #region NetworkXBase Override

        internal override void DataProcessingCenter( AppSession session, int protocol, int customer, byte[] content )
        {
            if(protocol == HslProtocol.ProtocolUserString)
            {
                action?.Invoke( this, Encoding.Unicode.GetString( content ) );
                OnReceived?.Invoke( this, Encoding.Unicode.GetString( content ) );
            }
        }

        internal override void SocketReceiveException( AppSession session, Exception ex )
        {
            // 发生异常的时候需要进行重新连接
            while (true)
            {
                Console.WriteLine( ex );
                Console.WriteLine( StringResources.Language.ReConnectServerAfterTenSeconds );
                System.Threading.Thread.Sleep( this.reconnectTime );

                if(CreatePush( ).IsSuccess)
                {
                    Console.WriteLine( StringResources.Language.ReConnectServerSuccess );
                    break;
                }
            }
        }

        #endregion
        
        #region Public Method 

        /// <summary>
        /// 创建数据推送服务
        /// </summary>
        /// <param name="pushCallBack">触发数据推送的委托</param>
        /// <returns>是否创建成功</returns>
        public OperateResult CreatePush( Action<NetPushClient, string> pushCallBack )
        {
            action = pushCallBack;
            return CreatePush( );
        }

        /// <summary>
        /// 创建数据推送服务,使用事件绑定的机制实现
        /// </summary>
        /// <returns>是否创建成功</returns>
        public OperateResult CreatePush( )
        {
            CoreSocket?.Close( );

            // 连接服务器
            OperateResult<Socket> connect = CreateSocketAndConnect( endPoint, 5000 );
            if (!connect.IsSuccess) return connect;

            // 发送订阅的关键字
            OperateResult send = SendStringAndCheckReceive( connect.Content, 0, keyWord );
            if (!send.IsSuccess) return send;

            // 确认服务器的反馈
            OperateResult<int, string> receive = ReceiveStringContentFromSocket( connect.Content );
            if (!receive.IsSuccess) return receive;

            // 订阅不存在
            if (receive.Content1 != 0)
            {
                connect.Content?.Close( );
                return new OperateResult( receive.Content2 );
            }

            // 异步接收
            AppSession appSession = new AppSession( );
            CoreSocket = connect.Content;
            appSession.WorkSocket = connect.Content;
            ReBeginReceiveHead( appSession, false );

            return OperateResult.CreateSuccessResult( );
        }
        
        /// <summary>
        /// 关闭消息推送的界面
        /// </summary>
        public void ClosePush()
        {
            action = null;
            if (CoreSocket != null && CoreSocket.Connected) CoreSocket?.Send( BitConverter.GetBytes( 100 ) );
            System.Threading.Thread.Sleep( 20 );
            CoreSocket?.Close( );
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// 本客户端的关键字
        /// </summary>
        public string KeyWord => keyWord;

        /// <summary>
        /// 获取或设置重连服务器的间隔时间
        /// </summary>
        public int ReConnectTime { set => reconnectTime = value; get => reconnectTime; }

        #endregion

        #region Public Event

        /// <summary>
        /// 当接收到数据的事件信息,接收到数据的时候触发。
        /// </summary>
        public event Action<NetPushClient, string> OnReceived;

        #endregion

        #region Private Member

        private IPEndPoint endPoint;                           // 服务器的地址及端口信息
        private string keyWord = string.Empty;                 // 缓存的订阅关键字
        private Action<NetPushClient, string> action;          // 服务器推送后的回调方法
        private int reconnectTime = 10000;                     // 重连服务器的时间

        #endregion

        #region Object Override

        /// <summary>
        /// 返回表示当前对象的字符串
        /// </summary>
        /// <returns>字符串</returns>
        public override string ToString( )
        {
            return $"NetPushClient[{endPoint}]";
        }

        #endregion
    }
}