• 超详细的TCP、Sokcket和SuperSocket入门指导


    前言

    本文主要介绍TCP、Sokcket和SuperSocket的基础使用。

    创建实例模式的SuperSocket服务

    首先创建控制台项目,然后Nuget添加引用SuperSocket.Engine。

    然后编写服务代码,SuperSocket的服务代码主要是配置AppServer对象,因为AppServer已经很好的封装端口监听了。

    代码如下所示:

     class Program
     {
         static AppServer appServer { get; set; }
         static void Main(string[] args)
         {
             var serverConfig = new SuperSocket.SocketBase.Config.ServerConfig();
             serverConfig.Port = 5180;
             serverConfig.TextEncoding = "gb2312";
             serverConfig.MaxConnectionNumber = 1000;
             appServer = new AppServer(); 
             //配置
             if (!appServer.Setup(serverConfig))  
             {
                 Console.WriteLine("配置失败!"); 
                 return;
             } 
             //启动
             if (!appServer.Start())
             {
                 Console.WriteLine("启动失败!"); 
                 return;
             } 
             Console.WriteLine("启动成功,按Q退出!"); 
             appServer.NewSessionConnected += new SessionHandler<AppSession>(appServer_NewSessionConnected);
             appServer.SessionClosed += appServer_NewSessionClosed; 
             appServer.NewRequestReceived += new RequestHandler<AppSession, StringRequestInfo>(appServer_NewRequestReceived); 
             while (Console.ReadKey().KeyChar != 'q')
             { 
                 continue;
             } 
             //停止
             appServer.Stop(); 
             Console.WriteLine("服务已停止");
             Console.ReadKey();
         }  
        static void appServer_NewSessionConnected(AppSession session)
        {
            var count = appServer.SessionCount;
            Console.WriteLine($"服务端得到来自客户端的连接成功 ,当前会话数量:" + count);  
            //这里也可以向会话的stream里写入数据,如果在这里向流写入数据,则客户端需要在Send之前先接收一次,不然的话,Send后接收的就是这条数据了
            session.Send("连接成功");
        } 
        static void appServer_NewSessionClosed(AppSession session, CloseReason aaa)
        {
            var count = appServer.SessionCount;
            Console.WriteLine($"服务端 失去 来自客户端的连接" + session.SessionID + aaa.ToString()+ " 当前会话数量:" + count); 
        } 
        static void appServer_NewRequestReceived(AppSession session, StringRequestInfo requestInfo)
        {
            Console.WriteLine($"Key:" + requestInfo.Key + $" Body:" + requestInfo.Body);
            session.Send("我是返回值:" + requestInfo.Body);
        } 
    ​
     }
    

    AppServer:AppServer是SuperSocket中定义的Socket服务类,他替我们实现了复杂的端口监听,不用再写While循环,不用再关心线程阻塞的问题,在监听端口在这里,我们只要调用AppServer的对象的Start方法,就可以了;AppServer还提供了一个配置文件类—ServerConfig,通过它,我们可以配置具体监听的端口、并发数量、编码、最大传输字节数、传输模式(TCP/UDP)等等属性;此外还提供三个重要事件:会话连接启动事件(NewSessionConnected)、会话关闭事件(SessionClosed)、请求接受事件(NewRequestReceived)。

    注:文中在连接成功的事件中,我们向客户端发送消息了,即,客户端在连接后,发送消息前,需要接收该信息。

    创建TCP发送消息客户端

    服务建立后,我们建立客户端。

    代码如下所示:

    static void Main(string[] args)
    {
        TCPConnect("127.0.0.1", 5180);    
        Console.ReadKey();
    }
    static void TCPConnect(String server, Int32 port)
    {
        string message = $"ADD kiba518 518" + "
    ";
        try
        { 
            TcpClient client = new TcpClient();
            client.Connect(server, port); 
            Byte[] data = System.Text.Encoding.Default.GetBytes(message); 
            String responseData = String.Empty; 
            NetworkStream stream = client.GetStream(); 
            byte[] buffer = new byte[1024 * 1024 * 2];
            Int32 bytes = stream.Read(buffer, 0, buffer.Length);
            responseData = System.Text.Encoding.Default.GetString(buffer, 0, bytes);
            Console.WriteLine("接收服务器在连接事件中写入的数据: {0}", responseData); 
            stream.Write(data, 0, data.Length); 
            Console.WriteLine("发送数据: {0}", message); 
            data = new Byte[256]; 
            bytes = stream.Read(buffer, 0, buffer.Length);
            responseData = System.Text.Encoding.Default.GetString(buffer, 0, bytes);
            Console.WriteLine("接收返回值: {0}", responseData); 
            stream.Close();
            client.Close();
        }
        catch (ArgumentNullException e)
        {
            Console.WriteLine("ArgumentNullException: {0}", e.Message);
        }
        catch (SocketException e)
        {
            Console.WriteLine("SocketException: {0}", e.Message);
        } 
        Console.Read();
    }

    代码很简单,就是使用TcpClient连接服务器的IP和端口,然后发送消息。

    因为我们使用的SuperSocket,有格式要求,所以我们需要准守。

    格式要求如下:

    命令名称+空格+参数+参数+...参数+" "

    对应的字符串如下:

    $"ADD kiba518 518" + " "

    因为上文中,服务在连接成功后就向客户端发送的流中写入了数据,所以,我们在Send消息前,先接收一下流中的数据。

    客户端与服务联调

    先运行服务,在运行客户端,结果服务端与客户端成功的完成了一次通信,如下图所示:

    为了更清晰的了解通信内容,我们在服务接收消息事件中断点,如下图:

    可以看到参数requestInfo完整的解析了我们发送的字符串【"ADD kiba518 518" + " "】。

    创建配置模式的SuperSocket服务

    现在我们创建一个配置模式的SuperSocket服务,这种模式客户通过配置创建多个SuperSocket,即可以在一个项目里通过配置监听多个端口,这里,我们只做一个端口监听的配置例子。

    与实例模式的开始一样,先创建一个控制台程序,然后Nuget添加引用SuperSocket.Engine。

    然后进行三步操作。

    一,编写Main函数,启动SuperSocket,通过启动引导工厂BootstrapFactory实例化一个启动引导对象,然后初始化化,该初始化会遍历当前项目中所有继承了AppServer的类,然后调用他们的Start方法,代码如下所示:

    static void Main(string[] args)
    {
        #region 初始化Socket
        IBootstrap bootstrap = BootstrapFactory.CreateBootstrap();
        if (!bootstrap.Initialize())
        {
            Console.WriteLine(DateTime.Now + ":Socket初始化失败
    ");
            return;
        } 
        var result = bootstrap.Start();
        foreach (var server in bootstrap.AppServers)
        {
            if (server.State == ServerState.Running)
            {
                Console.WriteLine(DateTime.Now + ":serverName为:" + server.Name + "Socket运行中
    ");
                
            }
            else
            {
                Console.WriteLine(DateTime.Now + ":serverName为:" + server.Name + "Socket启动失败
    ");
    ​
            }
        }
        Console.ReadKey(); 
        #endregion
    }

    二,修改App.config配置文件,在configuration节点下,增加superSocket的section,并配置superSocket,代码如下:

    <configSections>
        <section name="superSocket" type="SuperSocket.SocketEngine.Configuration.SocketServiceConfig, SuperSocket.SocketEngine" /> 
      </configSections>
      <!--配置SocketServer路径-->
      <superSocket>
        <servers>
      <!-- serverType属性有两个参数,第一个是服务类的完全限定名,第二个是服务类的命名空间 -->
          <server name="MySocket" textEncoding="gb2312"
                  serverType="SuperSocketServerSessionMode.SocketServer, SuperSocketServerSessionMode"
                 ip="Any" port="5180" maxConnectionNumber="100">
          </server>
        </servers>
       </superSocket>

    三,创建SocketServer类、SocketSession类、SocketCommand类。

    SocketServer类:继承泛型AppServer(其泛型类指定一个会话类)该类用于创建SuperSocket的服务并监听端口;其Setup方法,默认读取App.config配置文件中的superSocket节点—servers节点—server节点;读取时根据server的serverType属性匹配读取。

    public class SocketServer : AppServer<SocketSession>
    {
        protected override bool Setup(IRootConfig rootConfig, IServerConfig config)
        {
            Console.WriteLine("正在准备配置文件");
            return base.Setup(rootConfig, config);
        } 
        protected override void OnStarted()
        {
            Console.WriteLine("服务已开始");
            base.OnStarted();
        } 
        protected override void OnStopped()
        {
            Console.WriteLine("服务已停止");
            base.OnStopped();
        }
        protected override void OnNewSessionConnected(SocketSession session)
        {
            Console.WriteLine("新的连接地址为" + session.LocalEndPoint.Address.ToString() + ",时间为" + DateTime.Now);
            base.OnNewSessionConnected(session);
        }
    }
    

    SocketSession类:继承AppSession,是SuperSocket的会话类。

    如果客户端所发送的消息不合法,则会被会话的HandleUnknownRequest函数截获,如果合法,则发送到指定的命令类中。

    代码如下:

    public class SocketSession : AppSession<SocketSession>
    {
        public override void Send(string message)
        {
            Console.WriteLine("发送消息:" + message);
            base.Send(message);
        } 
        protected override void OnSessionStarted()
        {
            Console.WriteLine("Session已启动");  
            base.OnSessionStarted();
        } 
        protected override void OnInit()
        {
            this.Charset = Encoding.GetEncoding("gb2312");
            base.OnInit();
        }
        protected override void HandleUnknownRequest(StringRequestInfo requestInfo)
        { 
            Console.WriteLine($"遇到未知的请求 Key:" + requestInfo.Key + $" Body:" + requestInfo.Body);
            base.HandleUnknownRequest(requestInfo);
        }    
    }

    SocketCommand类:是SuperSocket的命令类,定义明确的会话命令;类名即客户端发送消息的第一个空格前的字符串。

    代码如下:

    public class SocketCommand : CommandBase<SocketSession, StringRequestInfo>
    {
        public override void ExecuteCommand(SocketSession session, StringRequestInfo requestInfo)
        {
            //根据参数个数或者其他条件判断,来进行一些自己的操作
            Console.WriteLine($"调用成功 Key:" + requestInfo.Key + $" Body:" + requestInfo.Body); 
            session.Send("已经成功接收到你的请求
    "); 
        }
    }

    创建配置模式的SuperSocket客户端

    创建一个配置模式的SuperSocket客户端,这一次我们使用Socket类创建。

    代码如下:

    static Socket socketClient { get; set; }
     static void Main(string[] args)
     {
        socketClient = new Socket(SocketType.Stream, ProtocolType.Tcp);
        IPAddress ip = IPAddress.Parse("127.0.0.1");
        IPEndPoint point = new IPEndPoint(ip, 5180); 
        socketClient.Connect(point); 
        Thread thread = new Thread(Recive); //不停的接收服务器端发送的消息
        thread.Start();
        Thread thread2 = new Thread(Send);//不停的给服务器发送数据
        thread2.Start();
     }
     static void Recive()
     { 
        while (true)
        {
            //获取发送过来的消息
            byte[] buffer = new byte[1024 * 1024 * 2];
            var effective = socketClient.Receive(buffer);
            if (effective == 0)
            {
                break;
            }
            var str = Encoding.Default.GetString(buffer, 0, effective);
            Console.WriteLine("服务器 --- " + str);
            Thread.Sleep(2000);
        }
     }
     static void Send()
     {
        int i = 0;int param1 = 0;int param2 = 0;
        while (true)
        {
            i++;param1 = i + 1;param2 = i + 2;
            Console.WriteLine($"Send  i:{i}  param1:{param1} param2:{param2}");
            string msg = $"SocketCommand {param1} {param2}" + "
    ";
            Console.WriteLine($"msg:{msg}");
            var buffter = Encoding.Default.GetBytes(msg);
            var temp = socketClient.Send(buffter);
            Console.WriteLine($"Send  发送的字节数:{temp} "); 
            Thread.Sleep(1000);
        } 
     }

    可以看到Socket的使用方式与Tcp的使用方式几乎相同,都是指定IP和端口号,只是Socket多了一步,需要指定协议类型ProtocolType,这里我们指定了是TCP。

    客户端与服务联调

    先运行服务,在运行客户端,结果通信成功,如下图所示:

    ----------------------------------------------------------------------------------------------------

    到此TCP、Sokcket和SuperSocket的基本使用已经介绍完了,代码已经传到Github上了,欢迎大家下载。

    代码已经传到Github上了,欢迎大家下载。

    Github地址: https://github.com/kiba518/SuperSocketConsole

    ----------------------------------------------------------------------------------------------------

    注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!
    若您觉得这篇文章还不错,请点击下方的推荐】,非常感谢!

    https://www.cnblogs.com/kiba/p/13728088.html

     

  • 相关阅读:
    Spring MVC 问题归纳
    Java中响应结果工具类,可自定义响应码,内容,响应消息
    Java 获取当前时间前一个小时的时间
    Java中获取32位UUID
    DebuggerStepThrough requests that the debugger step through a function without any user interaction.
    C# list all time zones
    C# remove single quotes from string
    Mock heartbeat via While true Thread.Sleep and System.Timers.Timer
    Notepad++ remove carrigae return format via regular expression [ ]+ replaced with :
    C# get class and method summary
  • 原文地址:https://www.cnblogs.com/kiba/p/13728088.html
Copyright © 2020-2023  润新知