• 使用NewLife网络库构建可靠的自动售货机Socket服务端(一)


      最近有个基于tcp socket 协议和设备交互需求,想到了新生命团队的各种组件,所以决定用NewLife网络库作为服务端来完成一系列的信息交互.

      第一,首先说一下我们需要实现的功能需求吧

     1,首先客户有一堆自动售货机的设备,设备连接socket服务端后 定时发送设备实时状态作为心跳信息,并且服务端需要下发信息予以确认。

     2,需要知道设备的实时在线状态

     3,设备需要实现微信,支付宝扫码支付需求,当客户买东西的时候选择扫码支付时,设备上报产品价格信息,支付方式,服务器下发微信或者支付宝的当面付二维码。

     4,当客户扫码支付后,服务器需要下发支付结果。

     5,设备上报出货成功或失败信息,服务器予以回复确认

     6,设备上报现金收款的收款或者退款信息,服务器保存并且下发回复确认。

     7,服务器后台需要能够主动的向设备推送广告信息,并且能够实现掉线设备的广告推送

     第二,我们来分析这个可靠的服务器的大致结构是如何的(仅包含设备实时状态和支付交互)

     1,想要服务稳定可靠,那么首先考虑的是程序的运行方式,当然是以一个windows服务为宿主的方式来运行最为可靠,那么我们可以使用TopShelf来构建这样一个服务宿主

     2,实现设备的在线状态实时可知,我们需要定时的去判断这个设备是否在定时给服务器发送心跳信息,这个项目中我们以超时未发送心跳信息为标准来衡量他是否在线。

     3,设备数据上报涉及到粘包的处理,设备上报的数据是怎么样一个协议,如何来解决粘包的问题,这里我们借助Newlife网络库的管道模式来处理粘包

     4,微信支付宝的扫码支付如何及时知道客户付款状态,并且及时的下发给设备。

     第三,我们需要用到的第三方类库有哪些

      1,首先使用的网络库是Newlife 新生命团队的网络库

      2,构建windows服务使用的是TopShelf

      3,状态的信息保存使用Redis,这里我们使用CSRedisCore 这个类库

      4,微信支付宝本次使用的是PaySharp这个库,二维码生成使用QrCoder库

     第四,开始构建的基本的Socket服务吧

              1,首先创建一个windows服务,引入Topshelf后

             

            static void Main(string[] args)
            {
                var rc = HostFactory.Run(x =>                                   //1
                {
                    x.Service<DianSocketMain>(s =>                                   //2
                    {
                        s.ConstructUsing(name =>new DianSocketMain());                //3
                        s.WhenStarted(tc => tc.Start());                         //4
                        s.WhenStopped(tc => tc.Stop());                          //5
                    });
                    x.RunAsLocalSystem();                                       //6
    
                    x.SetDescription("售货机socket服务端");                   //7
                    x.SetDisplayName("Vending machine socket");                                  //8
                    x.SetServiceName("Vendingmachinesocket");                                  //9
                    x.OnException(s =>
                    {
                        LogerHelper.WriteErroLog("test",s.Message);
                    });
                });                                                             //10
            }

      

    DianSocketMain类就是具体的Socket服务端,来看下是如何启动一个基本的socket服务端
    public class DianSocketMain
        {
            /// <summary>
            ///网络库服务端 20181225
            /// </summary>
            private NetServer _newLifeServer;
            /// <summary>
            /// 
            /// </summary>
            public void Start()
            {
                try
                {
                    try
                    {   //redis初始化
                        string redisHost = CoomHelper.GetAppSettings("RedisHost", "127.0.0.1:6379");
                        string redisPwd = CoomHelper.GetAppSettings("RedisPwd", "");
                        string prefix = "{device_server}:";
                        string redisConn = $"{redisHost},password={redisPwd},defaultDatabase=0,poolsize=50,ssl=false,writeBuffer=10240,prefix={prefix}";
    
                        var csredis = new CSRedis.CSRedisClient(redisConn);
    
                        RedisHelper.Initialization(csredis);
                    }
                    catch (Exception e)
                    {
                        XTrace.WriteLine(e.Message);
                    }
    
                    //启动客户端
                    StartNewLifeListenClient();
                }
                catch (Exception e)
                {
                    XTrace.WriteException(e);
                }
    
            }
            /// <summary>
            /// 停止win服务
            /// </summary>
            public void Stop()
            {
                try
                {
                    if (_newLifeServer != null)
                    {
                        _newLifeServer.Dispose();
                    }
                }
                catch (Exception e)
                {
                    XTrace.WriteException(e);
                }
            }
    
    
            /// <summary>
            /// 监听客户端
            /// </summary>
            private void StartNewLifeListenClient()
            {
                try
                {
                    XTrace.WriteLine("当前tcp端口号为:" + 9046);
                    //创建监听地址和端口
                    IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
                    var svr = new NetServer(ipAddress, 9046, NetType.Tcp)
                    {
                        Log = XTrace.Log,
                        SessionTimeout = 60
                    };
                    svr.Add<ReciveFilter>();//粘包处理管道
                    svr.Received += new EventHandler<ReceivedEventArgs>(NewlifeRecive);//数据接收
                    //svr.Error += new EventHandler<ExceptionEventArgs>(NewlifeError);//错误处理
                    //svr.OnDisposed+=new EventHandler();
                    svr.Start();
                    _newLifeServer = svr;
                    //XTrace.WriteLine("会话超时时间为:"+svr.SessionTimeout);
                }
                catch (Exception ex)
                {
                    XTrace.WriteLine(ex.Message);
                }
    
            }
    
            /// <summary>
            /// 数据接收
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void NewlifeRecive(object sender, ReceivedEventArgs e)
            {
                INetSession session = (INetSession)sender;
                var pk = e.Message as Packet;
                if (pk.Count == 0)
                {
                    XTrace.WriteLine("数据包解析错误");
                    return;
    
                }
             }
        }

              这里包含的一个有redis的初始化,粘包处理,数据接收的一个基本服务端,下面我们再讲如何解决粘包的问题。

  • 相关阅读:
    查询同一表格中姓名相同但身份证号不同的记录
    Liunx常用命令
    判断当前移动端是Android、还是ios、还是微信
    mybatis 返回值问题
    log4j2+mybaits 打印sql操作语句
    java日期格式问题
    eachart图表100px大小原因,及处理办法
    springboot中的默认数据库连接池HikariDataSource
    SpringBoot中logback.xml使用application.yml中属性
    linux 下的vi vim快捷键,命令总结
  • 原文地址:https://www.cnblogs.com/yushuo/p/10283622.html
Copyright © 2020-2023  润新知