使用NewLife網絡庫構建可靠的自動售貨機Socket服務端(一)

  最近有個基於tcp socket 協議和設備交互需求,想到了新生命團隊的各類組件,因此決定用NewLife網絡庫做爲服務端來完成一系列的信息交互.

  第一,首先說一下咱們須要實現的功能需求吧

 1,首先客戶有一堆自動售貨機的設備,設備鏈接socket服務端後 定時發送設備實時狀態做爲心跳信息,而且服務端須要下發信息予以確認。redis

 2,須要知道設備的實時在線狀態windows

 3,設備須要實現微信,支付寶掃碼支付需求,當客戶買東西的時候選擇掃碼支付時,設備上報產品價格信息,支付方式,服務器下發微信或者支付寶的當面付二維碼。服務器

 4,當客戶掃碼支付後,服務器須要下發支付結果。微信

 5,設備上報出貨成功或失敗信息,服務器予以回覆確認網絡

 6,設備上報現金收款的收款或者退款信息,服務器保存而且下發回覆確認。session

 7,服務器後臺須要可以主動的向設備推送廣告信息,而且可以實現掉線設備的廣告推送socket

 第二,咱們來分析這個可靠的服務器的大體結構是如何的(僅包含設備實時狀態和支付交互)

 1,想要服務穩定可靠,那麼首先考慮的是程序的運行方式,固然是以一個windows服務爲宿主的方式來運行最爲可靠,那麼咱們能夠使用TopShelf來構建這樣一個服務宿主tcp

 2,實現設備的在線狀態實時可知,咱們須要定時的去判斷這個設備是否在定時給服務器發送心跳信息,這個項目中咱們以超時未發送心跳信息爲標準來衡量他是否在線。微信支付

 3,設備數據上報涉及到粘包的處理,設備上報的數據是怎麼樣一個協議,如何來解決粘包的問題,這裏咱們藉助Newlife網絡庫的管道模式來處理粘包spa

 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的初始化,粘包處理,數據接收的一個基本服務端,下面咱們再講如何解決粘包的問題。

相關文章
相關標籤/搜索