Commit ce595cfd authored by 潘栩锋's avatar 潘栩锋 🚴

添加 WSCF 服务

parent 7e62d955
using FLY.Thick.Base.IService;
using FLY.Thick.Base.Server;
using FLY.Thick.FilmCasting.Common;
using FLY.Thick.FilmCasting.IService;
using FLY.Thick.FilmCasting.OBJ_INTERFACE;
using IInitParamService = FLY.Thick.FilmCasting.IService.IInitParamService;
namespace FLY.Thick.FilmCasting.Server.OBJProxy
{
public class OBJProxys
{
public OBJProxys(int objsys_idx, TDGage gage)
{
var jsonDistOBJProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.JSONDIST_ID,
typeof(OBJComponents.IService.IJsonDistService), new OBJComponents.Server.JsonDist());
var warnSystemOBJProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.WARNING_OBJ_ID,
typeof(OBJComponents.IService.IWarningSystem2Service), gage.warning);
var ioDefineObjProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.IO_ID,
typeof(IFlyAdIoDefineService), FlyADIODefine.Instance);
var gageOBJProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.TDGAGE_ID,
typeof(ITDGageService), gage);
var borderSearchOBJProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.BORDERSEARCH_ID,
typeof(IBorderSearchService), gage.borderSearch);
var curveOBJProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.CURVE_ID,
typeof(ICurveService), gage.curve);
var getSampleOBJProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.GET_SAMPLE_ID,
typeof(IGetSampleService), gage.getSample);
var initParamOBJProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.INITPARAM_ID,
typeof(IInitParamService),gage.initParam);
var scanCorrOBJProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.SCANCORR_ID,
typeof(IScanCorrService),gage.gmScanCorr);
var flyAdOBJProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.FLYAD_ID,
typeof(IFlyADService), gage.flyAdService);
var gageInfoOBJProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.GAGEINFO_ID,
typeof(IGageInfoService), gage.gmGageInfo);
var fixOBJProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.FIX_ID,
typeof(IFixService), gage.gmFix);
var profileOBJProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.PROFILE_ID,
typeof(IFilmCastingProfileService), gage.profile);
var scanWarningOBJProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.SCANWARNING_ID,
typeof(IScanWarningService), gage.scanWarning);
var boltMapOBJProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.BOLTMAP_ID,
typeof(IBoltMapFilmCastingService), gage.boltmap);
var bulkDbObjProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.BULKDB_ID,
typeof(IBulkDbService), gage.bulkDb);
var rejectObjProxy = new FObjBase.Reflect.Reflect_Proxy(objsys_idx, OBJ_INTERFACE_ID.REJECT_ID,
typeof(IRejectService), gage.reject);
}
}
}
using FLY.Thick.Base.IService;
using FLY.Thick.FilmCasting.Common;
using FLY.Thick.FilmCasting.IService;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WebSocketSharp.Server;
using IInitParamService = FLY.Thick.FilmCasting.IService.IInitParamService;
namespace FLY.Thick.FilmCasting.Server.WsProxy
{
public class WsProxys
{
public WsProxys(WebSocketServer wss, TDGage gage)
{
wss.AddWebSocketService<WSCF.Reflect_Proxy>("/thk/WarningSystem", (wsproxy) => wsproxy.Init(typeof(OBJComponents.IService.IWarningSystem2Service), gage.warning));
wss.AddWebSocketService<WSCF.Reflect_Proxy>("/thk/ThkGauge", (wsproxy) => wsproxy.Init(typeof(ITDGageService), gage));
wss.AddWebSocketService<WSCF.Reflect_Proxy>("/thk/BorderSearch", (wsproxy) => wsproxy.Init(typeof(IBorderSearchService), gage.borderSearch));
wss.AddWebSocketService<WSCF.Reflect_Proxy>("/thk/Curve", (wsproxy) => wsproxy.Init(typeof(ICurveService), gage.curve));
wss.AddWebSocketService<WSCF.Reflect_Proxy>("/thk/Getsample", (wsproxy) => wsproxy.Init(typeof(IGetSampleService), gage.getSample));
wss.AddWebSocketService<WSCF.Reflect_Proxy>("/thk/InitParam", (wsproxy) => wsproxy.Init(typeof(IInitParamService), gage.initParam));
wss.AddWebSocketService<WSCF.Reflect_Proxy>("/thk/ScanCorr", (wsproxy) => wsproxy.Init(typeof(IScanCorrService), gage.gmScanCorr));
wss.AddWebSocketService<WSCF.Reflect_Proxy>("/thk/FlyAd", (wsproxy) => wsproxy.Init(typeof(IFlyADService), gage.flyAdService));
wss.AddWebSocketService<WSCF.Reflect_Proxy>("/thk/Fix", (wsproxy) => wsproxy.Init(typeof(IFixService), gage.gmFix));
wss.AddWebSocketService<WSCF.Reflect_Proxy>("/thk/FilmCastingProfile", (wsproxy) => wsproxy.Init(typeof(IFilmCastingProfileService), gage.profile));
wss.AddWebSocketService<WSCF.Reflect_Proxy>("/thk/ScanWarning", (wsproxy) => wsproxy.Init(typeof(IScanWarningService), gage.scanWarning));
wss.AddWebSocketService<WSCF.Reflect_Proxy>("/thk/BoltMapFilmCasting", (wsproxy) => wsproxy.Init(typeof(IBoltMapFilmCastingService), gage.boltmap));
wss.AddWebSocketService<WSCF.Reflect_Proxy>("/thk/BulkDb", (wsproxy) => wsproxy.Init(typeof(IBulkDbService), gage.bulkDb));
wss.AddWebSocketService<WSCF.Reflect_Proxy>("/thk/Reject", (wsproxy) => wsproxy.Init(typeof(IRejectService), gage.reject));
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WSCF
{
//public delegate void AsyncCBHandler(object asyncContext, object retData);
}
This diff is collapsed.
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WSCF
{
///// <summary>
///// 注册 event 返回类型;
///// 客户端,默认使用 Trigger_xxxx(xxxx为event名称),作为触发事件的函数,该函数的参数类型就是EventArgsType;
///// </summary>
//public class PushAttribute : Attribute
//{
// public const string DefaultTriggerNameHeader = "Trigger_";
// public Type EventArgsType;
// public string TriggerName;
// public PushAttribute(Type eventArgsType)
// {
// EventArgsType = eventArgsType;
// }
// public PushAttribute(Type eventArgsType, string triggerName)
// {
// EventArgsType = eventArgsType;
// TriggerName = triggerName;
// }
//}
///// <summary>
///// 注册远程调用返回类型; 回调函数名称只能是 AsyncCBHandler asyncDelegate, object asyncContext
///// </summary>
//public class CallAttribute : Attribute
//{
// public Type ReponseType;
// public CallAttribute()
// {
// }
// public CallAttribute(Type reponseType)
// {
// ReponseType = reponseType;
// }
//}
///// <summary>
///// 注册 它的PropertyChanged 事件,且枚举它的子属性,
///// 找到[PropertyPush] 递归 注册下去
///// </summary>
//public class PropertyPushAttribute : Attribute
//{
//}
}
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WSCF
{
/// <summary>
/// 管理全部 XxxxServiceClient 的连接关系
/// </summary>
[JsonObject(MemberSerialization.OptIn)]
public class FObjServiceClientManager
{
NLog.ILogger logger = NLog.LogManager.GetCurrentClassLogger();
private static FObjServiceClientManager instance = null;
/// <summary>
/// 全局管理器
/// </summary>
public static FObjServiceClientManager Instance
{
get
{
if (instance == null)
{
instance = new FObjServiceClientManager();
instance.Load();
}
return instance;
}
}
/// <summary>
/// 连接地址
/// </summary>
[JsonProperty]
public List<ConnAddr> ConnAddrs { get; } = new List<ConnAddr>();
/// <summary>
/// 默认地址
/// </summary>
public List<ConnDefaultAddr> DefaultAddrs { get; } = new List<ConnDefaultAddr>();
/// <summary>
/// 连接到 另一个Obj系统
/// </summary>
/// <param name="connName"></param>
/// <param name="fObjClient"></param>
/// <returns></returns>
public string Connect_to_Another_OBJSys(string connName, WebSocketClient wsClient)
{
//找到地址
var connaddr = ConnAddrs.Find(c => c.ConnName == connName);
if (connaddr == null)
{
string addr = "0.0.0.1:12345";//没有默认值,创建连接到不存在的地址,避免出错
//没有,那就创建一个
//查找默认值
var defaultAddr = DefaultAddrs.Find(c => c.ConnName == connName);
if (defaultAddr != null)
addr = defaultAddr.Addr;
connaddr = new ConnAddr() { ConnName = connName, Addr = addr };
ConnAddrs.Add(connaddr);
}
if (!connaddr.Clients.Contains(wsClient))
{
connaddr.Clients.Add(wsClient);
}
return connaddr.Addr;
}
/// <summary>
/// 客户端注销时通知
/// </summary>
/// <param name="fObjClient"></param>
public void ObjClientDisponse(WebSocketClient wsClient)
{
if (string.IsNullOrEmpty(wsClient.ServiceName))
return;
var connaddr = ConnAddrs.Find(c => c.Clients.Contains(wsClient));
if(connaddr!=null)
connaddr.Clients.Remove(wsClient);
}
/// <summary>
/// 重连
/// </summary>
/// <param name="connName"></param>
/// <param name="addr"></param>
public void ReConnect(string connName, string addr)
{
//找到地址
var connaddr = ConnAddrs.Find(c => c.ConnName == connName);
if (connaddr == null)
{
//没有!!!!,失败!!!
logger.Error($"ReConnect({connaddr},{addr}), 不能找到 ConnAddr");
return;
}
connaddr.Addr = addr;
//通知全部客户重连
foreach (var client in connaddr.Clients) {
client.ReConnect(addr);
}
}
string filename = "serviceManager.json";
string file_default_path = "default/serviceManager.default.json";
void LoadDefault()
{
if (!File.Exists(file_default_path))
return;
try
{
string json = File.ReadAllText(file_default_path);
var p = JsonConvert.DeserializeObject<List<ConnDefaultAddr>>(json);
DefaultAddrs.AddRange(p);
}
catch (Exception e)
{
}
}
/// <summary>
/// 加载配置
/// </summary>
void Load()
{
LoadDefault();
if (File.Exists(filename))
{
try
{
string json = File.ReadAllText(filename);
JsonConvert.PopulateObject(json, this);
}
catch
{
}
}
}
/// <summary>
/// 保存配置
/// </summary>
public void Save()
{
try
{
string json = JsonConvert.SerializeObject(this, Formatting.Indented);
File.WriteAllText(filename, json);
}
catch
{
}
}
}
/// <summary>
/// 连接地址
/// </summary>
[JsonObject(MemberSerialization.OptIn)]
public class ConnAddr
{
/// <summary>
/// 连接器名称
/// </summary>
[JsonProperty]
public string ConnName;
/// <summary>
/// 设备地址
/// </summary>
[JsonProperty]
public string Addr;
/// <summary>
/// 客户端 服务代理Id
/// </summary>
public List<WebSocketClient> Clients = new List<WebSocketClient>();
}
public class ConnDefaultAddr
{
/// <summary>
/// 连接器名称
/// </summary>
public string ConnName;
/// <summary>
/// 设备地址
/// </summary>
public string Addr;
}
}
<?xml version="1.0" encoding="utf-8"?>
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<PropertyChanged />
</Weavers>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="PropertyChanged" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="InjectOnPropertyNameChanged" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if the On_PropertyName_Changed feature is enabled.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="TriggerDependentProperties" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if the Dependent properties feature is enabled.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="EnableIsChangedProperty" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if the IsChanged property feature is enabled.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="EventInvokerNames" type="xs:string">
<xs:annotation>
<xs:documentation>Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="CheckForEquality" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="CheckForEqualityUsingBaseEquals" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if equality checks should use the Equals method resolved from the base class.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UseStaticEqualsFromBase" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to control if equality checks should use the static Equals method resolved from the base class.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="SuppressWarnings" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to turn off build warnings from this weaver.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="SuppressOnPropertyNameChangedWarning" type="xs:boolean">
<xs:annotation>
<xs:documentation>Used to turn off build warnings about mismatched On_PropertyName_Changed methods.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
\ No newline at end of file
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using static WSCF.Reflect_OBJ_INTERFACE;
namespace WSCF
{
public interface IReflectSeviceClientCore: INotifyPropertyChanged
{
bool IsConnected { get; set; }
/// <summary>
/// 已经同步完成;
/// 已经收到了 CALL_GetAllProperties, 全部属性都与服务器一致
/// </summary>
bool IsSynced { get; set; }
/// <summary>
/// 当前 INotifyPropertyChanged 对象 引发了 PropertyChanged, 是由于 接收到数据导致的
/// </summary>
bool IsInPushValue { get; set; }
}
}
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("WebSocket Communication Foundation")]
[assembly: AssemblyDescription("基于 WebSocket 通讯框架")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("佛山市枫莱尔自动化技术有限公司")]
[assembly: AssemblyProduct("WSCF")]
[assembly: AssemblyCopyright("Copyright © 2021 FlyAutomation")]
[assembly: AssemblyTrademark("FlyAutomation")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("712d814b-00b7-4dec-8105-fe06f25d36a1")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("2.1.0.0")]
[assembly: AssemblyFileVersion("2.1.0.0")]
using Newtonsoft.Json.Linq;
namespace WSCF
{
public class Reflect_OBJ_INTERFACE
{
public const string paramName_asyncDelegate = "asyncDelegate";
public const string paramName_asyncContext = "asyncContext";
/// <summary>
/// PkgData 的 data 实体
/// </summary>
public class NameData
{
public string name;
public JToken data;
}
/// <summary>
///
/// </summary>
public class PkgData
{
/// <summary>
/// 客户端 中全局唯一 交易 id
/// </summary>
public string guid;
/// <summary>
/// PkgName 的 string
/// </summary>
public string name;
/// <summary>
/// 数据包实体
/// </summary>
public JToken data;
public PkgData() { }
/// <summary>
/// 正向控制 通讯包
/// </summary>
/// <param name="name"></param>
/// <param name="guid"></param>
/// <param name="data"></param>
public PkgData(string name, string guid, JToken data)
{
this.name = name;
this.guid = guid;
this.data = data;
}
}
}
}
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using WebSocketSharp;
using WebSocketSharp.Server;
using static WSCF.Reflect_OBJ_INTERFACE;
namespace WSCF
{
/// <summary>
/// obj 服务代理;
/// 1.如果代理的对象为 INotifyPropertyChanged, 对象内的 property 改变,能推送给客户端( [JsonIgnore] 除外);
/// 2.代理的对象不为INotifyPropertyChanged, 但 对象内的 property
/// a.是 [PropertyPush],
/// b.且是 INotifyPropertyChanged,
/// c.且 只能是get,不能有set,
/// 那这个 property 内的 子property 改变,也会推送给 客户端 且 子property 是 [PropertyPush],会继续向下全部注册 PropertyChanged,
/// 也推送给 客户端;
/// 3. 客户端 可以通过 Call(.....) 调用 服务 的function, function返回的内容,需要通过[Call(...)] 定义; 且function 必须是
/// void function(object param1, object param2,object paramN, AsyncCBHandler asyncDelegate, object asyncContext);
/// 必须有参数 AsyncCBHandler asyncDelegate, object asyncContext, 名字不能改。 前面的 param1~paramN, 多少个都行
/// 4. 服务中的event, 通过 [Push(...)] 可以推送给客户端, 但event 只能是 EventHandler
/// [Push(typeof(BulkDBTempFrameChangedEventArgs))]
/// public event EventHandler TempFrameChanged;
///
/// </summary>
public class Reflect_Proxy:WebSocketBehavior, IDisposable
{
/// <summary>
/// 服务器中, 提供的全部服务
/// </summary>
protected WsServiceProxy Proxy;
public Reflect_Proxy()
{
}
public void Init(Type interfaceType, INotifyPropertyChanged obj)
{
var proxy = new WsServiceProxy();
proxy.Init(interfaceType, obj);
proxy.SetSendEx(SendTo);
Proxy = proxy;
}
protected override void OnMessage(MessageEventArgs e)
{
if (!e.IsText)
return;
string json = e.Data;
var pkgData = Newtonsoft.Json.JsonConvert.DeserializeObject<PkgData>(json);
//客户端 向 服务器 中的 服务 请求
Proxy.OnMessage(this, pkgData);
}
protected override void OnOpen()
{
base.OnOpen();
Proxy.OnOpen();
}
protected override void OnClose(CloseEventArgs e)
{
base.OnClose(e);
Proxy.OnClose();
}
public virtual void SendTo(string msg)
{
if (this.State != WebSocketState.Open)
return;
base.Send(msg);
}
public void Dispose()
{
Proxy.Dispose();
}
}
}
using FObjBase;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace WSCF
{
public abstract class Reflect_SeviceClient : WebSocketClient, IDisposable, IReflectSeviceClientCore
{
/// <summary>
/// 代理对象 接口类型
/// </summary>
protected abstract Type InterfaceType { get; }
/// <summary>
/// 已经同步完成;
/// 已经收到了 CALL_GetAllProperties, 全部属性都与服务器一致
/// </summary>
public bool IsSynced { get; set; }
/// <summary>
/// 当前 INotifyPropertyChanged 对象 引发了 PropertyChanged, 是由于 接收到数据导致的
/// </summary>
public bool IsInPushValue { get; set; }
ReflectSeviceClientAssistant assistant;
public Reflect_SeviceClient(string serverName,bool isByConnName, string addrOrConnName)
{
if (isByConnName == false)
{
base.Init(serverName, addrOrConnName);
}
else {
base.InitByConnName(serverName, addrOrConnName);
}
assistant = new ReflectSeviceClientAssistant();
assistant.Init(InterfaceType, this);
assistant.SetSendEx(Send);
}
protected override void OnOpen()
{
assistant.OnOpen();
}
protected override void OnMessage(string msg)
{
var pkgData = JsonConvert.DeserializeObject<Reflect_OBJ_INTERFACE.PkgData>(msg);
OnMessage(pkgData);
}
protected virtual void OnMessage(Reflect_OBJ_INTERFACE.PkgData pkgData)
{
assistant.OnMessage(pkgData);
}
protected override void OnClose()
{
assistant.OnClose();
}
protected void Call(string methodName, object parameters, AsyncCBHandler asyncDelegate, object asyncContext)
{
assistant.Call(methodName, parameters, asyncDelegate, asyncContext);
}
protected void Call(string methodName, object parameters)
{
Call(methodName, parameters, null, null);
}
protected void Call(string methodName)
{
Call(methodName, null, null, null);
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{712D814B-00B7-4DEC-8105-FE06F25D36A1}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>WSCF</RootNamespace>
<AssemblyName>WSCF</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<Deterministic>true</Deterministic>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="AsyncCBHandler.cs" />
<Compile Include="ReflectSeviceClientAssistant.cs" />
<Compile Include="WsServiceProxy.cs" />
<Compile Include="CallAttribute.cs" />
<Compile Include="COMMON.cs" />
<Compile Include="FObjServiceClientManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReflectData.cs" />
<Compile Include="Reflect_Proxy.cs" />
<Compile Include="Reflect_SeviceClient.cs" />
<Compile Include="WebSocketClient.cs" />
<Compile Include="IReflectSeviceClientCore.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json">
<Version>13.0.2</Version>
</PackageReference>
<PackageReference Include="NLog">
<Version>5.1.0</Version>
</PackageReference>
<PackageReference Include="PropertyChanged.Fody">
<Version>4.1.0</Version>
</PackageReference>
<PackageReference Include="WebSocketSharp-netstandard">
<Version>1.0.1</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\thick_public\Project.FLY.FObjSys\FObjBaseReflect\FObjBase.Reflect.csproj">
<Project>{15f40c32-d546-4b2a-8d80-b3ddbcdaa690}</Project>
<Name>FObjBase.Reflect</Name>
</ProjectReference>
<ProjectReference Include="..\..\thick_public\Project.FLY.FObjSys\FObjSys\FObjBase.csproj">
<Project>{abfe87d4-b692-4ae9-a8c0-1f470b8acbb8}</Project>
<Name>FObjBase</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WebSocketSharp;
namespace WSCF
{
public abstract class WebSocketClient: INotifyPropertyChanged, IDisposable
{
public event PropertyChangedEventHandler PropertyChanged;
public bool IsConnected { get; set; }
/// <summary>
/// 重连剩余秒数
/// </summary>
public int RetrySurplusSec { get; private set; }
Stopwatch retry_stopwatch = new Stopwatch();
System.Timers.Timer retry_timer;
public string ServiceName;
protected WebSocket ws;
System.Timers.Timer ping_timer;
public WebSocketClient()
{
//断开重连 定时器
retry_timer = new System.Timers.Timer();
retry_timer.AutoReset = true;
retry_timer.Interval = 1000;
retry_timer.Elapsed += Retry_timer_Elapsed;
//长时间没有通讯 测试连接状态 定时器
ping_timer = new System.Timers.Timer();
ping_timer.AutoReset = true;
ping_timer.Interval = 10000;
ping_timer.Elapsed += Ping_timer_Elapsed;
//建立 websocket 连接
//this.ServiceName = serviceName;
}
protected void Init(string serviceName, string addr)
{
this.ServiceName = serviceName;
ws = new WebSocket($"ws://{addr}/{ServiceName}");
ws.OnMessage += Ws_OnMessage;
ws.OnOpen += Ws_OnOpen;
ws.OnClose += Ws_OnClose;
Retry();
Task.Factory.StartNew(() =>
{
ws.Connect();
});
}
public void InitByConnName(string serviceName,string connName)
{
var addr = FObjServiceClientManager.Instance.Connect_to_Another_OBJSys(connName, this);
Init(serviceName, addr);
}
bool ping_timer_ing = false;
private void Ping_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (ping_timer_ing)
return;
ping_timer_ing = true;
ws.Ping();
ping_timer_ing = false;
}
bool retry_timer_ing = false;
private void Retry_timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (retry_timer_ing)
return;
retry_timer_ing = true;
if (UpdateRetryStatus())
{
Retry();//正常应该StopRetry() 怕它不会触发 Ws_OnClose, 只有当 OnOpen 才 StopRetry()
ws.Connect();
}
retry_timer_ing = false;
}
public void TouchPing()
{
ping_timer.Stop();
ping_timer.Start();
}
void StopPing()
{
ping_timer.Stop();
}
public void ReConnect(string addr)
{
if (ws == null)
{
Init(ServiceName, addr);
return;
}
ws.Close();
ws.OnMessage -= Ws_OnMessage;
ws = new WebSocket($"ws://{addr}/{ServiceName}");
ws.OnMessage += Ws_OnMessage;
ws.OnOpen += Ws_OnOpen;
ws.OnClose += Ws_OnClose;
Retry();//正常应该StopRetry() 怕它不会触发 Ws_OnClose, 只有当 OnOpen 才 StopRetry()
Task.Factory.StartNew(() =>
{
ws.Connect();
});
}
void Retry()
{
retry_stopwatch.Restart();
UpdateRetryStatus();
//5秒后再尝试连接
retry_timer.Stop();
retry_timer.Start();
}
void StopRetry()
{
retry_stopwatch.Stop();
retry_timer.Stop();
}
bool UpdateRetryStatus()
{
TimeSpan elapsed = TimeSpan.FromSeconds(5) - retry_stopwatch.Elapsed;
RetrySurplusSec = (int)(((elapsed > TimeSpan.Zero) ? elapsed : TimeSpan.Zero).TotalSeconds);
return (RetrySurplusSec <= 0);
}
private void Ws_OnClose(object sender, CloseEventArgs e)
{
IsConnected = false;
Retry();
StopPing();
OnClose();
}
private void Ws_OnOpen(object sender, EventArgs e)
{
IsConnected = true;
StopRetry();
OnOpen();
}
private void Ws_OnMessage(object sender, MessageEventArgs e)
{
if (!e.IsText)
return;
OnMessage(e.Data);
}
public virtual void Dispose()
{
ws.Close();
FObjServiceClientManager.Instance.ObjClientDisponse(this);
}
protected void Send(string data)
{
ws.Send(data);
TouchPing();
}
protected abstract void OnMessage(string msg);
protected abstract void OnOpen();
protected abstract void OnClose();
}
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment