一,程序逻辑图示
 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);
        }

测试代码

  /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            //Application.EnableVisualStyles();
            //Application.SetCompatibleTextRenderingDefault(false);
            //Application.Run(new Form1());
            var serverInstance = new List<ObjectInstance>();
            serverInstance.Add(new ObjectInstance() { InstanceKey = "Server-1", Instance = new Server() });
            SocketServerBase sbServer = new SocketServerBase(serverInstance);
            sbServer.Start(9999);
 
 
            var clientInstance = new List<ObjectInstance>();
            clientInstance.Add(new ObjectInstance() { InstanceKey = "client-1", Instance = new Client() });
            SocketClientBase sbClient = new SocketClientBase(clientInstance);
            sbClient.Connect(8888, "127.0.0.1", 9999);
 
 
 
            Thread.Sleep(1000);
 
            var client = sbServer.ClientSocketList.Find(p => p.RemoteIp == "127.0.0.1" && p.RemorePort == 8888);
            StringBuilder sendText = new StringBuilder();
            for (int i = 0; i < 10; i++)
            {
                sendText.Append(text);
            }
            string strText = sendText.ToString();
            sendText.Length = 0;
            while (true)
            {
                var response = sbClient.CallRemoteMethod("Server-1", "Add");
                response = sbClient.CallRemoteMethod("Server-1", "Add2", 1, 2);
                response = sbClient.CallRemoteMethod("Server-1", "Add3", 1, 2);
                response = sbClient.CallRemoteMethod("Server-1", "Add4", strText);
                client.CallRemoteMethod("client-1", "Print", strText);
            }
            Console.ReadLine();
        }
    
 
 
    public class Server
    {
        public void Add()
        {
            Console.WriteLine("Server Add");
        }
 
        public void Add2(int x, int y)
        {
            Console.WriteLine("Server Add2");
        }
 
        public int Add3(int x, int y)
        {
            Console.WriteLine("Server Add3");
            return 1;
        }
        public int Add4(string text)
        {
            Console.WriteLine("Server Add3");
            return 1;
        }
    }
 
    public class Client
    {
        public void Print(string text)
        {
            // Console.WriteLine(text);
            Console.WriteLine("Client Print");
        }
    }

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

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

posted on 2012-04-28 18:03  rolends1986  阅读(4277)  评论(4编辑  收藏  举报