使用FastTcpServerEx构建服务器

前言

本小节是NetworkSocket系列的第6小节,在阅读本小节之前,您可能需要先阅读前面的几个小节,否则可能觉得内容跳转比较大。

描述

FastTcpServerEx是从TcpServerEx派生,使用的协议和TcpServerEx完成相同,FastTcpServerEx充分结合C#强大的反射功能,大大地简化了服务器编程难度,更符合实际通讯项目的编写,与之相比,前两章节提到的TcpServerBase和TcpServerEx构建服务器,离实际项目要求还相差很远。FastTcpServerEx的工作原理是,当收到客户端发来的数据DataEventExArgs后,分析DataEventExArgs的Action参数,把Action和对应的服务方法绑定,把DataEventExArgs.Binary转换为服务方法对应的参数,然后通过反射调用服务方法,将方法的返回值再封装为DataEventExArgs返回给客户端,这里虽然用到了反射,但已经改善和优化过,方便性的提升带来的价值大过于性能的损失价值。

服务器编写思路

你可以把FastTcpServerEx比作Wcf来理解,编写步骤是:1、编写服务契约IDemoServer,当然还有用到的实体,建议实体单独作一个项目工程,这样在序列化工作很方便;2、新增DemoServer类,派生于FastTcpServerEx,并继承IDemoServer接口;3、实现IDemoServer接口

编写接口

新建Server工程,引用NetworkSocket.dll,引入NetworkSocket、NetWorkSocket.TcpExtention、NetWorkSocket.Serialization、Entity命名空间,添加IDemoServer接口

View Code
using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Entity;

using NetWorkSocket;

using NetWorkSocket.TcpExtention;



namespace Server

{

    /// <summary>

    /// 服务接口

    /// 要求每个方法的第一个参数必须是SocketAsync(DataEventExArgs)类型

    /// 这个参数很重要(验证客端,断开客户端等都用到)

    /// </summary>

    public interface IDemoServer

    {

        /// <summary>

        /// 客户端登录

        /// </summary>

        /// <param name="client">客户端</param>

        /// <param name="user">用户信息</param>

        /// <param name="fAdmin">是否是管理员登录</param>

        /// <returns></returns>

        bool Login(SocketAsync<DataEventExArgs> client, Userinfo user, bool fAdmin);



        /// <summary>

        /// 求和

        /// </summary>

        /// <param name="client">客户端</param>

        /// <param name="x">参数x</param>

        /// <param name="y">参数y</param>

        /// <param name="z">参数z</param>

        /// <returns></returns>

        int GetSum(SocketAsync<DataEventExArgs> client, int x, int y, int z);



        /// <summary>

        /// 获取客户端本机上的时间

        /// 此方法由客户端来实现,服务器来调用

        /// [ClientMethod]是修饰此方法为客户端方法的特性

        /// </summary>

        /// <param name="client">客户端</param>

        /// <param name="callBack">回调,收到数据后,将回调此方法</param>

        [ClientMethod]

        void GetDateTime(SocketAsync<DataEventExArgs> client, Action<DateTime> callBack);

    }

}

上面的接口有三个服务方法,分别为客户端登录、客户获取数据相加、获取客户端本机时间,前两个方法都是客户端主动请求,服务器被动处理,而后一个方法是服务器主动请求,客户端被动处理(即服务器和客户端功能倒置)。这里要注意的是,每个方法的第一个参数必须是SocketAsync<DataEventExArgs>,这个参数不是数据参数,不会被序列化然后传送到另一端,而是在方法的实现中会经常用到这个参数。

实现接口

实现接口也就是实现了服务器的功能,这里也就不多篇幅来说明怎么实现接口了。

View Code
using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using Entity;

using NetWorkSocket;

using NetWorkSocket.Serialization;

using NetWorkSocket.TcpExtention;





namespace Server

{

    /// <summary>

    /// 服务器接口的实现

    /// 第一个接口必须是服务器的接口(如果有多个接口的话)

    /// </summary>

    public class DemoServer : FastTcpServerEx, IDemoServer

    {

        /// <summary>

        /// 重写验证客户端的方法

        /// 在客户端请求服务时,此方法第一时间被调用

        /// 如果返回flase,则服务器会丢弃客户端的请求

        /// </summary>

        /// <param name="client"></param>

        /// <param name="action"></param>

        /// <returns></returns>

        protected override bool ValidateClient(SocketAsync<DataEventExArgs> client, int action)

        {

            // action为0,对应接口的第一个方法,也就是Login方法

            bool forLogin = (action == 0);



            // 如果此请求不是Login类型请求

            if (forLogin == false)

            {

                // 验证通过后才可以请求其它服务方法

                return client.HasValidated;

            }

            return base.ValidateClient(client, action);

        }



        /// <summary>

        /// 客户端登录

        /// </summary>

        /// <param name="client">客户端</param>

        /// <param name="user">用户信息</param>

        /// <param name="fAdmin">是否是管理员登录</param>

        /// <returns></returns>

        public bool Login(SocketAsync<DataEventExArgs> client, Userinfo user, bool fAdmin)

        {

            if (user != null)

            {

                // 标记客户端为合法有效的用户

                // 这样,client在登录后,就可以有权调用GetSum服务方法

                client.HasValidated = true;

                client.UserToken = user; // 保存user对象,方便查找client,client可以从this.AliveClients属性查找



                // 从客户端获取时间

                this.GetDateTime(client, (time) =>

                {

                    Console.WriteLine("{0}({1}) {2}", user.name, fAdmin ? "Admin" : "User", time);

                });



                // 返回登录成功

                return true;

            }



            return false;

        }





        /// <summary>

        /// 求和

        /// </summary>

        /// <param name="client">客户端</param>

        /// <param name="x">参数x</param>

        /// <param name="y">参数y</param>

        /// <param name="z">参数z</param>

        /// <returns></returns>

        public int GetSum(SocketAsync<DataEventExArgs> client, int x, int y, int z)

        {

            return x + y + z;

        }



        /// <summary>

        /// 获取客户端本机上的时间

        /// 此方法由客户端来实现,服务器来调用

        /// [ClientMethod]是修饰此方法为客户端方法的特性

        /// </summary>

        /// <param name="client">客户端</param>

        /// <param name="callBack">回调,收到数据后,将回调此方法</param>

        [ClientMethod]

        public void GetDateTime(SocketAsync<DataEventExArgs> client, Action<DateTime> callBack)

        {

            // 使用InvokeClient简化发送数据到客户端的过程

            // 如果没有数据参数,InvokeClient的第二个参数可以为null

            base.InvokeClient<DateTime>(client, null, callBack);

        }



    }

}

当接口实现后,服务器的功能已编写完成,下面是启动服务器的方法

View Code
 static void Main(string[] args)

        {

            Console.Title = "Flex Server";

            DemoServer server = new DemoServer();

            server.StartListen(new IPEndPoint(IPAddress.Any, 8181));

            Console.WriteLine("127.0.0.1 8181");



            while (true)

            {

                Console.ReadLine();     

            }

        }

生成服务调用代理

wcf的时候,我们把服务发布后,通过vs很方便就可以生成服务调用的代理类,FastTcpServerEx也有类似功能,不同的是,这个代理类是通过ProxyMaker工具来反射IDemoServer,获取里面的方法,然后逆向生成调用代码,最终于编译为Server.dll输出,客户端只要引用Server.dll,就可以方便的和服务器通讯了。

运行ProxyMaker

使用FastTcpServerEx构建服务器

这里对应我们的命令是:ProxyMaker.exe /a ..\Demo\Server\bin\Debug\Server.exe /i IDemoServer ,我们可以把它放到批处理文件,以后双击就可以编译出Server.dll;

使用FastTcpServerEx构建服务器

编写客户端

有了Server.dll,编写客户端的难度也大大的降低了,新建Client工程,引用NetworkSocke.dll和刚才生成的Server.dll;实例化 DemoServer client = new DemoServer();然后就可以调用里面的方法了,这里和wcf客户端几乎完全一样;由于比较简单,客户端代码中我就不注释了。

View Code
using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows.Forms;

using Entity;

using Server;



namespace Client

{

    static class Program

    {

        /// <summary>

        /// 应用程序的主入口点。

        /// </summary>

        static void Main()

        {

            DemoServer client = new DemoServer();



            client.OnGetDateTime += new DemoServer.GetDateTime(client_OnGetDateTime);



            client.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8181));



            Random ran = new Random();

            Userinfo user = new Userinfo() { password = "123456" };



            while (true)

            {

                Console.ReadLine();

                user.name = "A" + ran.Next(0, 100).ToString();



                client.Login(user, true, (state) =>

                {

                    if (state)

                    {

                        int x = ran.Next(0, 100);

                        int y = ran.Next(0, 100);

                        int z = ran.Next(0, 100);



                        client.GetSum(x, y, z, (sum) =>

                        {

                            Console.WriteLine("{0} + {1} + {2} = {3}", x, y, z, sum);

                        });

                    }

                });

            }

        }



        static DateTime client_OnGetDateTime()

        {

            return DateTime.Now;

        }



    }

}

运行效果

 使用FastTcpServerEx构建服务器

你可能感兴趣的:(server)