[C#.NET] 開發通訊協定必須要會的技巧
基本上處理通訊協定需要瞭解到計算機概論的東西,比如 AND/OR/XOR 這些,理論上的東西可能就不是我能寫的了,我們來看看比較實務上的技巧
>> 運算子
先來看個例子
public void MyTestMethod2() { ushort source = 6235; byte hi = (byte)(source >> 8); byte lo = (byte)source; Debug.WriteLine("hi:{0},lo:{1}", hi, lo); }
Result
hi:24,lo:91
6235 變成 2進制 的樣子,最右邊的 Q 是基準點,如下圖
當調用 source >> 8 後,於是基準點來到了 Q,就可以得到 24
至於 (byte)source 會得到 91,就是因為byte 只能處理 8 個bit,其餘的都會被丟棄,所以轉型的時候一定要特別注意溢位跟資料遺失的問題
<< 運算子
再用同樣的例子解釋
public void MyTestMethod2() { ushort source = 6235; var hi = source << 8; Debug.WriteLine("hi:{0}", hi); }
Result:
hi:1596160
右邊多了 8 個bit ,所以轉成 10 進制的結果就是 1596160
.NET BCL 提供的 BitConverter.GetBytes 也可以達到 >> 的效果,取出特定的 byte
public void MyTestMethod2() { ushort source = 6235; var sourceArray = BitConverter.GetBytes(source); Debug.WriteLine("hi:{0},lo:{1}", sourceArray[0], sourceArray[1]); }
Result:
hi:91,lo:24
眼尖的捧油應該會發現sourceArray[0]存放的是91,不是24,這樣的組合我們稱為 Little-Endian,若需要將陣列要在轉換成所需的字串,要先調用Array.Reverse
以下範例就是將陣列轉成 Hexadecimal
public void MyTestMethod2() { short source = 6235; var sourceArray = BitConverter.GetBytes(source); Array.Reverse(sourceArray); var hi = Convert.ToString(sourceArray[0], 16); var lo = Convert.ToString(sourceArray[1], 16); Debug.WriteLine("hi:{0},lo:{1}", hi, lo); }
Result:
hi:18,lo:5b
I 運算子
這就是計算機概論講的 OR 運算;當進行 2 進位運算,只要有任一位元為 1 時,運算結果才能為 1
public void MyTestMethod2() { byte result = 25 | 155; Debug.WriteLine("result:{0}", result); }
result:155
轉換成2進制,如下圖:
& 運算子
這就是計算機概論講的 AND 運算;當進行 2 進位運算,只有兩個位元為 1 時,運算結果才能為 1,反之為 0
public void MyTestMethod2() { byte result = 25 & 155; Debug.WriteLine("result:{0}", result); }
result:25
轉換成2進制,如下圖:
^ 運算子
這就是計算機概論講的 XOR 運算;當進行 2 進位運算,只有一個位元為 1 時,運算結果才能為 1,反之為 0
public void MyTestMethod2() { byte result = 25 ^ 155; Debug.WriteLine("result:{0}", result); }
result:130
轉換成2進制,如下圖:
~ 運算子
這就是計算機概論講的 NOT ,就是 0 變 1,1 變 0,正號變負號,負號變正號
public void MyTestMethod2() { sbyte result = 25; Debug.WriteLine("result:{0}", ~result); }
result:-26
在用 TCP/Serial 處理通訊時,我們會需要用到byte[],我們有幾個方式可以組合所需的byte[],以下是我常遇到的情境。
- 情境一:用整數組合 protocol
使用MemoryStream
public void MyTestMethod2() { ushort transport = 1; ushort protocol = 0; byte function = 1; ushort length = 6; ushort start = 0; ushort quantity = 10; byte[] requestArray = null; using (MemoryStream memory = new MemoryStream()) { memory.WriteByte((byte)(transport >> 8)); memory.WriteByte((byte)transport); memory.WriteByte((byte)(protocol >> 8)); memory.WriteByte((byte)protocol); memory.WriteByte(function); memory.WriteByte((byte)(length >> 8)); memory.WriteByte((byte)length); memory.WriteByte((byte)(start >> 8)); memory.WriteByte((byte)start); memory.WriteByte((byte)(quantity >> 8)); memory.WriteByte((byte)quantity); requestArray = memory.ToArray(); } }當然List<byte> 也是不錯的選擇,在此就不再多描述。
- 情境二:用byte[] + 整數組合 protocol
基本上這就是動態處理陣列
使用MemoryStream
public void MyTestMethod3() { byte[] transportArray = new byte[2] { 1, 2 }; ushort protocol = 0; byte function = 1; ushort length = 6; ushort start = 0; ushort quantity = 10; byte[] requestArray = null; using (MemoryStream memory = new MemoryStream()) { memory.Write(transportArray, 0, transportArray.Length); memory.WriteByte((byte)(protocol >> 8)); memory.WriteByte((byte)protocol); memory.WriteByte(function); memory.WriteByte((byte)(length >> 8)); memory.WriteByte((byte)length); memory.WriteByte((byte)(start >> 8)); memory.WriteByte((byte)start); memory.WriteByte((byte)(quantity >> 8)); memory.WriteByte((byte)quantity); requestArray = memory.ToArray(); } }當然List<byte> 也是不錯的選擇,在此就不再多描述。
還有一個蠻常見的方式就是Array.Copy,不過不太適合在這個情境裡,程式碼會變得又臭又長。
- 情境三:用 16 進制字串組合 protocol
使用 Convert.ToByte
[TestMethod()]
public void MyTestMethod5()
{
var request = "00 00 00 00 00 06 01 01 00 00 00 0A".Replace(" ", "");
var requestArray = Enumerable.Range(0, request.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(request.Substring(x, 2), 16))
.ToArray();
}更多進制轉換可參考
http://www.dotblogs.com.tw/yc421206/archive/2008/11/15/5992.aspx
http://www.dotblogs.com.tw/yc421206/archive/2008/10/27/5790.aspx
http://www.dotblogs.com.tw/yc421206/archive/2008/11/15/5993.aspx
若通訊格式是吃ACSII,可以使用 Encoding.ASCII.GetByte() 方法處理
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET