在C#領(lǐng)域或者說(shuō).net通信領(lǐng)域中有著眾多的解決方案,WCF,HttPRequest,WebAPI,Remoting,socket等技術(shù)。這些技術(shù)都有著自己擅長(zhǎng)的領(lǐng)域,或者被合并或者仍然應(yīng)用于某些場(chǎng)合。本文主要介紹Socket通訊,因其有著跨平臺(tái)、跨語(yǔ)言、高性能等優(yōu)勢(shì),適合某些情況的應(yīng)用以及性能優(yōu)越的解決方案。
本文是基于一個(gè)小項(xiàng)目中的應(yīng)用,使用了異步方式的Socket通訊,性能上達(dá)到多客戶端多點(diǎn)通訊,大文件(M-G級(jí)別)的文件傳輸,異步長(zhǎng)連接上的性能優(yōu)勢(shì),但此項(xiàng)目也有些不足:未進(jìn)行大量的外網(wǎng)長(zhǎng)時(shí)間傳輸測(cè)試,對(duì)不穩(wěn)定的網(wǎng)絡(luò)狀況未做很好的處理,例如加入斷點(diǎn)續(xù)傳功能,對(duì)Socket傳輸錯(cuò)誤(其中微軟提供了大量的Socket通訊錯(cuò)誤代碼指示錯(cuò)誤類(lèi)型,請(qǐng)參考http://www.survivalescaperooms.com/Aricc/archive/2010/01/29/1659134.html)未做一個(gè)很好的分類(lèi)處理,只簡(jiǎn)單的統(tǒng)一為一個(gè)類(lèi)型的錯(cuò)誤。所以,此項(xiàng)目介紹只是想拋磚引玉介紹異步Socket通訊,如果有不足或改進(jìn)之處,還請(qǐng)各位不吝指出。
這里的同步和異步指的是服務(wù)端Accept接受客戶端連接請(qǐng)求的方式。在同步模式下,服務(wù)端要開(kāi)啟一個(gè)Thread線程循環(huán)監(jiān)聽(tīng)可能來(lái)自客戶端的服務(wù),如果沒(méi)有則阻塞,如果有連接則接受連接并存入Connection Pool連接池,這樣一個(gè)連接(或者說(shuō)一個(gè)連接線程,一般占用系統(tǒng)內(nèi)存約為2M,具體原因請(qǐng)參考《CLR via C#》中線程章節(jié)),這樣32位系統(tǒng)下單一應(yīng)用程序最大內(nèi)存不超過(guò)2G,也就是說(shuō),單一連接服務(wù)端所能接受客戶端最大的請(qǐng)求數(shù)為1000(實(shí)測(cè)下為700+);而異步連接則應(yīng)用非阻塞式異步連接機(jī)制(http://www.survivalescaperooms.com/2018/archive/2011/05/10/2040333.html)BeginAccept異步接受客戶端請(qǐng)求并執(zhí)行相應(yīng)請(qǐng)求邏輯,在執(zhí)行完畢后系統(tǒng)能自動(dòng)優(yōu)化,并當(dāng)再次應(yīng)用時(shí)喚醒,從而達(dá)到可接受大量的客戶端請(qǐng)求,但也限于“同時(shí)”執(zhí)行的客戶端數(shù)量,對(duì)于某些長(zhǎng)連接客戶端巨大,但并發(fā)性小的情景適用。
眾所周知,在Socket通訊中傳輸?shù)钠胀ǖ淖址蛘叨M(jìn)制數(shù)據(jù)流,不適用于一些復(fù)雜的情況,例如約定一個(gè)可擴(kuò)展的協(xié)議,可變長(zhǎng)協(xié)議等,所以本項(xiàng)目采用自定義協(xié)議類(lèi)型來(lái)滿足可擴(kuò)展需求:
Header | 協(xié)議頭 | 命令 | 流1長(zhǎng)度 | 流2長(zhǎng)度 |
2字節(jié) | 4字節(jié) | 4字節(jié) | 4字節(jié) | |
Body | 流1 | 流2 | ||
N字節(jié) | N字節(jié) |
說(shuō)明:
協(xié)議頭為:FF 7E ,2字節(jié)固定值
命令為:命令編號(hào),如1001
流1長(zhǎng)度:Int32型指示Body中的流1的長(zhǎng)度
流2長(zhǎng)度:Int32型指示Body中的流2的長(zhǎng)度
流1:字節(jié)流
流2:字節(jié)流
這樣,基于上述協(xié)議可自定義流1、流2的長(zhǎng)度分別存放不同數(shù)據(jù),基于協(xié)議還可以對(duì)數(shù)據(jù)協(xié)議進(jìn)行封裝,提供公共的解析方式。
1 /// <summary> 2 /// 通訊二進(jìn)制協(xié)議,此協(xié)議基于變長(zhǎng)的流傳輸。 3 /// 注:擴(kuò)展此方法成員時(shí),請(qǐng)重寫(xiě)相關(guān)方法。 4 /// </summary> 5 /// <remarks> 6 /// Create By CYS 7 /// </remarks> 8 public class CommunicateProtocol : IDisposable 9 { 10 #region Public Properties 11 /// <summary> 12 /// Byte array length of flag 13 /// </summary> 14 public const int ByteLength_HeaderFlag = 2; 15 /// <summary> 16 /// Byte array length of command 17 /// </summary> 18 public const int ByteLength_HeaderCmd = 4; 19 /// <summary> 20 /// Byte array length of header stream1 21 /// </summary> 22 public const int ByteLength_HeaderStream1Len = 4; 23 /// <summary> 24 /// Byte array length of header stream2 25 /// </summary> 26 public const int ByteLength_HeaderStream2Len = 4; 27 /// <summary> 28 /// 協(xié)議頭長(zhǎng)度 29 /// </summary> 30 public static int FlagLen 31 { 32 get { return ByteLength_HeaderFlag; } 33 } 34 /// <summary> 35 /// 命令(Int32) 36 /// </summary> 37 public int Command 38 { 39 get 40 { 41 return BitConverter.ToInt32(header_Cmd, 0); 42 } 43 set 44 { 45 BitConverter.GetBytes(value).CopyTo(header_Cmd, 0); 46 } 47 } 48 /// <summary> 49 /// 流1長(zhǎng)度 50 /// </summary> 51 /// <returns></returns> 52 public int Stream1Len 53 { 54 get 55 { 56 return BitConverter.ToInt32(header_Stream1Len, 0); 57 } 58 set 59 { 60 BitConverter.GetBytes(value).CopyTo(header_Stream1Len, 0); 61 } 62 } 63 /// <summary> 64 /// 流2長(zhǎng)度 65 /// </summary> 66 /// <returns></returns> 67 public int Stream2Len 68 { 69 get 70 { 71 return BitConverter.ToInt32(header_Stream2Len, 0); 72 } 73 set 74 { 75 BitConverter.GetBytes(value).CopyTo(header_Stream2Len, 0); 76 } 77 } 78 #endregion Public Properties 79 80 #region Private Properties 81 private static byte[] header_Flag = new byte[ByteLength_HeaderFlag]; 82 private byte[] header_Cmd = new byte[ByteLength_HeaderCmd]; 83 private byte[] header_Stream1Len = new byte[ByteLength_HeaderStream1Len]; 84 private byte[] header_Stream2Len = new byte[ByteLength_HeaderStream1Len]; 85 private byte[] body_Stream1 = new byte[0]; 86 private Stream body_Stream2; 87 #endregion Private Properties 88 89 #region Constructor 90 /// <summary> 91 /// Static constructor 92 /// </summary> 93 static CommunicateProtocol() 94 { 95 header_Flag = new byte[ByteLength_HeaderFlag] { 0xFF, 0x7E }; 96 } 97 98 #endregion Constructor 99 100 #region Public Method101 /// <summary>102 /// 判斷是否是協(xié)議頭標(biāo)志103 /// </summary>104 /// <param name="bytes"></param>105 /// <returns></returns>106 public static bool CheckFlag(byte[] bytes)107 {108 if (bytes.Length != header_Flag.Length)109 return false;110 if (bytes.Length != 2)111 return false;112 if (!bytes[0].Equals(header_Flag[0]) || !bytes[1].Equals(header_Flag[1]))113 return false;114 return true;115 }116 /// <summary>117 /// SetStream1118 /// </summary>119 /// <param name="sm"></param>120 public void SetStream1(byte[] sm)121 {122 body_Stream1 = sm;123 }124 /// <summary>125 /// GetStream1126 /// </summary>127 /// <returns></returns>128 public byte[] GetStream1()129 {130 return body_Stream1;131 }132 /// <summary>133 /// SetStream2134 /// </summary>135 /// <param name="sm"></param>136 public void SetStream2(Stream sm)137 {138 body_Stream2 = sm;139 }140 /// <summary>141 /// body_Stream2142 /// </summary>143 /// <returns></returns>144 public Stream GetStream2()145 {146 return body_Stream2;147 }148 /// <summary>149 /// GetHeaderBytes150 /// </summary>151 /// <returns></returns>152 public byte[] GetHeaderBytes()153 {154 int offset = 0;155 byte[] bytes = new byte[ByteLength_HeaderFlag + ByteLength_HeaderCmd + ByteLength_HeaderStream1Len + ByteLength_HeaderStream2Len];156 157 Array.Copy(header_Flag, 0, bytes, 0, ByteLength_HeaderFlag); offset += ByteLength_HeaderFlag;158 Array.Copy(header_Cmd, 0, bytes, offset, ByteLength_HeaderCmd); offset += ByteLength_HeaderCmd;159 Array.Copy(header_Stream1Len, 0, bytes, offset, ByteLength_HeaderStream1Len); offset += ByteLength_HeaderStream1Len;160 Array
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注