超詳細的TCP、Sokcket和SuperSocket與TCP入門指導

kiba518發表於2020-10-12

前言

本文主要介紹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(); 
    #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("已經成功接收到你的請求\r\n"); 
    }
}

建立配置模式的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}" + "\r\n";
        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

 

 

相關文章