/// <summary>
        /// 创建简单 HPSocket.IServer 服务端对象,并创建匿名监听事件。
        /// <para>建议使用 <see cref="DisposeServer(HPSocket.IServer, log4net.ILog)"/> 断开销毁客户端对象。 </para>
        /// <para>&lt;IServer&gt; 类型约束实现 <see cref="HPSocket.IServer"/> 接口,参考: <see cref="HPSocket.Tcp.TcpServer"/>, <see cref="HPSocket.Udp.UdpServer"/> ... </para>
        /// </summary>
        /// <typeparam name="IServer">&lt;IServer&gt; 类型约束实现 <see cref="HPSocket.IServer"/> 接口,参考: <see cref="HPSocket.Tcp.TcpServer"/>, <see cref="HPSocket.Udp.UdpServer"/> ... </typeparam>
        /// <param name="localPort">绑定的本机端口号</param>
        /// <param name="receivedCallback">客户端数据接收回调函数</param>
        /// <exception cref="ArgumentException"></exception>
        /// <returns>返回 <see cref="HPSocket.IServer"/> 实例对象。</returns>
        public static IServer CreateServer <IServer>(ushort localPort, Action <IntPtr, byte[]> receivedCallback)
            where IServer : class, HPSocket.IServer, new()
        {
            if (localPort <= 0 || receivedCallback == null)
            {
                throw new ArgumentException("参数不能为空");
            }

            IServer server = new IServer()
            {
                Port = localPort,
                MaxConnectionCount = 255,
            };

            server.OnAccept += (HPSocket.IServer sender, IntPtr connId, IntPtr client) =>
            {
                ushort port = 0;
                string ip   = "0.0.0.0";
                server.GetRemoteAddress(connId, out ip, out port);
                SpaceCGUtils.Log.InfoFormat("客户端 {0}:{1} 连接成功", ip, port);

                return(HPSocket.HandleResult.Ok);
            };
            server.OnReceive += (HPSocket.IServer sender, IntPtr connId, byte[] data) =>
            {
                receivedCallback?.Invoke(connId, data);
                return(HPSocket.HandleResult.Ok);
            };
            server.OnClose += (HPSocket.IServer sender, IntPtr connId, HPSocket.SocketOperation socketOperation, int errorCode) =>
            {
                ushort port = 0;
                string ip   = "0.0.0.0";
                server.GetRemoteAddress(connId, out ip, out port);
                string message = Kernel32Extension.GetSysErrroMessage((uint)errorCode);
                SpaceCGUtils.Log.InfoFormat("客户端 {0}:{1} 断开连接({2}),描述:({3}) {4}", ip, port, socketOperation, errorCode, message);

                return(HPSocket.HandleResult.Ok);
            };

            bool result = server.Start();

            SpaceCGUtils.Log.InfoFormat("服务端({0}) {1}:{2} {3}", typeof(IServer), server.Address, server.Port, result ? "已启动监听" : "启动失败");

            return(server);
        }
        public static DeviceInfo GetDevice(int vid, int pid)
        {
            string[] paths = HIDExtension.GetHIDDevicesPath();

            for (int i = 0; i < paths.Length; i++)
            {
                Console.WriteLine(paths[i]);
                IntPtr handle = Kernel32.Kernel32.CreateFile(paths[i], 3221225472u, 3, IntPtr.Zero, 3, 0x40000000, IntPtr.Zero);
                if (handle == IntPtr.Zero)
                {
                    Console.WriteLine("SafeFileHandle IsInvalid");
                    Console.WriteLine(Kernel32Extension.GetSysErrroMessage("CreateFile"));
                    continue;
                }

                HIDD_ATTRIBUTES attributes = new HIDD_ATTRIBUTES();
                bool            result1    = HIDExtension.GetHIDDeviceAttributes(new SafeFileHandle(handle, true), ref attributes);
                if (!result1)
                {
                    Console.WriteLine("GetHIDDeviceAttributes Error");
                    continue;
                }
                Console.WriteLine(attributes);

                HIDP_CAPS caps    = new HIDP_CAPS();
                bool      result2 = HIDExtension.GetHIDDeviceCapabilities(new SafeFileHandle(handle, true), ref caps);
                if (!result2)
                {
                    Console.WriteLine("GetHIDDeviceCapabilities Error.");
                    continue;
                }

                if (attributes.VendorID == vid && attributes.ProductID == pid && caps.InputReportByteLength > 0)
                {
                    Console.WriteLine("{0}  {1}", HIDExtension.GetHidUsage(caps), caps);
                    if (caps.InputReportByteLength > 0)
                    {
                        Console.WriteLine("Index::{0}", i);
                    }

                    int  numberBuffer = 0;
                    bool result3      = HID.HidD_GetNumInputBuffers(new SafeFileHandle(handle, true), ref numberBuffer);
                    Console.WriteLine("result3:{0} {1}", result3, numberBuffer);

                    byte[] inputReportBuffer = new byte[caps.InputReportByteLength];
                    bool   result4           = HID.HidD_GetInputReport(new SafeFileHandle(handle, true), inputReportBuffer, inputReportBuffer.Length + 1);
                    Console.WriteLine("result4:{0}", result4);

                    DeviceInfo device = new DeviceInfo();
                    device.Path         = paths[i];
                    device.Capabilities = caps;
                    device.Attributes   = attributes;
                    device.HidUsage     = GetHidUsage(caps);

                    /*
                     * device.HidHandle = Kernel32.Kernel32.CreateFile(paths[i],
                     *   0u,//AccessRights.GENERIC_READ | AccessRights.GENERIC_WRITE,
                     *   ShareMode.FILE_SHARE_READ | ShareMode.FILE_SHARE_WRITE,
                     *   IntPtr.Zero,
                     *   CreationDisposition.OPEN_EXISTING,
                     *   0,
                     *   IntPtr.Zero);
                     */
                    device.HidHandle         = new SafeFileHandle(handle, true);
                    device.InputReportLength = caps.InputReportByteLength;
                    //bool gib = HID.HidD_GetNumInputBuffers(handle, ref device.InputReportLength);
                    //Console.WriteLine("GNIB:{0} {1}", gib, device.InputReportLength);

                    device.FileStream = new FileStream(device.HidHandle, FileAccess.ReadWrite, caps.InputReportByteLength, true);
                    HID.HidD_FlushQueue(device.HidHandle);

                    return(device);
                }
            }

            return(null);// deviceList.ToArray();
        }
        /// <summary>
        /// 创建 HPSocket.IClient 客户端连接对象,并创建匿名监听事件。如果只关心数据的接收/处理,适用此方法,其它事件状态会记录在日志中。
        /// <para>建议使用 <see cref="DisposeClient(HPSocket.IClient, log4net.ILog)"/> 断开销毁客户端对象。 </para>
        /// <para> &lt;IClient&gt; 类型约束实现 <see cref="HPSocket.IClient"/> 接口,参考: <see cref="HPSocket.Tcp.TcpClient"/>, <see cref="HPSocket.Udp.UdpClient"/>, <see cref="HPSocket.Udp.UdpCast"/> ... </para>
        /// </summary>
        /// <typeparam name="IClient">&lt;IClient&gt; 类型约束实现 <see cref="HPSocket.IClient"/> 接口,参考: <see cref="HPSocket.Tcp.TcpClient"/>, <see cref="HPSocket.Udp.UdpClient"/>, <see cref="HPSocket.Udp.UdpCast"/> ...</typeparam>
        /// <param name="remoteAddress">远程服务端地址</param>
        /// <param name="remotePort">远程服务端端口</param>
        /// <param name="receivedCallback">数据接收回调</param>
        /// <param name="autoConnect">断开后是否自动连接,等待 3000ms 后重新连接</param>
        /// <exception cref="ArgumentException"></exception>
        /// <returns>返回 <see cref="HPSocket.IClient"/> 实例对象。</returns>
        public static IClient CreateClient <IClient>(string remoteAddress, ushort remotePort, Action <HPSocket.IClient, byte[]> receivedCallback, bool autoConnect = true)
            where IClient : class, HPSocket.IClient, new()
        {
            if (string.IsNullOrWhiteSpace(remoteAddress) || remotePort <= 0 || receivedCallback == null)
            {
                throw new ArgumentException("参数设置错误");
            }

            IClient client = new IClient()
            {
                Async              = true,
                Port               = remotePort,
                Address            = remoteAddress,
                FreeBufferPoolSize = 64,        //默认:60
                FreeBufferPoolHold = 64 * 3,    //默认:60
            };

            int Timeout = 1000;         // 等待重新连接挂起的毫秒数
            //client.ExtraData = true;
            bool IsAvailable = true;    // 网络是否可用,指本机网络配置,或是物理网络是否断开
            // 检查远程服务地址,是否为本机地址
            bool        IsLocalAddress = remoteAddress == "0.0.0.0" || remoteAddress == "127.0.0.1";
            IPHostEntry entry          = Dns.GetHostEntry(Dns.GetHostName());

            foreach (IPAddress ip in entry.AddressList)
            {
                IsLocalAddress = IsLocalAddress || remoteAddress == ip.ToString();
            }

            //监听事件
            client.OnConnect += (HPSocket.IClient sender) =>
            {
                Timeout = 1000;
                ushort localPort = 0;
                string localAddr = null;
                client.GetListenAddress(out localAddr, out localPort);
                SpaceCGUtils.Log.InfoFormat("客户端({0}) {1}:{2} 连接成功", typeof(IClient), localAddr, localPort);

                return(HPSocket.HandleResult.Ok);
            };
            client.OnReceive += (HPSocket.IClient sender, byte[] data) =>
            {
                receivedCallback?.Invoke(sender, data);
                return(HPSocket.HandleResult.Ok);
            };
            client.OnClose += (HPSocket.IClient sender, HPSocket.SocketOperation enOperation, int errorCode) =>
            {
                string message = Kernel32Extension.GetSysErrroMessage((uint)errorCode);
                SpaceCGUtils.Log.InfoFormat("客户端({0})连接被断开({1}),描述:({2}) {3}", typeof(IClient), enOperation, errorCode, message);

                if (IsAvailable && autoConnect)
                //if (client.ExtraData != null && (bool)client.ExtraData && autoConnect)
                {
                    SpaceCGUtils.Log.InfoFormat("客户端等待 {0}ms 后,重尝试重新连接", Timeout);

                    Task.Run(() =>
                    {
                        Thread.Sleep(Timeout);
                        Console.WriteLine("client....client");
                        client.Connect();
                        Timeout = Timeout >= 10000 ? Timeout : Timeout + 1000;
                    });
                }

                return(HPSocket.HandleResult.Ignore);
            };

            //连接服务
            bool result = client.Connect();

            // 非本机地址,监听网络的可用性
            if (!IsLocalAddress)
            {
                NetworkChange.NetworkAvailabilityChanged += (object sender, NetworkAvailabilityEventArgs e) =>
                {
                    if (client == null)
                    {
                        return;
                    }
                    SpaceCGUtils.Log.InfoFormat("网络的可用性发生变化,Network Change, IsAvailable : {0}", e.IsAvailable);

                    Timeout     = 1000;
                    IsAvailable = e.IsAvailable;
                    //client.ExtraData = e.IsAvailable;

                    if (!e.IsAvailable && client.IsConnected)
                    {
                        client.Stop();
                    }
                    if (e.IsAvailable && !client.IsConnected)
                    {
                        client.Connect();
                    }
                };
            }
            else
            {
                SpaceCGUtils.Log.InfoFormat("客户端({0})连接的为本地网络服务地址:{1} ,未监听网络的可用性变化。", typeof(IClient), remoteAddress);
            }

            return(client);
        }