2020年10月12日星期一

超详细的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" + "\r\n"; 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,有格式要求,所以我们需要准守。

格式要求如下:

命令名称+空格+参数+参数+...参数+"\r\n"

对应的字符串如下:

$"ADD kiba518 518" + "\r\n"

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

客户端与服务联调

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

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

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

创建配置模式的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初始化失败\r\n");  return; }  var result = bootstrap.Start(); foreach (var server in bootstrap.AppServers) {  if (server.State == ServerState.Running)  {   Console.WriteLine(DateTime.Now + ":serverName为:" + server.Name + "Socket运行中\r\n");     }  else  {   Console.WriteLine(DateTime.Now + ":serverName为:" + server.Name + "Socket启动失败\r\n");​  } } Console.ReadKey();  

没有评论:

发表评论