ITPub博客

首页 > 应用开发 > .net > [NewLife.Net]开始网络编程

[NewLife.Net]开始网络编程

原创 .net 作者:bitstone 时间:2022-01-11 00:15:29 0 删除 编辑

网络编程的重要性就不说了,先上源码: https://github.com/NewLifeX/NewLife.Net

一个服务端,就是监听一些端口,接收客户端连接和数据,进行处理,然后响应。


!!!这是一个单机压测达到2266万tps的网络框架!


标准网络服务器

网络服务器NetServer用于接收各种客户端(PC、APP、IoTDevice)发送上来的数据。


以下代码来自源码库一个测试子项目 https://github.com/NewLifeX/NewLife.Net/tree/master/EchoTest

using System;
using NewLife;
using NewLife.Net;
namespace EchoTest
{
    /// <summary>定义服务端,用于管理所有网络会话</summary>
    class MyNetServer : NetServer<MyNetSession>
    {
    }
    /// <summary>定义会话。每一个远程连接唯一对应一个网络会话,再次重复收发信息</summary>
    class MyNetSession : NetSession<MyNetServer>
    {
        /// <summary>客户端连接</summary>
        protected override void OnConnected()
        {
            // 发送欢迎语
            Send($"Welcome to visit {Environment.MachineName}!  [{Remote}]\r\n");
            base.OnConnected();
        }
        /// <summary>客户端断开连接</summary>
        protected override void OnDisconnected()
        {
#if DEBUG
            WriteLog("客户端{0}已经断开连接啦", Remote);
#endif
            base.OnDisconnected();
        }
        /// <summary>收到客户端数据</summary>
        /// <param name="e"></param>
        protected override void OnReceive(ReceivedEventArgs e)
        {
#if DEBUG
            WriteLog("收到:{0}", e.Packet.ToStr());
#endif
            // 把收到的数据发回去
            Send(e.Packet);
        }
        /// <summary>出错</summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected override void OnError(Object sender, ExceptionEventArgs e)
        {
#if DEBUG
            WriteLog("[{0}]错误:{1}", e.Action, e.Exception?.GetTrue().Message);
#endif
            base.OnError(sender, e);
        }
    }
}

服务端核心类是NetServer,一般来说,每个网络服务端都会写一个自己的类来继承NetServer,以方便编写自己的NetSession会话逻辑。

实在简单的应用,也可以直接实例化NetServer,然后通过事件来处理收到的连接和数据。

这里我们写了个MyNetServer,没有任何代码,仅仅是为了指定使用哪个网络会话类。

网络会话NetSession非常重要,每一个Tcp连接就对应一个会话,对Udp来说同一个远端套接字(IP+端口)就是一个会话。


网络会话最重要的有几块:

  1. OnConnected 连接 ,Tcp三次握手之后,双方还没有发送数据包之前,此时可以做一些准备工作,或者向客户端发送欢迎语。Udp会话开始在第一个数据包达到时也会调用Start。
  2. OnDisconnected 断开 。客户端连接断开或者服务端主动断开时。
  1. OnReceive 接收 ,每次收到数据包以后,都会触发该方法,数据包位于e.Packet。Tcp默认同步处理,未完成当前数据包处理之前,不会接收本连接的下一个数据包。
  2. Send 发送 。发送Packet数据包给本会话连接的客户端,扩展方法支持发送字符串或数据流。
  1. OnError 错误 。发生异常时。

!!!注意: 粘包问题在OnReceive之前处理,下回有专门文章分析,接收数据的ReceivedEventArgs里面还有个Message,支持编码器对数据包进行解码成为消息 。

 

使用服务端

本例程是Echo回声程序,因此OnReceive把收到的数据包原样发回去。

服务端用法很简单

        static TimerX _timer;
        static NetServer _server;
        static void TestServer()
        {
            // 实例化服务端,指定端口,同时在Tcp/Udp/IPv4/IPv6上监听
            var svr = new MyNetServer
            {
                Port = 1234,
                Log = XTrace.Log,
                SessionLog = XTrace.Log,
#if DEBUG
                SocketLog = XTrace.Log,
                LogSend = true,
                LogReceive = true,
#endif
            };
            svr.Start();
            _server = svr;
            // 定时显示性能数据
            _timer = new TimerX(ShowStat, svr, 100, 1000) { Async = true };
        }
        static void ShowStat(Object state)
        {
            var msg = "";
            if (state is NetServer ns)
                msg = ns.GetStat();
            //else if (state is ISocketRemote ss)
            //    msg = ss.GetStat();
            Console.Title = msg;
        }


指定端口和日志,然后就可以开始服务了。

默认在Tcp/Udp/IPv4/IPv6上监听,客户端爱用哪个协议来连接都行。

当然,NetServer还可以支持多个端口同时监听,共用数据处理代码。

服务端后面附带了一个定时器,每秒在控制台标题栏显示服务端状态统计信息。


注意, Debug模式用于开发观察日志,Release用于压测,看不到详细日志 。

调试模式运行效果

 从日志来看,客户端连接(Tcp.New)时,向客户端发送问候语(Tcp.Send),然后收到客户端请求(Tcp.Recv)并响应。

全程只有一个客户端连接,服务端只用一个线程(ThreadID=4)处理所有请求。

客户端断开连接时,服务端内部会抛出异常,在控制台里面异常日志一律以红色显示。

MyNetSession.OnError也捕获到了这个异常。

最后是客户端断开触发Dispose事件。


使用客户端

客户端用法更简单

static void TestClient()
{
    var uri = new NetUri("tcp://::1:1234");
    //var uri = new NetUri("tcp://net.newlifex.com:1234");
    var client = uri.CreateRemote();
    client.Log = XTrace.Log;
    client.LogSend = true;
    client.LogReceive = true;
    client.Received += (s, e) =>
    {
        XTrace.WriteLine("收到:{0}", e.Packet.ToStr());
    };
    client.Open();
    // 定时显示性能数据
    _timer = new TimerX(ShowStat, client, 100, 1000);
    // 循环发送数据
    for (var i = 0; i < 5; i++)
    {
        Thread.Sleep(1000);
        var str = "你好" + (i + 1);
        client.Send(str);
    }
    client.Dispose();
}

运行效果

客户端执行Dispose后,会调用Close关闭到服务端的连接。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70012705/viewspace-2851595/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2022-01-11

  • 博文量
    4
  • 访问量
    1566