网络程序应该注册成为系统服务,以保证其自启动以及稳定可靠运行!

这一场,讲讲怎么建立一个生产级别的网络服务。

老规矩,先上源码:https://github.com/NewLifeX/NewLife.Net

系统服务功能,由网络库的兄弟框架,X组件的Agent来支撑,以前也叫XAgent,网上搜索 NewLife.Agent 可以找到不少文章。

XAgent在X组件里面很年轻,才10年,设计于2008年,上海陆家嘴。


阅读本文之前,建议阅读

此处为文档,点击链接查看:https://newlifex.com/go/doc/5653434


最终效果

EchoAgent跑起来先来看看最终效果,客户端用上次的EchoTest,大家也可以telnet net.newlifex.com 1234 来看效果

image.png

左边窗口就是这次要讲的网络服务程序,工作在循环调试模式。

右边窗口是上一次的EchoTest客户端,连接左边网络服务。

客户端向服务端发送了5次数据,都得到响应,同时,服务端每秒主动向客户端发送一次本机时间。


建立控制台项目

建立一个控制台项目,通过nuget引用NewLife.Core。项目源码 https://github.com/NewLifeX/NewLife.Net/tree/master/EchoAgent

新建一个服务类 MyService,继承自泛型基类 AgentServiceBase<MyService>

Program.Main里面增加一行引导程序:

class Program
{
    static void Main(String[] args) => new MyService().Main(args);
}


下面就开始慢慢完善我们的服务类MyService

public MyService()
{
    ServiceName = "EchoAgent";
    DisplayName = "回声服务";
    Description = "这是NewLife.Net的一个回声服务示例!";
}

指定一些基本参数,看效果图可以猜到用途


服务名、显示名、描述,就这么多!


系统服务的标准动作就是启动和停止

        MyNetServer _Server;
        /// <summary>开始服务</summary>
        /// <param name="reason"></param>
        protected override void StartWork(String reason)
        {
            // 实例化服务端,指定端口,同时在Tcp/Udp/IPv4/IPv6上监听
            var svr = new MyNetServer
            {
                Port = 1234,
                Log = XTrace.Log,
#if DEBUG
                SocketLog = XTrace.Log,
                LogSend = true,
                LogReceive = true,
#endif
            };
            svr.Start();

            _Server = svr;

            _timer1 = new TimerX(s => ShowStat(_Server), null, 1000, 1000) { Async = true };
            _timer2 = new TimerX(s => SendTime(_Server), null, 1000, 1000) { Async = true };

            base.StartWork(reason);
        }

        /// <summary>停止服务</summary>
        /// <param name="reason"></param>
        protected override void StopWork(String reason)
        {
            _Server.TryDispose();
            _Server = null;

            base.StopWork(reason);
        }

        private TimerX _timer1;
        private TimerX _timer2;

        private String _last;
        /// <summary>显示服务端状态</summary>
        /// <param name="ns"></param>
        private void ShowStat(NetServer ns)
        {
            if (ns == null) return;

            var msg = ns.GetStat();
            if (msg == _last) return;

            _last = msg;

            WriteLog(msg);
        }

        /// <summary>向所有客户端发送时间</summary>
        /// <param name="ns"></param>
        private void SendTime(NetServer ns)
        {
            if (ns == null) return;

            var str = DateTime.Now.ToFullString() + Environment.NewLine;
            var buf = str.GetBytes();
            ns.SendAllAsync(buf);
        }


我们重载启动函数,初始化网络服务,并重启停止函数来销毁网络服务。

这里的MyNetServer从上一个例程拷贝过来。

网络服务做一个成员资源,避免被GC回收。


开发调试

既然是控制台项目,先跑起来看看:

image.png

红色字体显示重要信息,黄色字体显示菜单,常用功能是235。

我们选择5循环调试,其实就是在控制台里面模拟服务工作流程,让网络服务跑起来。

底下日志可以看到,它监听了4个套接字。

 

2是安装服务,也就是把当前应用安装成为Windows服务或者Linux的Systemd服务,这里特别注意,一般需要管理员权限,才能安装成功,除非关闭系统UAC。

3是启动服务,只有在安装了服务之后,才能看到。

 

所以,XAgent程序,既是开发调试控制台程序,也是安装卸载、启动停止服务的操作台,更是Windows服务程序本身!

细心的同学可以发现,安装好的Windows服务实质上就是 EchoAgent.exe -s,带有-s参数。


安装服务

最后,我们把它安装到一台公网服务器上,tcp://net.newlifex.com:1234,telnet上去看看效果

image.png

服务端日志如下:

#Software: EchoAgent
#ProcessID: 13592 x64
#AppDomain: EchoAgent
#FileName: D:\X\NewLife.Net\Bin\Agent\EchoAgent.exe
#BaseDirectory: D:\X\NewLife.Net\Bin\Agent\
#TempPath: C:\Users\Stone\AppData\Local\Temp\
#CommandLine: D:\X\NewLife.Net\Bin\Agent\EchoAgent.dll
#ApplicationType: Console
#CLR: 3.1.5, .NET Core 3.1.5
#OS: Microsoft Windows NT 6.2.9200.0, X3/Stone
#CPU: 8
#GC: IsServerGC=False, LatencyMode=Interactive
#Date: 2020-07-05
#:  线ID 线Y/W/N/T 线/ID 
#Fields: Time ThreadID Kind Name Message
13:18:26.412  1 N - MyNet 4
13:18:26.416  1 N - MyNetTcp.Start Tcp://0.0.0.0:1234
13:18:26.422  1 N - MyNet  Tcp://0.0.0.0:1234
13:18:26.424  1 N - MyNetTcp6.Start Tcp://:::1234
13:18:26.425  1 N - MyNet  Tcp://:::1234
13:18:26.427  1 N - MyNetUdp.Open Udp://0.0.0.0:1234
13:18:26.431  1 N - MyNet  Udp://0.0.0.0:1234
13:18:26.432  1 N - MyNetUdp6.Open Udp://:::1234
13:18:26.433  1 N - MyNet  Udp://:::1234
13:18:26.433  1 N - MyNet 
13:18:26.434  1 N -  


至此,我们的Windows网络服务程序开发完成,并安装到公网服务器上,持续对外提供Echo服务!