程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#網絡編程(異步傳輸字符串)三

C#網絡編程(異步傳輸字符串)三

編輯:C#入門知識

這篇文章我們將前進一大步,使用異步的方式來對服務端編程,以使它成為一個真正意義上的服務器:可以為多個客戶端的多次請求服務。但是開始之前,我們需要解決上一節中遺留的一個問題。

消息發送時的問題

這個問題就是:客戶端分兩次向流中寫入數據(比如字符串)時,我們主觀上將這兩次寫入視為兩次請求;然而服務端有可能將這兩次合起來視為一條請求,這在兩個請求間隔時間比較短的情況下尤其如此。同樣,也有可能客戶端發出一條請求,但是服務端將其視為兩條請求處理。下面列出了可能的情況,假設我們在客戶端連續發送兩條“Welcome to Tracefact.net!”,則數據到達服務端時可能有這樣三種情況:

\

NOTE:在這裡我們假設采用ASCII編碼方式,因為此時上面的一個方框正好代表一個字節,而字符串到達末尾後為持續的0(因為byte是值類型,且最小為0)。

上面的第一種情況是最理想的情況,此時兩條消息被視為兩個獨立請求由服務端完整地接收。第二種情況的示意圖如下,此時一條消息被當作兩條消息接收了:

\

而對於第三種情況,則是兩條消息被合並成了一條接收:

\

如果你下載了上一篇文章所附帶的源碼,那麼將Client2.cs進行一下修改,不通過用戶輸入,而是使用一個for循環連續的發送三個請求過去,這樣會使請求的間隔時間更短,下面是關鍵代碼:

string msg = "Welcome to TraceFact.Net!";

for (int i = 0; i <= 2; i++) {
    byte[] buffer = Encoding.Unicode.GetBytes(msg);     // 獲得緩存
    try {
        streamToServer.Write(buffer, 0, buffer.Length); // 發往服務器
        Console.WriteLine("Sent: {0}", msg);
    } catch (Exception ex) {
        Console.WriteLine(ex.Message);
        break;
    }
}

運行服務端,然後再運行這個客戶端,你可能會看到這樣的結果:

\

\

可以看到,盡管上面將消息分成了三條單獨發送,但是服務端卻將後兩條合並成了一條。對於這些情況,我們可以這樣處理:就好像HTTP協議一樣,在實際的請求和應答內容之前包含了HTTP頭,其中是一些與請求相關的信息。我們也可以訂立自己的協議,來解決這個問題,比如說,對於上面的情況,我們就可以定義這樣一個協議:

[length=XXX]:其中xxx是實際發送的字符串長度(注意不是字節數組buffer的長度),那麼對於上面的請求,則我們發送的數據為:“[length=25]Welcome to TraceFact.Net!”。而服務端接收字符串之後,首先讀取這個“元數據”的內容,然後再根據“元數據”內容來讀取實際的數據,它可能有下面這樣兩種情況:

NOTE:我覺得這裡借用“元數據”這個術語還算比較恰當,因為“元數據”就是用來描述數據的數據。

  • “[“”]”中括號是完整的,可以讀取到length的字節數。然後根據這個數值與後面的字符串長度相比,如果相等,則說明發來了一條完整信息;如果多了,那麼說明接收的字節數多了,取出合適的長度,並將剩余的進行緩存;如果少了,說明接收的不夠,那麼將收到的進行一個緩存,等待下次請求,然後將兩條合並。
  • “[”“]”中括號本身就不完整,此時讀不到length的值,因為中括號裡的內容被截斷了,那麼將讀到的數據進行緩存,等待讀取下次發送來的數據,然後將兩次合並之後再按上面的方式進行處理。

接下來我們來看下如何來進行實際的操作,實際上,這個問題已經不屬於C#網絡編程的內容了,而完全是對字符串的處理。所以我們不再編寫服務端/客戶端代碼,直接編寫處理這幾種情況的方法:

public class RequestHandler {
    private string temp = string.Empty;

    public string[] GetActualString(string input) {
        return GetActualString(input, null);
    }

    private string[] GetActualString(string input, List<string> outputList) {
        if (outputList == null)
            outputList = new List<string>();

        if (!String.IsNullOrEmpty(temp))
            input = temp + input;

        string output = "";
        string pattern = @"(?<=^[length=)(d+)(?=])";
        int length;
                   
        if (Regex.IsMatch(input, pattern)) {

            Match m = Regex.Match(input, pattern);

            // 獲取消息字符串實際應有的長度
            length = Convert.ToInt32(m.Groups[0].Value);

            // 獲取需要進行截取的位置
            int startIndex = input.IndexOf(]) + 1;

            // 獲取從此位置開始後所有字符的長度
            output = input.Substring(startIndex);

            if (output.Length == length) {
         

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved