• C# 小规模网络远程调用的基类(基于Socket方式)实现


    一,程序逻辑图示 
     image

    物理拓扑就不画了,是一般简单的CS架构

    二,服务端实现过程

      1), 服务端开始监听,并启动接收线程 
      

            public void Start(int port)
            {
                _listenPort = port;
                serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                serverSocket.Bind(new IPEndPoint(IPAddress.Any, port));
     
                serverSocket.Listen(_backlog);
                Console.WriteLine("端口侦听开始");
                for (int i = 0; i < _recieveThreadCount; i++)
                {
                    Thread acceptThread = new Thread(new ThreadStart(RecieveAccept));
                    acceptThread.Name = "接收" + (i + 1) + "号线程";
                    acceptThreadList.Add(acceptThread);
                    acceptThread.Start();
                }
            }

      2), 接收线程的实现,按照上面的逻辑图示,我们接收到连接后,就要实例连接对象,并注入监听对象的服务对象 
     

                Console.WriteLine(Thread.CurrentThread.Name + "开始");
                while (true)
                {
                    Socket clientSocket = serverSocket.Accept();
                    _clientSocketList.Add(new SocketClientBase(_instanceList, clientSocket));
                    Console.WriteLine(Thread.CurrentThread.Name + "获取到新的客户端(" + clientSocket.RemoteEndPoint.ToString() + ")");
                }

    服务端的代码就这么多,所有操作都是交给连接对象(SocketClientBase)去处理的

    三,客户端实现过程(连接对象)

    1), 服务对象定义 

     [Serializable()]
        public class ObjectInstance
        {
            /// <summary>
            /// 实例KEY
            /// </summary>
            public string InstanceKey { get; set; }
            /// <summary>
            /// 实例
            /// </summary>
            public object Instance { get; set; }
        }

    2), Request消息和Response消息的实现

        [Serializable()]
        abstract public class Message
        {
            abstract public MessageType MessageType { get; set; }
        }
        [Serializable()]
        public class RequestMessage : Message
        {
            public RequestMessage(ActionType actionType, string instanceKey, string callName)
            {
                _requestKey = Guid.NewGuid().ToString();
                ActionType = actionType;
                InstanceKey = instanceKey;
                CallName = callName;
            }
            private string _requestKey;
     
            public string RequestKey
            {
                get { return _requestKey; }
                private set { _requestKey = value; }
            }
            public DateTime SendTimeKey { get; set; }
            public ActionType ActionType { get; private set; }
            public string InstanceKey { get; private set; }
            public string CallName { get; private set; }
            public override MessageType MessageType
            {
                get
                {
                    return Net.MessageType.Request;
                }
                set
                {
                    throw new NotImplementedException();
                }
            }
     
            public Object[] Parameters { get; set; }
        }
        [Serializable()]
        public class ResponseMessage : Message
        {
            public ResponseMessage(string requestKey)
            {
                _requestKey = requestKey;
            }
            private string _requestKey;
     
            public string RequestKey
            {
                get { return _requestKey; }
                private set { _requestKey = value; }
            }
     
            public bool IsError { get; set; }
            public XQException ErrorInfo { get; set; }
     
            public object ReturnObject { get; set; }
            public DateTime SendTimeKey { get; set; }
     
            public override MessageType MessageType
            {
                get
                {
                    return Net.MessageType.Response;
                }
                set
                {
                    throw new NotImplementedException();
                }
            }
        }
        [Serializable()]
        public enum ActionType
        {
            CallMethod = 0, CallProperty = 1, CallField = 4, Other = 8
        }
        [Serializable()]
        public enum MessageType
        {
            Response = 0, Request = 1
        }

    上面我定义远程调用的方式的,和调用的约定对象,以及返回结果的定义

    3),发送远程调用消息 
     

            /// <summary>
            /// 调用远程方法
            /// </summary>
            /// <param name="instanceKey"></param>
            /// <param name="methodName"></param>
            /// <param name="pars"></param>
            /// <returns></returns>
            public ResponseMessage CallRemoteMethod(string instanceKey, string methodName, params object[] pars)
            {
                var response = new RequestMessage(ActionType.CallMethod, instanceKey, methodName);
                if (pars != null && pars.Length > 0)
                    response.Parameters = pars;
                return CallRemoteHost(response);
            }
      
            /// <summary>
            /// 请求远程主机
            /// </summary>
            /// <param name="request"></param>
            /// <returns></returns>
            public ResponseMessage CallRemoteHost(RequestMessage request)
            {
                ResponseMessage response = null;
                var getResponse = new OnGetReponseHandler(delegate(ResponseMessage args)
                {
                    if (args.RequestKey == request.RequestKey)
                    {
                        response = args;
                    }
                });
                this.OnGetReponseEvent += getResponse;
                SendRequest(request);
                DateTime beginTime = DateTime.Now;
                while (true)
                {
                    if (TimeSpan.FromTicks(DateTime.Now.Ticks - beginTime.Ticks).TotalMilliseconds > 60 * 1000)
                    {
                        this.OnGetReponseEvent -= getResponse;
                        return new ResponseMessage(request.RequestKey) { IsError = true, ErrorInfo = XQException.GetException(5565, "远程操作超时") };
                    }
                    if (response != null)
                        break;
                }
                this.OnGetReponseEvent -= getResponse;
                return response;
            }
            /// <summary>
            /// 发送请求
            /// </summary>
            /// <param name="request"></param>
            private void SendRequest(RequestMessage request)
            {
                byte[] data = SerializationHelper.ToByte(request);
                var streamData = SetStreamDataEnd(data);
                int count = clientSocket.Send(streamData);
                Console.WriteLine("发送数据到" + count + "字节数据到" + clientSocket.RemoteEndPoint.ToString());
            }
    4), 回复远程调用,这里有两种情况,一种是远程主机发送过来的请求,另一种是远程主机响应的请求的回发 
    a),消息为请求,我们就需要执行请求的内容,然后返回执行结果 
     
            private void ActionRequest(RequestMessage request)
            {
                ResponseMessage response = new ResponseMessage(request.RequestKey);
                Object instance = GetInstance(request.InstanceKey);
                if (instance == null)
                {
                    response.IsError = true;
                    response.ErrorInfo = XQException.GetException(5566, "实例不存在");
                }
                else
                {
                    string callName = request.CallName;
                    switch (request.ActionType)
                    {
                        case ActionType.CallMethod:
                            var methodInfo = instance.GetType().GetMethod(callName);
                            if (methodInfo == null)
                            {
                                response.IsError = true;
                                response.ErrorInfo = XQException.GetException(5567, "方法不存在");
                            }
                            else
                            {
                                object result = methodInfo.Invoke(instance, request.Parameters);
                                response.ReturnObject = result;
                            }
                            break;
                        case ActionType.CallProperty:
                            var propertyInfo = instance.GetType().GetProperty(callName);
                            if (propertyInfo == null)
                            {
                                response.IsError = true;
                                response.ErrorInfo = XQException.GetException(5568, "属性不存在");
                            }
                            else
                            {
                                object result = propertyInfo.GetValue(instance, null);
                                response.ReturnObject = result;
                            }
                            break;
                        case ActionType.CallField:
                            var fieldInfo = instance.GetType().GetField(callName);
                            if (fieldInfo == null)
                            {
                                response.IsError = true;
                                response.ErrorInfo = XQException.GetException(5569, "字段不存在");
                            }
                            else
                            {
                                object result = fieldInfo.GetValue(instance);
                                response.ReturnObject = result;
                            }
                            break;
                    }
                }
                SendResponse(response);
            }

    b),当消息为返回的请求结果

           private void ActionResponse(ResponseMessage response)
            {
                if (OnGetReponseEvent != null)
                    OnGetReponseEvent(response);
            }

    总结,这个实现模型,是基于一种旁注理念的,松耦合的实现方式,这个模型只是一个原型,没有错误处理等其他一些外围实现,我试验过单客户端IO性能大概48M,由于没有设计线程池,所以只能小规模应用

    ,完整源代码/Files/Rolends/SocketBase.rar

    转载请注明:http://www.cnblogs.com/Rolends 

      HAPPY EVERY DAY ! !

  • 相关阅读:
    SQL审核平台
    Redis单线程为什么快简单理解
    性能测试关注指标
    nmon
    pycharm安装教程
    MAVEN中央仓库地址大全
    MAVEN概念、安装与配置、配置文件
    linux在线模拟地址
    HTTP学习链接、书籍
    Java启动exe
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2475817.html
Copyright © 2020-2023  润新知