diff --git a/src/dotnetCampus.Ipc/CompilerServices/GeneratedProxies/Models/GeneratedProxyMemberInvokeModel.cs b/src/dotnetCampus.Ipc/CompilerServices/GeneratedProxies/Models/GeneratedProxyMemberInvokeModel.cs index 96843765..946a3689 100644 --- a/src/dotnetCampus.Ipc/CompilerServices/GeneratedProxies/Models/GeneratedProxyMemberInvokeModel.cs +++ b/src/dotnetCampus.Ipc/CompilerServices/GeneratedProxies/Models/GeneratedProxyMemberInvokeModel.cs @@ -1,11 +1,14 @@ -using System.Diagnostics.CodeAnalysis; +using System; +using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Runtime.Serialization; using System.Text; using dotnetCampus.Ipc.CompilerServices.GeneratedProxies.Models; +using dotnetCampus.Ipc.Context; using dotnetCampus.Ipc.Messages; using dotnetCampus.Ipc.Serialization; +using dotnetCampus.Ipc.Utils.Extensions; namespace dotnetCampus.Ipc.CompilerServices.GeneratedProxies { @@ -69,7 +72,11 @@ public string Id /// public static IpcMessage Serialize(GeneratedProxyMemberInvokeModel model) { - return JsonIpcMessageSerializer.Serialize(model.ToString(), model); + // 加上头信息 + var serializeMessage = JsonIpcMessageSerializer.Serialize(model.ToString(), model); + + return new IpcMessage(serializeMessage.Tag, serializeMessage.Body, + (ulong) KnownMessageHeaders.RemoteObjectMessageHeader); } /// @@ -80,7 +87,19 @@ public static IpcMessage Serialize(GeneratedProxyMemberInvokeModel model) /// public static bool TryDeserialize(IpcMessage message, [NotNullWhen(true)] out GeneratedProxyMemberInvokeModel? model) { - return JsonIpcMessageSerializer.TryDeserialize(message, out model); + if (message.TryReadBusinessHeader(out var header) && header == (ulong) KnownMessageHeaders.RemoteObjectMessageHeader) + { + // 跳过业务头的消息内容 + var deserializeMessage = message.Skip(sizeof(ulong)); + + return JsonIpcMessageSerializer.TryDeserialize(deserializeMessage, out model); + } + else + { + // 如果业务头不对,那就不需要解析了 + model = null; + return false; + } } /// diff --git a/src/dotnetCampus.Ipc/CompilerServices/GeneratedProxies/Models/GeneratedProxyMemberReturnModel.cs b/src/dotnetCampus.Ipc/CompilerServices/GeneratedProxies/Models/GeneratedProxyMemberReturnModel.cs index a3ada21b..d2603a99 100644 --- a/src/dotnetCampus.Ipc/CompilerServices/GeneratedProxies/Models/GeneratedProxyMemberReturnModel.cs +++ b/src/dotnetCampus.Ipc/CompilerServices/GeneratedProxies/Models/GeneratedProxyMemberReturnModel.cs @@ -3,8 +3,10 @@ using System.Runtime.Serialization; using dotnetCampus.Ipc.CompilerServices.GeneratedProxies.Models; +using dotnetCampus.Ipc.Context; using dotnetCampus.Ipc.Messages; using dotnetCampus.Ipc.Serialization; +using dotnetCampus.Ipc.Utils.Extensions; namespace dotnetCampus.Ipc.CompilerServices.GeneratedProxies { @@ -56,12 +58,27 @@ public GeneratedProxyMemberReturnModel(Exception exception) public static IpcMessage Serialize(GeneratedProxyMemberReturnModel model) { - return JsonIpcMessageSerializer.Serialize("Return", model); + var serializeMessage = JsonIpcMessageSerializer.Serialize("Return", model); + + return new IpcMessage(serializeMessage.Tag, serializeMessage.Body, + (ulong) KnownMessageHeaders.RemoteObjectMessageHeader); } public static bool TryDeserialize(IpcMessage message, [NotNullWhen(true)] out GeneratedProxyMemberReturnModel? model) { - return JsonIpcMessageSerializer.TryDeserialize(message, out model); + if (message.TryReadBusinessHeader(out var header) && header == (ulong) KnownMessageHeaders.RemoteObjectMessageHeader) + { + // 跳过业务头的消息内容 + var deserializeMessage = message.Skip(sizeof(ulong)); + + return JsonIpcMessageSerializer.TryDeserialize(deserializeMessage, out model); + } + else + { + // 如果业务头不对,那就不需要解析了 + model = null; + return false; + } } } } diff --git a/src/dotnetCampus.Ipc/CompilerServices/GeneratedProxies/Utils/IpcProxyInvokingHelper.cs b/src/dotnetCampus.Ipc/CompilerServices/GeneratedProxies/Utils/IpcProxyInvokingHelper.cs index 2c479bae..1957551f 100644 --- a/src/dotnetCampus.Ipc/CompilerServices/GeneratedProxies/Utils/IpcProxyInvokingHelper.cs +++ b/src/dotnetCampus.Ipc/CompilerServices/GeneratedProxies/Utils/IpcProxyInvokingHelper.cs @@ -93,7 +93,7 @@ internal string TypeName } var requestMessage = GeneratedProxyMemberInvokeModel.Serialize(model); - requestMessage = new IpcMessage(requestMessage.Tag, requestMessage.Body, CoreMessageType.JsonObject); + //requestMessage = new IpcMessage(requestMessage.Tag, requestMessage.Body, CoreMessageType.JsonObject); var responseMessage = await PeerProxy.GetResponseAsync(requestMessage).ConfigureAwait(false); if (GeneratedProxyMemberReturnModel.TryDeserialize(responseMessage, out var returnModel)) { diff --git a/src/dotnetCampus.Ipc/Context/KnownMessageHeaders.cs b/src/dotnetCampus.Ipc/Context/KnownMessageHeaders.cs new file mode 100644 index 00000000..419d6c2b --- /dev/null +++ b/src/dotnetCampus.Ipc/Context/KnownMessageHeaders.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace dotnetCampus.Ipc.Context; + +/// +/// 已知的消息头 +/// +/// 现在已有三套通讯方法: +/// - RemoteObject +/// - MVC +/// - Raw +/// 其中 Raw 不加头,完全都裸通讯方式 +public enum KnownMessageHeaders : ulong +{ + /// + /// 发送的消息是 RemoteObject 通讯的消息 + /// + RemoteObjectMessageHeader + // 消息头是 R(e)m(ote)O(b)j(ect) 的 RmOj 几个字符组成的 long 头 + = 0x526D4F6A, +} diff --git a/src/dotnetCampus.Ipc/IpcMessageCommandType.cs b/src/dotnetCampus.Ipc/IpcMessageCommandType.cs index 865e1d43..fdeedb04 100644 --- a/src/dotnetCampus.Ipc/IpcMessageCommandType.cs +++ b/src/dotnetCampus.Ipc/IpcMessageCommandType.cs @@ -41,35 +41,35 @@ internal enum IpcMessageCommandType : short /// ResponseMessage = (1 << 2) | Business, - /// - /// 请求的细分类型,IPC 框架无法识别和处理此消息体。 - /// - RawRequestMessage = (1 << 3) | RequestMessage, + ///// + ///// 请求的细分类型,IPC 框架无法识别和处理此消息体。 + ///// + //RawRequestMessage = (1 << 3) | RequestMessage, - /// - /// 响应的细分类型,IPC 框架无法识别和处理此消息体。 - /// - RawResponseMessage = (1 << 3) | ResponseMessage, + ///// + ///// 响应的细分类型,IPC 框架无法识别和处理此消息体。 + ///// + //RawResponseMessage = (1 << 3) | ResponseMessage, - /// - /// 请求的细分类型,IPC 框架知道此消息体是可被处理的字符串。 - /// - StringRequestMessage = (1 << 4) | RequestMessage, + ///// + ///// 请求的细分类型,IPC 框架知道此消息体是可被处理的字符串。 + ///// + //StringRequestMessage = (1 << 4) | RequestMessage, - /// - /// 响应的细分类型,IPC 框架知道此消息体是可被处理的字符串。 - /// - StringResponseMessage = (1 << 4) | ResponseMessage, + ///// + ///// 响应的细分类型,IPC 框架知道此消息体是可被处理的字符串。 + ///// + //StringResponseMessage = (1 << 4) | ResponseMessage, - /// - /// 请求的细分类型,IPC 框架知道此消息体是可被处理的 .NET 对象。 - /// - ObjectRequestMessage = (1 << 5) | RequestMessage, + ///// + ///// 请求的细分类型,IPC 框架知道此消息体是可被处理的 .NET 对象。 + ///// + //ObjectRequestMessage = (1 << 5) | RequestMessage, - /// - /// 响应的细分类型,IPC 框架知道此消息体是可被处理的 .NET 对象。 - /// - ObjectResponseMessage = (1 << 5) | ResponseMessage, + ///// + ///// 响应的细分类型,IPC 框架知道此消息体是可被处理的 .NET 对象。 + ///// + //ObjectResponseMessage = (1 << 5) | ResponseMessage, /// /// 其他消息。 diff --git a/src/dotnetCampus.Ipc/Messages/IpcMessage.cs b/src/dotnetCampus.Ipc/Messages/IpcMessage.cs index d272b497..a83713c2 100644 --- a/src/dotnetCampus.Ipc/Messages/IpcMessage.cs +++ b/src/dotnetCampus.Ipc/Messages/IpcMessage.cs @@ -1,4 +1,6 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; +using dotnetCampus.Ipc.Context; namespace dotnetCampus.Ipc.Messages { @@ -13,35 +15,22 @@ public readonly struct IpcMessage /// 请标记此消息用于在调试过程中追踪。 /// IPC 消息的具体内容。 [DebuggerStepThrough] - public IpcMessage(string tag, IpcMessageBody body) + public IpcMessage(string tag, IpcMessageBody body) : this(tag, body, (ulong) 0) { - Tag = tag; - Body = body; - CoreMessageType = CoreMessageType.Raw; } /// /// 创建一条可在 IPC 框架中传输的消息。 /// - /// 请标记此消息用于在调试过程中追踪。 - /// IPC 消息的具体内容。 + /// + /// + /// [DebuggerStepThrough] - public IpcMessage(string tag, byte[] data) : this(tag, new IpcMessageBody(data)) - { - } - - /// - /// 创建一条可在 IPC 框架中传输的消息。 - /// - /// 请标记此消息用于在调试过程中追踪。 - /// IPC 消息的具体内容。 - /// 由 IPC 框架传入,用以标记此消息可被 IPC 框架识别和处理的类型。 - [DebuggerStepThrough] - internal IpcMessage(string tag, IpcMessageBody body, CoreMessageType coreMessageType) + public IpcMessage(string tag, IpcMessageBody body, ulong ipcMessageHeader) { Tag = tag; Body = body; - CoreMessageType = coreMessageType; + IpcMessageHeader = ipcMessageHeader; } /// @@ -49,9 +38,8 @@ internal IpcMessage(string tag, IpcMessageBody body, CoreMessageType coreMessage /// /// 请标记此消息用于在调试过程中追踪。 /// IPC 消息的具体内容。 - /// 由 IPC 框架传入,用以标记此消息可被 IPC 框架识别和处理的类型。 [DebuggerStepThrough] - internal IpcMessage(string tag, byte[] data, CoreMessageType coreMessageType) : this(tag, new IpcMessageBody(data), coreMessageType) + public IpcMessage(string tag, byte[] data) : this(tag, new IpcMessageBody(data)) { } @@ -65,9 +53,32 @@ internal IpcMessage(string tag, IpcMessageBody body, CoreMessageType coreMessage /// public IpcMessageBody Body { get; } + ///// + ///// 标记此消息可被 IPC 框架识别和处理的类型。 + ///// + //internal CoreMessageType CoreMessageType { get; } + /// - /// 标记此消息可被 IPC 框架识别和处理的类型。 + /// 消息头类型,用来标识这条消息属于什么机制发送的消息。默认是 0 表示 Raw 裸消息。为 0 时,将不会带在发送的数据里面。框架内预设的消息类型,请参阅 类 /// - internal CoreMessageType CoreMessageType { get; } + public ulong IpcMessageHeader { get; } + + /// + /// 调试使用的属性 + /// + public KnownMessageHeaders Header => (KnownMessageHeaders) IpcMessageHeader; + + internal IpcBufferMessageContext ToIpcBufferMessageContextWithMessageHeader(IpcMessageCommandType ipcMessageCommandType) + { + if (IpcMessageHeader == 0) + { + return new IpcBufferMessageContext(Tag, ipcMessageCommandType, Body); + } + + var header = BitConverter.GetBytes(IpcMessageHeader); + var ipcBufferMessageContext = + new IpcBufferMessageContext(Tag, ipcMessageCommandType, new IpcMessageBody(header), Body); + return ipcBufferMessageContext; + } } } diff --git a/src/dotnetCampus.Ipc/Messages/IpcMessageBody.cs b/src/dotnetCampus.Ipc/Messages/IpcMessageBody.cs index 5d9a59d8..7cc2b1c8 100644 --- a/src/dotnetCampus.Ipc/Messages/IpcMessageBody.cs +++ b/src/dotnetCampus.Ipc/Messages/IpcMessageBody.cs @@ -59,6 +59,13 @@ public IpcMessageBody(byte[] buffer, int start, int length) /// 数据长度 /// public int Length { get; } + + internal static IpcMessageBody EmptyIpcMessageBody => +#if NET45 + new IpcMessageBody(new byte[0]); +#else + new IpcMessageBody(Array.Empty()); +#endif } /// diff --git a/src/dotnetCampus.Ipc/Pipes/IpcClientService.cs b/src/dotnetCampus.Ipc/Pipes/IpcClientService.cs index 2876d56c..7e1daa8e 100644 --- a/src/dotnetCampus.Ipc/Pipes/IpcClientService.cs +++ b/src/dotnetCampus.Ipc/Pipes/IpcClientService.cs @@ -315,7 +315,7 @@ await IpcMessageConverter.WriteAsync /// /// 业务层使用的 /// - internal async Task WriteMessageAsync(IpcMessageTracker tracker) + internal async Task WriteMessageAsync(IpcMessageTracker tracker) { VerifyNotDisposed(); @@ -341,10 +341,12 @@ async Task WriteMessageAsyncInner() var stream = result.NamedPipeClientStream; + var ipcMessageBody = tracker.Message.Body; + // 追踪、校验消息。 var ack = AckManager.GetAck(); tracker.Debug("IPC start writing..."); - tracker.CriticalStep("SendCore", ack, tracker.Message); + tracker.CriticalStep("SendCore", ack, ipcMessageBody); // 发送消息。 await IpcMessageConverter.WriteAsync @@ -354,9 +356,9 @@ await IpcMessageConverter.WriteAsync AckManager.GetAck(), // 表示这是业务层的消息 IpcMessageCommandType.Business, - tracker.Message.Buffer, - tracker.Message.Start, - tracker.Message.Length, + ipcMessageBody.Buffer, + ipcMessageBody.Start, + ipcMessageBody.Length, IpcConfiguration.SharedArrayPool, tracker.Tag ); diff --git a/src/dotnetCampus.Ipc/Pipes/IpcMessageManagerBase.cs b/src/dotnetCampus.Ipc/Pipes/IpcMessageManagerBase.cs index 19ab35d1..6f62e48e 100644 --- a/src/dotnetCampus.Ipc/Pipes/IpcMessageManagerBase.cs +++ b/src/dotnetCampus.Ipc/Pipes/IpcMessageManagerBase.cs @@ -14,45 +14,85 @@ class IpcMessageManagerBase protected static IpcBufferMessageContext CreateResponseMessageInner(IpcClientRequestMessageId messageId, in IpcMessage response) { /* - * MessageHeader - * MessageId - * Response Message Length - * Response Message - */ + * MessageHeader + * MessageId + * Response Message Length + * Response Message + */ + var messageLength = response.Body.Length; var currentMessageIdByteList = BitConverter.GetBytes(messageId.MessageIdValue); - var responseMessageLengthByteList = BitConverter.GetBytes(response.Body.Length); + IpcMessageBody businessHeader; + if (response.IpcMessageHeader == 0) + { + businessHeader = IpcMessageBody.EmptyIpcMessageBody; + } + else + { + // 需要带上头的消息 + messageLength += sizeof(ulong); + + // 有业务头,加上业务头 + businessHeader = new IpcMessageBody(BitConverter.GetBytes(response.IpcMessageHeader)); + } + + var responseMessageLengthByteList = BitConverter.GetBytes(messageLength); + return new IpcBufferMessageContext ( response.Tag, - IpcMessageCommandType.ResponseMessage | response.CoreMessageType.AsMessageCommandTypeFlags(), - new IpcMessageBody(ResponseMessageHeader), - new IpcMessageBody(currentMessageIdByteList), - new IpcMessageBody(responseMessageLengthByteList), - response.Body + IpcMessageCommandType.ResponseMessage, + new[] + { + new IpcMessageBody(ResponseMessageHeader), + new IpcMessageBody(currentMessageIdByteList), + new IpcMessageBody(responseMessageLengthByteList), + businessHeader, + response.Body + } ); } protected static IpcBufferMessageContext CreateRequestMessageInner(in IpcMessage request, ulong currentMessageId) { /* - * MessageHeader - * MessageId - * Request Message Length - * Request Message - */ + * MessageHeader + * MessageId + * Request Message Length + * Request Message + */ var currentMessageIdByteList = BitConverter.GetBytes(currentMessageId); - var requestMessageLengthByteList = BitConverter.GetBytes(request.Body.Length); + var messageLength = request.Body.Length; + + IpcMessageBody businessHeader; + if (request.IpcMessageHeader == 0) + { + businessHeader = IpcMessageBody.EmptyIpcMessageBody; + } + else + { + // 需要带上头的消息 + messageLength += sizeof(ulong); + + // 有业务头,加上业务头 + businessHeader = new IpcMessageBody(BitConverter.GetBytes(request.IpcMessageHeader)); + } + + var requestMessageLengthByteList = BitConverter.GetBytes(messageLength); return new IpcBufferMessageContext ( request.Tag, - IpcMessageCommandType.RequestMessage | request.CoreMessageType.AsMessageCommandTypeFlags(), - new IpcMessageBody(RequestMessageHeader), - new IpcMessageBody(currentMessageIdByteList), - new IpcMessageBody(requestMessageLengthByteList), - request.Body + IpcMessageCommandType.RequestMessage, + new[] + { + new IpcMessageBody(RequestMessageHeader), + new IpcMessageBody(currentMessageIdByteList), + new IpcMessageBody(requestMessageLengthByteList), + businessHeader, + request.Body + } ); } diff --git a/src/dotnetCampus.Ipc/Pipes/PeerProxy.cs b/src/dotnetCampus.Ipc/Pipes/PeerProxy.cs index ead5dec3..3952fffb 100644 --- a/src/dotnetCampus.Ipc/Pipes/PeerProxy.cs +++ b/src/dotnetCampus.Ipc/Pipes/PeerProxy.cs @@ -56,20 +56,43 @@ internal PeerProxy(string peerName, IpcClientService ipcClientService, IpcIntern /// public async Task NotifyAsync(IpcMessage request) { - // 追踪业务消息。 - var requestTracker = new IpcMessageTracker(IpcContext.PipeName, PeerName, request.Body, request.Tag, IpcContext.Logger); - requestTracker.CriticalStep("Send", null, request.Body); + if (request.IpcMessageHeader != 0) + { + // 追踪业务消息。 + var requestTracker = new IpcMessageTracker(IpcContext.PipeName, PeerName, request, request.Tag, IpcContext.Logger); + requestTracker.CriticalStep("Send", null, request.Body); - await WaitConnectAsync(requestTracker).ConfigureAwait(false); + await WaitConnectAsync(requestTracker).ConfigureAwait(false); - try - { - // 发送带有追踪的请求。 - await IpcClientService.WriteMessageAsync(requestTracker).ConfigureAwait(false); + try + { + // 发送带有追踪的请求。 + await IpcClientService.WriteMessageAsync(requestTracker).ConfigureAwait(false); + } + catch (Exception e) + { + throw new IpcRemoteException($"[{nameof(NotifyAsync)}] Tag:'{request.Tag}'; LocalPeer:'{IpcContext.PipeName}'; RemotePeer:'{PeerName}'; ExceptionMessage:'{e.Message}'", e); + } } - catch (Exception e) + else { - throw new IpcRemoteException($"[{nameof(NotifyAsync)}] Tag:'{request.Tag}'; LocalPeer:'{IpcContext.PipeName}'; RemotePeer:'{PeerName}'; ExceptionMessage:'{e.Message}'", e); + var ipcBufferMessageContext = request.ToIpcBufferMessageContextWithMessageHeader(IpcMessageCommandType.Business); + + var requestTracker = new IpcMessageTracker(IpcContext.PipeName, PeerName, ipcBufferMessageContext, ipcBufferMessageContext.Tag, IpcContext.Logger); + + requestTracker.CriticalStep("Send", null, request.Body); + + await WaitConnectAsync(requestTracker).ConfigureAwait(false); + + try + { + // 发送带有追踪的请求。 + await IpcClientService.WriteMessageAsync(requestTracker).ConfigureAwait(false); + } + catch (Exception e) + { + throw new IpcRemoteException($"[{nameof(NotifyAsync)}] Tag:'{request.Tag}'; LocalPeer:'{IpcContext.PipeName}'; RemotePeer:'{PeerName}'; ExceptionMessage:'{e.Message}'", e); + } } } diff --git a/src/dotnetCampus.Ipc/Utils/Extensions/IpcMessageExtension.cs b/src/dotnetCampus.Ipc/Utils/Extensions/IpcMessageExtension.cs new file mode 100644 index 00000000..248ef51b --- /dev/null +++ b/src/dotnetCampus.Ipc/Utils/Extensions/IpcMessageExtension.cs @@ -0,0 +1,29 @@ +using System; +using dotnetCampus.Ipc.Messages; + +namespace dotnetCampus.Ipc.Utils.Extensions; + +static class IpcMessageExtension +{ + public static IpcMessage Skip(this IpcMessage ipcMessage, int length) + { + return new IpcMessage(ipcMessage.Tag, new IpcMessageBody(ipcMessage.Body.Buffer, + ipcMessage.Body.Start + length, + ipcMessage.Body.Length - length)); + } + + public static bool TryReadBusinessHeader(this in IpcMessage ipcMessage, out ulong header) + { + var length = sizeof(ulong); + if (ipcMessage.Body.Length < length) + { + header = 0; + return false; + } + else + { + header = BitConverter.ToUInt64(ipcMessage.Body.Buffer, ipcMessage.Body.Start); + return true; + } + } +}