zoukankan      html  css  js  c++  java
  • 超详细的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

     

  • 相关阅读:
    JeePlus:代码生成器
    JeePlus:API工具
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
  • 原文地址:https://www.cnblogs.com/kiba/p/13728088.html
Copyright © 2011-2022 走看看