自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

開(kāi)發(fā) 后端
C#網(wǎng)絡(luò)編程消息發(fā)送問(wèn)題是什么呢?C#網(wǎng)絡(luò)編程消息發(fā)送問(wèn)題是如何解決的呢?那么本文就向你介紹相關(guān)的內(nèi)容。

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

三種情況 

NOTE:在這里我們假設(shè)采用ASCII編碼方式,因?yàn)榇藭r(shí)上面的一個(gè)方框正好代表一個(gè)字節(jié),而字符串到達(dá)末尾后為持續(xù)的0(因?yàn)閎yte是值類型,且最小為0)。

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

一條消息被當(dāng)作兩條消息接收 

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

合并成了一條接收 

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

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

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

運(yùn)行服務(wù)端 

運(yùn)行客戶端 

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

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

NOTE:我覺(jué)得這里借用“元數(shù)據(jù)”這個(gè)術(shù)語(yǔ)還算比較恰當(dāng),因?yàn)椤霸獢?shù)據(jù)”就是用來(lái)描述數(shù)據(jù)的數(shù)據(jù)。

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

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

這個(gè)方法接收一個(gè)滿足協(xié)議格式要求的輸入字符串,然后返回一個(gè)數(shù)組,這是因?yàn)槿绻霈F(xiàn)多次請(qǐng)求合并成一個(gè)發(fā)送過(guò)來(lái)的情況,那么就將它們?nèi)糠祷?。隨后簡(jiǎn)單起見(jiàn),我在這個(gè)類中添加了一個(gè)靜態(tài)的Test()方法和PrintOutput()幫助方法,進(jìn)行了一個(gè)簡(jiǎn)單的測(cè)試,注意我直接輸入了length=13,這個(gè)是我提前計(jì)算好的。

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

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

輸出結(jié)果 

OK,從上面的輸出可以看到,這個(gè)方法能夠滿足我們的要求。對(duì)于這篇文章最開(kāi)始提出的問(wèn)題,可以很輕松地通過(guò)加入這個(gè)方法來(lái)解決,這里就不再演示了。

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

【編輯推薦】

  1. C#異步調(diào)用的應(yīng)用實(shí)踐淺談
  2. 委托實(shí)現(xiàn)C#異步調(diào)用淺析
  3. 淺析C#中異步和多線程的區(qū)別
  4. C# Socket通信三大問(wèn)題詳解
  5. C#異步調(diào)用四大方法詳解
責(zé)任編輯:仲衡 來(lái)源: 博客園
相關(guān)推薦

2009-07-30 18:50:32

C#發(fā)送消息C#應(yīng)用程序

2009-08-21 14:47:39

C#網(wǎng)絡(luò)編程

2009-08-21 17:19:36

C#網(wǎng)絡(luò)編程入門

2009-09-03 17:40:25

C#發(fā)送短信

2009-08-27 14:12:02

C# interfac

2009-08-21 10:17:14

C#異步網(wǎng)絡(luò)編程

2009-09-03 17:10:57

2009-08-20 17:30:56

C#異步編程模式

2009-08-21 17:48:43

C#網(wǎng)絡(luò)編程

2009-08-21 17:53:25

C#網(wǎng)絡(luò)編程客戶端程序

2009-09-04 18:16:19

C# Main參數(shù)C# Main

2009-01-16 09:58:07

C#編程C#內(nèi)存管理垃圾收集

2009-08-31 17:02:28

C#接口編程

2009-03-10 13:59:41

C#套接字編程

2009-08-21 17:33:34

服務(wù)器端程序C#網(wǎng)絡(luò)編程

2009-08-21 17:39:20

服務(wù)器端程序C#網(wǎng)絡(luò)編程

2009-08-25 15:52:27

C#工具欄

2009-08-20 17:47:54

C#異步編程模式

2009-08-14 17:45:52

C# ArrayLis

2009-08-17 18:34:50

C# ChangeCo
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)