介紹和背景
TCP編程是網絡編程領域最有趣的部分之一。在Ubuntu環境中,我喜歡使用.NET Core進行TCP編程,並使用本機Ubuntu腳本與TCP服務器進行通信。以前,我在.NET框架本身寫了一篇關於TCP服務器和客戶端的文章。現在,.NET框架本身將是開源的。我想寫一些關於他們之間的溝通渠道。基本上,我只是測試在新的.NET環境下工作的情況,而不是在舊的.NET框架環境中工作。
然而,在這篇文章中,我有一大堆的額外功能可供你使用。我將向您展示您將使用的方法來構建自己的TCP服務器,使用.NET核心程序集以及如何通過網絡與他們進行通信。對於客戶端應用程序,我不會構建任何東西。相反,我將使用允許通過TCP和UDP協議進行通信的本地腳本。
議程是這樣的:
-
構建和托管一個內置.NET Core的TCP服務器
-
啟動請求並使用TCP客戶端本機腳本將文本數據和文件數據發送到服務器。
這些是我會在這篇文章中引導你的一些東西,我也會澄清一切的目的。
我們不打算在這里建立任何特殊的應用程序,但是TCP是傳輸層中使用最廣泛的協議(與UDP相反),我們經常使用的大多數應用程序和服務都依賴於這個協議。HTTP,FTP,SMTP和所有其他類似協議直接依賴於TCP,並使用基於TCP協議的套接字(端口)進行通信。因此,您可以從最小的程序中啟動您的服務器,並在其上構建一個龐大的企業應用程序。它可以根據應用編程框架和連接到它的客戶端(或用戶)的需要進行擴展。
但是,我不打算談論如何構建這些復雜的應用程序,但是我將簡要介紹一下TCP服務器和基於客戶端的通信。為什么寫這個帖子?我將介紹跨平台環境下的TCP消耗。我將使用.NET Core創建服務器。其余部分將在本地完成,我將在Ubuntu中使用“nc”命令與我剛剛創建的服務器進行通信。因此,這個想法是讓你了解如何在.NET Core中構建一個服務器來提高效率和控制能力,以及如何使用多個平台及其服務與服務器進行通信,從而使用戶能夠與TCP服務器通信。那么,讓我們開始吧。
構建服務器端
在.NET環境中,System.Net命名空間包含了可用於學習和編程目的的所有參考資料。在服務器端編程任務中,我將使用TcpListener對象來處理傳入的TCP通信。基本上,這是一個本地的TCP部分,你會很快習慣它。我一直在使用這個對象以及在其生命周期中使用這個對象的程序,用於我自己的個人應用程序和一些基於網絡的應用程序,客戶端應用程序,設備和機器能夠通過路由器(調制解調器,或WLAN熱點等)。這樣,我可以創建一個使用TCP協議進行通信的中央服務器,並且可以使用TCP進行通信的客戶端也可以從此服務器發送或接收數據。然而,我不會深入到以多種格式通過網絡提交和傳輸數據。為了簡單起見,我將把事情簡單明了,因此我將不得不以純文本格式工作。
服務器 - 客戶端通信如何在TCP環境中工作的基本演示在以下創建的位圖圖形藝術中得到了演示:
圖1:服務器 - 客戶端設置
如圖所示,服務器控制資源的使用和使用方式。客戶端可以使用任何可以通過網絡使用TCP協議進行通信的設備。服務器處理請求並授予對資源的訪問權限。就像與其他程序交互一樣,TCP客戶端可以與TCP服務器交互,發送命令,發送請求,發送選項選擇(例如選擇要觸發的服務)等等。然后,TCP服務器處理這些請求,並根據這些請求以及正在傳遞的數據的值生成響應。TCP服務器可以:
-
通過TCP協議處理傳入的請求。
-
作為服務在后台運行; 哪些其他服務器也可以做。
-
將線路上的數據資源作為字節流發送。
-
盡管TCP服務器被認為是共享消息的純文本框架,但實際上不是消息,而是發送的字節。
-
TCP通信中的序列實際上是發送的字節,而不是消息。所以,客戶端應該能夠處理傳入的字節。
-
提供可靠的,有序的和錯誤檢查的方法和機制,在網絡上進行通信,而不是我們正在創建的服務器,而是協議。
在.NET Core中,TCP偵聽器允許您通過使用固定大小的靜態緩沖區來處理可用的字節數。有時,可能不會發送數據來填充緩沖區,有時緩沖區可能不足以覆蓋所有的緩沖區。
運行服務器的源代碼就像下面這樣簡單:
-
實例化對象。
-
設置IP地址來監聽和端口監聽。
-
等待客戶連接。
這一步承載服務器。在這個階段,承載服務器的程序應該保持活動並運行,否則程序將終止,關閉服務器本身。看看下面給出的代碼:
-
IPAddress address = IPAddress.Parse(“127.0.0.1” );
-
listener = new TcpListener(address,port);
-
listener.Start();
-
//代碼停止服務器並使用
-
// listener.AcceptTcpClientAsync();
-
//獲取連接客戶端的函數
這段代碼完成了我們在服務器端需要做的工作。即主持它。我用下面的代碼實際上表示服務器正在運行,並在此刻處於活動狀態。服務器本身不顯示為正在運行。
-
Console.WriteLine($ “Server started。Listen to TCP clients at 127.0.0.1:{port}” );
在這個階段之后,我們需要停止服務器自行終止。而不是保持相同的功能,並在這行代碼后,我創建了一個分離的功能,並在那里添加代碼等待客戶端。我們班有兩個功能,
-
啟動服務器
-
聽客戶
這是執行程序中大部分工作的第二個功能。這里是我們可以添加異步模式和多線程來支持多個客戶端同時連接的地方。不過,我並不打算在這一節中進一步深入。所以,正確的代碼來實際啟動服務器,並聽取客戶端如下所示:
-
using System;
-
using System.Net;
-
using System.Text;
-
using System.Net.Sockets;
-
namespace ConsoleApplication
-
{
-
class TcpHelper
-
{
-
privatestatic TcpListener listener { get; set; }
-
privatestaticbool accept { get; set; } = false;
-
publicstaticvoid StartServer(int port) {
-
IPAddress address = IPAddress.Parse("127.0.0.1");
-
listener = new TcpListener(address, port);
-
listener.Start();
-
accept = true;
-
Console.WriteLine($"Server started. Listening to TCP clients at 127.0.0.1:{port}");
-
}
-
publicstaticvoid Listen()
-
{
-
if(listener != null && accept)
-
{
-
// Continue listening.
-
while (true)
-
{
-
Console.WriteLine("Waiting for client...");
-
var clientTask = listener.AcceptTcpClientAsync(); // Get the client
-
if(clientTask.Result != null)
-
{
-
Console.WriteLine("Client connected. Waiting for data.");
-
var client = clientTask.Result;
-
string message = "";
-
while (message != null && !message.StartsWith("quit"))
-
{
-
byte[] data = Encoding.ASCII.GetBytes("Send next data: [enter 'quit' to terminate] ");
-
client.GetStream().Write(data, 0, data.Length);
-
byte[] buffer = newbyte[1024];
-
client.GetStream().Read(buffer, 0, buffer.Length);
-
message = Encoding.ASCII.GetString(buffer);
-
Console.WriteLine(message);
-
}
-
Console.WriteLine("Closing connection.");
-
client.GetStream().Dispose();
-
}
-
}
-
}
-
}
-
}
-
}
此代碼啟動服務器並繼續等待新的客戶端。一旦客戶端連接,它會向客戶端請求數據,並將該數據發布到客戶端發送“退出”到服務器。基本上,這是一個非常簡單但功能強大的服務器示例,用於教育目的。當然,我們現在也需要從主函數中調用這些函數,以便運行該項目。
-
public static void Main(string [] args)
-
{
-
//啟動服務器
-
TcpHelper.StartServer(5678);
-
TcpHelper.Listen(); //開始聆聽
-
}
目前我們已經完成了服務器端的腳本。服務器設置好后,會聽取客戶端的請求和數據,它們會傳遞到我們的服務器上。我們現在需要運行程序並啟動服務器來監聽請求。我不深入.NET核心執行過程和構建過程的深入; 至於那個,看我的另一個帖子:
-
在Linux上使用.NET Core快速啟動
運行程序,只需要執行下面的命令,
運行dotnet
輸出結果
如圖2所示:服務器啟動
正如你所看到的,TCP服務器在IP上啟動,我們指定了我們在函數調用中傳遞的端口。
其余的留給客戶端
正如我之前談到的,我將使用本地TCP客戶端而不是.NET核心的TCPClient對象,這樣即使在系統上沒有安裝.NET的情況下也可以使用服務器(例如,使用.NET框架的TCPClient對象)。在這篇文章中,我將在Unix(Linux和衍生)系統中使用“netcat”命令腳本。溝通可以簡單地完成。您可以從在線資源中了解更多關於這個腳本的內容,因為我不想再深究。我只是想演示這個用法。要了解更多信息,您可以訪問以下任一網址並了解更多信息:
-
nc - Unix,Linux命令
-
如何使用Netcat在VPS上建立和測試TCP和UDP連接
-
nc(1) - Linux手冊頁
您將能夠理解如何使用此命令來充當客戶端。這也允許你創建一個充當服務器的程序腳本,監聽網絡上的請求,但我們對這些因素不感興趣。相反,我們只是期待發送一個請求到服務器,並傳遞一些將顯示在屏幕上的數據。
連接和發送數據到服務器:
第一步是連接到TCP服務器。我們需要兩件事來建立連接,
-
IP地址
-
端口連接
我們將把它們作為參數傳遞給
$ nc 127.0.0.1 5678
下面的屏幕出現(我們的服務器接受請求並返回一條消息)
圖3:客戶端連接
(查看我們服務器的代碼,了解更多信息。 )
接下來,我們可以從這個終端發送數據,因為它需要更多的數據。我們將發送幾個字節的數據,然后發送“退出”來終止連接。讓我們看看這是如何工作的上下文。
圖4:客戶端將數據發送到服務器
我們發送了三條消息到服務器。所有這些都被檢查,最后在最后一條消息,流被關閉,終端開始要求更多的命令(而不是要求更多的數據)。為什么?如果你注意,你會看到“quit”命令已經被設置為連接的終結符。當我們發送這個命令時,連接終止,我們需要再次啟動連接。現在,我們來看另一邊。
圖5:服務器端消息日志
看看每個事件的行為如何變化。一旦我們的客戶端連接,在這里記錄一條消息:“客戶端連接。等待數據“。當客戶端連接時顯示此消息。您還可以記錄該客戶的時間和其他詳細信息。我們通過數據傳遞,在“退出”之后,你可以看到有一個“關閉連接”的日志,在另一端也應該顯示,但不幸的是,我錯過了這一點。您必須已經知道使用客戶端連接到服務器並發送數據。
興趣點
最后,這篇文章簡要介紹了.NET Core中的TCP編程,以及如何通過使用其他平台服務與服務器進行通信來抽象出整個概念。