av激情亚洲男人的天堂国语,日韩欧美精品一中文字幕,无码av一区二区三区无码,国产又色又爽又刺激的a片,国产又色又爽又刺激的a片

C#網(wǎng)絡(luò)編程消息發(fā)送問題淺析

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

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

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

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

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

 
 
 
 
  1. string msg = "Welcome to TraceFact.Net!";
  2. for (int i = 0; i <= 2; i++) {
  3. byte[] buffer = Encoding.Unicode.GetBytes(msg);
  4.  // 獲得緩存
  5. try {
  6. streamToServer.Write(buffer, 0, buffer.Length);
  7.  // 發(fā)往服務(wù)器
  8. Console.WriteLine("Sent: {0}", msg);
  9. } catch (Exception ex) {
  10. Console.WriteLine(ex.Message);
  11. break;
  12. }
  13. }

C#網(wǎng)絡(luò)編程之運行服務(wù)端,然后再運行這個客戶端,你可能會看到這樣的結(jié)果:

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

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

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

“[“”]”中括號是完整的,可以讀取到length的字節(jié)數(shù)。然后根據(jù)這個數(shù)值與后面的字符串長度相比,如果相等,則說明發(fā)來了一條完整信息;如果多了,那么說明接收的字節(jié)數(shù)多了,取出合適的長度,并將剩余的進行緩存;如果少了,說明接收的不夠,那么將收到的進行一個緩存,等待下次請求,然后將兩條合并。
“[”“]”中括號本身就不完整,此時讀不到length的值,因為中括號里的內(nèi)容被截斷了,那么將讀到的數(shù)據(jù)進行緩存,等待讀取下次發(fā)送來的數(shù)據(jù),然后將兩次合并之后再按上面的方式進行處理。
接下來我們來看下如何來進行實際的操作,實際上,這個問題已經(jīng)不屬于C#網(wǎng)絡(luò)編程的內(nèi)容了,而完全是對字符串的處理。所以我們不再編寫服務(wù)端/客戶端代碼,直接編寫處理這幾種情況的方法:

 
 
 
 
  1. public class RequestHandler {
  2. private string temp = string.Empty;
  3. public string[] GetActualString(string input) {
  4. return GetActualString(input, null);
  5. }
  6. private string[] GetActualString(
  7. string input, List outputList) {
  8. if (outputList == null)
  9. outputList = new List();
  10. if (!String.IsNullOrEmpty(temp))
  11. input = temp + input;
  12.  //C#網(wǎng)絡(luò)編程
  13. string output = "";
  14. string pattern = @"(?<=^\[length=)(\d+)(?=\])";
  15. int length;
  16. if (Regex.IsMatch(input, pattern)) {
  17. Match m = Regex.Match(input, pattern);
  18. // 獲取消息字符串實際應(yīng)有的長度
  19. length = Convert.ToInt32(m.Groups[0].Value);
  20. // 獲取需要進行截取的位置
  21. int startIndex = input.IndexOf(']') + 1;
  22. // 獲取從此位置開始后所有字符的長度
  23. output = input.Substring(startIndex);
  24. if (output.Length == length) {
  25. // 如果output的長度與消息字符串的應(yīng)有長度相等
  26. // 說明剛好是完整的一條信息
  27. outputList.Add(output);
  28. temp = "";
  29. } else if (output.Length < length) {
  30. // 如果之后的長度小于應(yīng)有的長度,
  31. // 說明沒有發(fā)完整,則應(yīng)將整條信息,包括元數(shù)據(jù),全部緩存
  32. // 與下一條數(shù)據(jù)合并起來再進行處理
  33. temp = input;
  34. // 此時程序應(yīng)該退出,因為需要等待下一條數(shù)據(jù)到來才能繼續(xù)處理
  35. } else if (output.Length > length) {
  36. // 如果之后的長度大于應(yīng)有的長度,
  37. // 說明消息發(fā)完整了,但是有多余的數(shù)據(jù)
  38. // 多余的數(shù)據(jù)可能是截斷消息,也可能是多條完整消息
  39. // 截取字符串
  40. output = output.Substring(0, length);
  41. outputList.Add(output);
  42. temp = "";
  43. // 縮短input的長度
  44. input = input.Substring(startIndex + length);
  45. // 遞歸調(diào)用  C#網(wǎng)絡(luò)編程
  46. GetActualString(input, outputList);
  47. }
  48. } else {// 說明“[”,“]”就不完整
  49. temp = input;
  50. }
  51. return outputList.ToArray();
  52. }
  53. }

這個方法接收一個滿足協(xié)議格式要求的輸入字符串,然后返回一個數(shù)組,這是因為如果出現(xiàn)多次請求合并成一個發(fā)送過來的情況,那么就將它們?nèi)糠祷亍kS后簡單起見,我在這個類中添加了一個靜態(tài)的Test()方法和PrintOutput()幫助方法,進行了一個簡單的測試,注意我直接輸入了length=13,這個是我提前計算好的。

 
 
 
 
  1. public static void Test() {
  2. RequestHandler handler = new RequestHandler();
  3. string input;
  4. // ***種情況測試 - 一條消息完整發(fā)送
  5. input = "[length=13]明天中秋,祝大家節(jié)日快樂!";
  6. handler.PrintOutput(input);
  7. // 第二種情況測試 - 兩條完整消息一次發(fā)送
  8. input = "明天中秋,祝大家節(jié)日快樂!";
  9. input = String.Format
  10. ("[length=13]{0}[length=13]{0}", input);
  11. handler.PrintOutput(input);
  12. // 第三種情況測試A - 兩條消息不完整發(fā)送
  13. input = "[length=13]明天中秋,祝大家節(jié)日快樂![length=13]明天中秋";
  14. handler.PrintOutput(input);
  15. input = ",祝大家節(jié)日快樂!";
  16. handler.PrintOutput(input);
  17.  //C#網(wǎng)絡(luò)編程
  18. // 第三種情況測試B - 兩條消息不完整發(fā)送
  19. input = "[length=13]明天中秋,祝大家";
  20. handler.PrintOutput(input);
  21. input = "節(jié)日快樂![length=13]明天中秋,祝大家節(jié)日快樂!";
  22. handler.PrintOutput(input);
  23.  //C#網(wǎng)絡(luò)編程
  24. // 第四種情況測試 - 元數(shù)據(jù)不完整
  25. input = "[leng";
  26. handler.PrintOutput(input); // 不會有輸出
  27. input = "th=13]明天中秋,祝大家節(jié)日快樂!";
  28. handler.PrintOutput(input);
  29. }
  30. // 用于測試輸出
  31. private void PrintOutput(string input) {
  32. Console.WriteLine(input);
  33. string[] outputArray = GetActualString(input);
  34. foreach (string output in outputArray) {
  35. Console.WriteLine(output);
  36. }
  37. Console.WriteLine();
  38. }

C#網(wǎng)絡(luò)編程運行上面的程序,可以得到如下的輸出:

OK,從上面的輸出可以看到,這個方法能夠滿足我們的要求。對于這篇文章最開始提出的問題,可以很輕松地通過加入這個方法來解決,這里就不再演示了。

C#網(wǎng)絡(luò)編程消息發(fā)送方面的內(nèi)容就向你介紹到這里,希望對你了解和學(xué)習(xí)C#網(wǎng)絡(luò)編程有所幫助。


分享名稱:C#網(wǎng)絡(luò)編程消息發(fā)送問題淺析
標題鏈接:http://uogjgqi.cn/article/dhhpcce.html
掃二維碼與項目經(jīng)理溝通

我們在微信上24小時期待你的聲音

解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流