[fix]修正UdpServer在接收广播时连续启动接收的错误,在StarAgent中,此时可能收到广播包,SocketFlags是Broadcast,需要清空,否则报错“参考的对象类型不支持尝试的操作”; 无需设置SocketOptionName.PacketInformation,在ReceiveMessageFromAsync时会自动设置,并且支持ipv6;
石头 编写于 2024-10-10 00:36:00 石头 提交于 2024-10-10 00:45:43
X
using System;
using System.Collections.Generic;
using System.IO;
using NewLife.Data;
using NewLife.Log;
using NewLife.Messaging;

namespace NewLife.Remoting
{
    /// <summary>编码器</summary>
    public interface IEncoder
    {
        ///// <summary>编码 请求/响应</summary>
        ///// <param name="action"></param>
        ///// <param name="code"></param>
        ///// <param name="value"></param>
        ///// <returns></returns>
        //Packet Encode(String action, Int32 code, Packet value);

        /// <summary>创建请求</summary>
        /// <param name="action"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        IMessage CreateRequest(String action, Object args);

        /// <summary>创建响应</summary>
        /// <param name="msg"></param>
        /// <param name="action"></param>
        /// <param name="code"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        IMessage CreateResponse(IMessage msg, String action, Int32 code, Object value);

        /// <summary>解码 请求/响应</summary>
        /// <param name="msg">消息</param>
        /// <param name="action">服务动作</param>
        /// <param name="code">错误码</param>
        /// <param name="value">参数或结果</param>
        /// <returns></returns>
        Boolean Decode(IMessage msg, out String action, out Int32 code, out Packet value);

        ///// <summary>编码 请求/响应</summary>
        ///// <param name="action">服务动作</param>
        ///// <param name="code">错误码</param>
        ///// <param name="value">参数或结果</param>
        ///// <returns></returns>
        //Packet Encode(String action, Int32 code, Object value);

        /// <summary>解码参数</summary>
        /// <param name="action">动作</param>
        /// <param name="data">数据</param>
        /// <param name="msg">消息</param>
        /// <returns></returns>
        IDictionary<String, Object> DecodeParameters(String action, Packet data, IMessage msg);

        /// <summary>解码结果</summary>
        /// <param name="action"></param>
        /// <param name="data"></param>
        /// <param name="msg">消息</param>
        /// <returns></returns>
        Object DecodeResult(String action, Packet data, IMessage msg);

        /// <summary>转换为目标类型</summary>
        /// <param name="obj"></param>
        /// <param name="targetType"></param>
        /// <returns></returns>
        Object Convert(Object obj, Type targetType);

        /// <summary>日志提供者</summary>
        ILog Log { get; set; }
    }

    /// <summary>编码器基类</summary>
    public abstract class EncoderBase
    {
        #region 编码/解码
        /// <summary>解码 请求/响应</summary>
        /// <param name="msg">消息</param>
        /// <param name="action">服务动作</param>
        /// <param name="code">错误码</param>
        /// <param name="value">参数或结果</param>
        /// <returns></returns>
        public virtual Boolean Decode(IMessage msg, out String action, out Int32 code, out Packet value)
        {
            code = 0;
            value = null;

            // 请求:action + args
            // 响应:action + code + result
            var ms = msg.Payload.GetStream();
            var reader = new BinaryReader(ms);

            action = reader.ReadString();
            if (action.IsNullOrEmpty()) throw new Exception("解码错误,无法找到服务名!");

            // 异常响应才有code
            if (msg.Reply && msg.Error) code = reader.ReadInt32();

            // 参数或结果
            if (ms.Length > ms.Position)
            {
                var len = reader.ReadInt32();
                if (len > 0) value = msg.Payload.Slice((Int32)ms.Position, len);
            }

            return true;
        }
        #endregion

        #region 日志
        /// <summary>日志提供者</summary>
        public ILog Log { get; set; } = Logger.Null;

        /// <summary>写日志</summary>
        /// <param name="format"></param>
        /// <param name="args"></param>
        public virtual void WriteLog(String format, params Object[] args) => Log?.Info(format, args);
        #endregion
    }
}