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

前言

本文主要介紹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地址: //github.com/kiba518/SuperSocketConsole

—————————————————————————————————-

註:此文章為原創,任何形式的轉載都請聯繫作者獲得授權並註明出處!
若您覺得這篇文章還不錯,請點擊下方的推薦】,非常感謝!

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

 

 

Tags: