- 1. 引言
-
2. 優(yōu)化過程
- 2.1. 進(jìn)程對象定義與初步分析
- 2.2. 排除Json序列化
- 2.3. 使用BinaryWriter進(jìn)行二進(jìn)制序列化
- 2.4. 數(shù)據(jù)類型調(diào)整
- 2.5. 再次數(shù)據(jù)類型調(diào)整與位域優(yōu)化
- 3. 優(yōu)化效果與總結(jié)
1. 引言
在操作系統(tǒng)中,進(jìn)程信息對于系統(tǒng)監(jiān)控和性能分析至關(guān)重要。假設(shè)我們需要開發(fā)一個(gè)監(jiān)控程序,該程序能夠捕獲當(dāng)前操作系統(tǒng)的進(jìn)程信息,并將其高效地傳輸?shù)狡渌耍ㄈ绶?wù)端或監(jiān)控端)。在這個(gè)過程中,如何將捕獲到的進(jìn)程對象轉(zhuǎn)換為二進(jìn)制數(shù)據(jù),并進(jìn)行優(yōu)化,以減小數(shù)據(jù)包的大小,成為了一個(gè)關(guān)鍵問題。本文將通過逐步分析,探討如何使用位域技術(shù)對C#對象進(jìn)行二進(jìn)制序列化優(yōu)化。
首先,我們給出了一個(gè)進(jìn)程對象的字段定義示例。為了通過網(wǎng)絡(luò)(TCP/UDP)傳輸該對象,我們需要將其轉(zhuǎn)換為二進(jìn)制格式。在這個(gè)過程中,如何做到最小的數(shù)據(jù)包大小是一個(gè)挑戰(zhàn)。
字段名 | 說明 | 示例 |
---|---|---|
PID | 進(jìn)程ID | 10565 |
Name | 進(jìn)程名稱 | 碼界工坊 |
Publisher | 發(fā)布者 | 沙漠盡頭的狼 |
CommandLine | 命令行 | dotnet CodeWF.Tools.dll |
CPU | CPU(所有內(nèi)核的總處理利用率) | 2.3% |
Memory | 內(nèi)存(進(jìn)程占用的物理內(nèi)存) | 0.1% |
Disk | 磁盤(所有物理驅(qū)動器的總利用率) | 0.1 MB/秒 |
Network | 網(wǎng)絡(luò)(當(dāng)前主要網(wǎng)絡(luò)上的網(wǎng)絡(luò)利用率 | 0 Mbps |
GPU | GPU(所有GPU引擎的最高利用率) | 2.2% |
GPUEngine | GPU引擎 | GPU 0 - 3D |
PowerUsage | 電源使用情況(CPU、磁盤和GPU對功耗的影響) | 低 |
PowerUsageTrend | 電源使用情況趨勢(一段時(shí)間內(nèi)CPU、磁盤和GPU對功耗的影響) | 非常低 |
Type | 進(jìn)程類型 | 應(yīng)用 |
Status | 進(jìn)程狀態(tài) | 效率模式 |
2. 優(yōu)化過程
2.1. 進(jìn)程對象定義與初步分析
我們根據(jù)字段的示例值確定了每個(gè)字段的數(shù)據(jù)類型。
字段名 | 數(shù)據(jù)類型 | 說明 | 示例 |
---|---|---|---|
PID | int | 進(jìn)程ID | 10565 |
Name | string? | 進(jìn)程名稱 | 碼界工坊 |
Publisher | string? | 發(fā)布者 | 沙漠盡頭的狼 |
CommandLine | string? | 命令行 | dotnet CodeWF.Tools.dll |
CPU | string? | CPU(所有內(nèi)核的總處理利用率) | 2.3% |
Memory | string? | 內(nèi)存(進(jìn)程占用的物理內(nèi)存) | 0.1% |
Disk | string? | 磁盤(所有物理驅(qū)動器的總利用率) | 0.1 MB/秒 |
Network | string? | 網(wǎng)絡(luò)(當(dāng)前主要網(wǎng)絡(luò)上的網(wǎng)絡(luò)利用率 | 0 Mbps |
GPU | string? | GPU(所有GPU引擎的最高利用率) | 2.2% |
GPUEngine | string? | GPU引擎 | GPU 0 - 3D |
PowerUsage | string? | 電源使用情況(CPU、磁盤和GPU對功耗的影響) | 低 |
PowerUsageTrend | string? | 電源使用情況趨勢(一段時(shí)間內(nèi)CPU、磁盤和GPU對功耗的影響) | 非常低 |
Type | string? | 進(jìn)程類型 | 應(yīng)用 |
Status | string? | 進(jìn)程狀態(tài) | 效率模式 |
創(chuàng)建一個(gè)C#類SystemProcess
表示進(jìn)程信息:
public class SystemProcess
{
public int PID { get; set; }
public string? Name { get; set; }
public string? Publisher { get; set; }
public string? CommandLine { get; set; }
public string? CPU { get; set; }
public string? Memory { get; set; }
public string? Disk { get; set; }
public string? Network { get; set; }
public string? GPU { get; set; }
public string? GPUEngine { get; set; }
public string? PowerUsage { get; set; }
public string? PowerUsageTrend { get; set; }
public string? Type { get; set; }
public string? Status { get; set; }
}
定義測試數(shù)據(jù)
private SystemProcess _codeWFObject = new SystemProcess()
{
PID = 10565,
Name = "碼界工坊",
Publisher = "沙漠盡頭的狼",
CommandLine = "dotnet CodeWF.Tools.dll",
CPU = "2.3%",
Memory = "0.1%",
Disk = "0.1 MB/秒",
Network = "0 Mbps",
GPU = "2.2%",
GPUEngine = "GPU 0 - 3D",
PowerUsage = "低",
PowerUsageTrend = "非常低",
Type = "應(yīng)用",
Status = "效率模式"
};
2.2. 排除Json序列化
將對象轉(zhuǎn)為Json字段串,這在Web開發(fā)是最常見的,因?yàn)楹啙崳昂蠖硕挤奖闾幚恚?/p>
public class SysteProcessUnitTest
{
private readonly ITestOutputHelper _testOutputHelper;
private SystemProcess _codeWFObject // 前面已給出定義,這里省
public SysteProcessUnitTest(ITestOutputHelper testOutputHelper)
{
_testOutputHelper = testOutputHelper;
}
/// <summary>
/// Json序列化大小測試
/// </summary>
[Fact]
public void Test_SerializeJsonData_Success()
{
var jsonData = JsonSerializer.Serialize(_codeWFObject);
_testOutputHelper.WriteLine($"Json長度:{jsonData.Length}");
var jsonDataBytes = Encoding.UTF8.GetBytes(jsonData);
_testOutputHelper.WriteLine($"json二進(jìn)制長度:{jsonDataBytes.Length}");
}
}
標(biāo)準(zhǔn)輸出:?
Json長度:366
json二進(jìn)制長度:366
盡管Json序列化在Web開發(fā)中非常流行,因?yàn)樗啙嵡乙子谔幚恚赥CP/UDP網(wǎng)絡(luò)傳輸中,Json序列化可能導(dǎo)致不必要的數(shù)據(jù)包大小增加。因此,我們排除了Json序列化,并尋找其他更高效的二進(jìn)制序列化方法。
{"PID":10565,"Name":"\u7801\u754C\u5DE5\u574A","Publisher":"\u6C99\u6F20\u5C3D\u5934\u7684\u72FC","CommandLine":"dotnet CodeWF.Tools.dll","CPU":"2.3%","Memory":"0.1%","Disk":"0.1 MB/\u79D2","Network":"0 Mbps","GPU":"2.2%","GPUEngine":"GPU 0 - 3D","PowerUsage":"\u4F4E","PowerUsageTrend":"\u975E\u5E38\u4F4E","Type":"\u5E94\u7528","Status":"\u6548\u7387\u6A21\u5F0F"}
2.3. 使用BinaryWriter進(jìn)行二進(jìn)制序列化
使用站長前面一篇文章寫的二進(jìn)制序列化幫助類SerializeHelper
轉(zhuǎn)換,該類使用BinaryWriter
將對象轉(zhuǎn)換為二進(jìn)制數(shù)據(jù)。
首先,我們使SystemProcess
類實(shí)現(xiàn)了一個(gè)空接口INetObject
,并在類上添加了NetHeadAttribute
特性。
/// <summary>
/// 網(wǎng)絡(luò)對象序列化接口
/// </summary>
public interface INetObject
{
}
[NetHead(1, 1)]
public class SystemProcess : INetObject
{
// 省略字段定義
}
然后,我們編寫了一個(gè)測試方法來驗(yàn)證序列化和反序列化的正確性,并打印了序列化后的二進(jìn)制數(shù)據(jù)長度。
/// <summary>
/// 二進(jìn)制序列化測試
/// </summary>
[Fact]
public void Test_SerializeToBytes_Success()
{
var buffer = SerializeHelper.SerializeByNative(_codeWFObject, 1);
_testOutputHelper.WriteLine($"序列化后二進(jìn)制長度:{buffer.Length}");
var deserializeObj = SerializeHelper.DeserializeByNative<SystemProcess>(buffer);
Assert.Equal("碼界工坊", deserializeObj.Name);
}
標(biāo)準(zhǔn)輸出:?
序列化后二進(jìn)制長度:152
比Json體積小了一半多(366到152),上面單元測試也測試了數(shù)據(jù)反序列化后驗(yàn)證數(shù)據(jù)是否正確,我們就以這個(gè)基礎(chǔ)繼續(xù)優(yōu)化。
2.4. 數(shù)據(jù)類型調(diào)整
為了進(jìn)一步優(yōu)化二進(jìn)制數(shù)據(jù)的大小,我們對數(shù)據(jù)類型進(jìn)行了調(diào)整。通過對進(jìn)程數(shù)據(jù)示例的分析,我們發(fā)現(xiàn)一些字段的數(shù)據(jù)類型可以更加緊湊地表示。例如,CPU利用率可以只傳遞數(shù)字部分(如2.3),而不需要傳遞百分號。這種調(diào)整可以減小數(shù)據(jù)包的大小。
字段名 | 數(shù)據(jù)類型 | 說明 | 示例 |
---|---|---|---|
PID | int | 進(jìn)程ID | 10565 |
Name | string? | 進(jìn)程名稱 | 碼界工坊 |
Publisher | string? | 發(fā)布者 | 沙漠盡頭的狼 |
CommandLine | string? | 命令行 | dotnet CodeWF.Tools.dll |
CPU | float | CPU(所有內(nèi)核的總處理利用率) | 2.3 |
Memory | float | 內(nèi)存(進(jìn)程占用的物理內(nèi)存) | 0.1 |
Disk | float | 磁盤(所有物理驅(qū)動器的總利用率) | 0.1 |
Network | float | 網(wǎng)絡(luò)(當(dāng)前主要網(wǎng)絡(luò)上的網(wǎng)絡(luò)利用率 | 0 |
GPU | float | GPU(所有GPU引擎的最高利用率) | 2.2 |
GPUEngine | byte | GPU引擎,0:無,1:GPU 0 - 3D | 1 |
PowerUsage | byte | 電源使用情況(CPU、磁盤和GPU對功耗的影響),0:非常低,1:低,2:中,3:高,4:非常高 | 1 |
PowerUsageTrend | byte | 電源使用情況趨勢(一段時(shí)間內(nèi)CPU、磁盤和GPU對功耗的影響),0:非常低,1:低,2:中,3:高,4:非常高 | 0 |
Type | byte | 進(jìn)程類型,0:應(yīng)用,1:后臺進(jìn)程 | 0 |
Status | byte | 進(jìn)程狀態(tài),0:正常運(yùn)行,1:效率模式,2:掛起 | 1 |
修改測試數(shù)據(jù)定義:
[NetHead(1, 2)]
public class SystemProcess2 : INetObject
{
public int PID { get; set; }
public string? Name { get; set; }
public string? Publisher { get; set; }
public string? CommandLine { get; set; }
public float CPU { get; set; }
public float Memory { get; set; }
public float Disk { get; set; }
public float Network { get; set; }
public float GPU { get; set; }
public byte GPUEngine { get; set; }
public byte PowerUsage { get; set; }
public byte PowerUsageTrend { get; set; }
public byte Type { get; set; }
public byte Status { get; set; }
}
/// <summary>
/// 普通優(yōu)化字段數(shù)據(jù)類型
/// </summary>
private SystemProcess2 _codeWFObject2 = new SystemProcess2()
{
PID = 10565,
Name = "碼界工坊",
Publisher = "沙漠盡頭的狼",
CommandLine = "dotnet CodeWF.Tools.dll",
CPU = 2.3f,
Memory = 0.1f,
Disk = 0.1f,
Network = 0,
GPU = 2.2f,
GPUEngine = 1,
PowerUsage = 1,
PowerUsageTrend = 0,
Type = 0,
Status = 1
};
添加單元測試如下:
/// <summary>
/// 二進(jìn)制序列化測試
/// </summary>
[Fact]
public void Test_SerializeToBytes2_Success()
{
var buffer = SerializeHelper.SerializeByNative(_codeWFObject2, 1);
_testOutputHelper.WriteLine($"序列化后二進(jìn)制長度:{buffer.Length}");
var deserializeObj = SerializeHelper.DeserializeByNative<SystemProcess2>(buffer);
Assert.Equal("碼界工坊", deserializeObj.Name);
Assert.Equal(2.2f, deserializeObj.GPU);
}
測試結(jié)果:
標(biāo)準(zhǔn)輸出:?
序列化后二進(jìn)制長度:99
又優(yōu)化了50%左右(152到99),爽不爽?繼續(xù),還有更爽的。
2.5. 再次數(shù)據(jù)類型調(diào)整與位域優(yōu)化
更進(jìn)一步地,我們引入了位域技術(shù)。位域允許我們更加精細(xì)地控制字段在內(nèi)存中的布局,從而進(jìn)一步減小二進(jìn)制數(shù)據(jù)的大小。我們重新定義了字段規(guī)則,并使用位域來表示一些枚舉值字段。通過這種方式,我們能夠顯著地減小數(shù)據(jù)包的大小。
看前面一張表,部分字段只是一些枚舉值,使用的byte
表示,即8位(bit),其中比如進(jìn)程類型只有2個(gè)狀態(tài)(0:應(yīng)用,1:后臺進(jìn)程),正好可以用1位即表示;像電源使用情況,無非就是5個(gè)狀態(tài),用3位可表示全,按這個(gè)規(guī)則我們重新定義字段規(guī)則如下:
字段名 | 數(shù)據(jù)類型 | 說明 | 示例 |
---|---|---|---|
PID | int | 進(jìn)程ID | 10565 |
Name | string? | 進(jìn)程名稱 | 碼界工坊 |
Publisher | string? | 發(fā)布者 | 沙漠盡頭的狼 |
CommandLine | string? | 命令行 | dotnet CodeWF.Tools.dll |
Data | byte[8] | 固定大小的幾個(gè)字段,見下表定義 |
固定字段(Data)的詳細(xì)說明如下:
字段名 | Offset | Size | 說明 | 示例 |
---|---|---|---|---|
CPU | 0 | 10 | CPU(所有內(nèi)核的總處理利用率),最后一位表示小數(shù)位,比如23表示2.3% | 23 |
Memory | 10 | 10 | 內(nèi)存(進(jìn)程占用的物理內(nèi)存),最后一位表示小數(shù)位,比如1表示0.1%,值可根據(jù)基本信息計(jì)算 | 1 |
Disk | 20 | 10 | 磁盤(所有物理驅(qū)動器的總利用率),最后一位表示小數(shù)位,比如1表示0.1%,值可根據(jù)基本信息計(jì)算 | 1 |
Network | 30 | 10 | 網(wǎng)絡(luò)(當(dāng)前主要網(wǎng)絡(luò)上的網(wǎng)絡(luò)利用率),最后一位表示小數(shù)位,比如253表示25.3%,值可根據(jù)基本信息計(jì)算 | 0 |
GPU | 40 | 10 | GPU(所有GPU引擎的最高利用率),最后一位表示小數(shù)位,比如253表示25.3 | 22 |
GPUEngine | 50 | 1 | GPU引擎,0:無,1:GPU 0 - 3D | 1 |
PowerUsage | 51 | 3 | 電源使用情況(CPU、磁盤和GPU對功耗的影響),0:非常低,1:低,2:中,3:高,4:非常高 | 1 |
PowerUsageTrend | 54 | 3 | 電源使用情況趨勢(一段時(shí)間內(nèi)CPU、磁盤和GPU對功耗的影響),0:非常低,1:低,2:中,3:高,4:非常高 | 0 |
Type | 57 | 1 | 進(jìn)程類型,0:應(yīng)用,1:后臺進(jìn)程 | 0 |
Status | 58 | 2 | 進(jìn)程狀態(tài),0:正常運(yùn)行,1:效率模式,2:掛起 | 1 |
上面這張表是位域規(guī)則表,Offset表示字段在Data字節(jié)數(shù)組中的位置(以bit為單位計(jì)算),Size表示字段在Data中占有的大小(同樣以bit單位計(jì)算),如Memory字段,在Data字節(jié)數(shù)組中,占據(jù)10到20位的空間。
修改類定義如下,注意看代碼中的注釋:
[NetHead(1, 3)]
public class SystemProcess3 : INetObject
{
public int PID { get; set; }
public string? Name { get; set; }
public string? Publisher { get; set; }
public string? CommandLine { get; set; }
private byte[]? _data;
/// <summary>
/// 序列化,這是實(shí)際需要序列化的數(shù)據(jù)
/// </summary>
public byte[]? Data
{
get => _data;
set
{
_data = value;
// 這是關(guān)鍵:在反序列化將byte轉(zhuǎn)換為對象,方便程序中使用
_processData = _data?.ToFieldObject<SystemProcessData>();
}
}
private SystemProcessData? _processData;
/// <summary>
/// 進(jìn)程數(shù)據(jù),添加NetIgnoreMember在序列化會忽略
/// </summary>
[NetIgnoreMember]
public SystemProcessData? ProcessData
{
get => _processData;
set
{
_processData = value;
// 這里關(guān)鍵:將對象轉(zhuǎn)換為位域
_data = _processData?.FieldObjectBuffer();
}
}
}
public record SystemProcessData
{
[NetFieldOffset(0, 10)] public short CPU { get; set; }
[NetFieldOffset(10, 10)] public short Memory { get; set; }
[NetFieldOffset(20, 10)] public short Disk { get; set; }
[NetFieldOffset(30, 10)] public short Network { get; set; }
[NetFieldOffset(40, 10)] public short GPU { get; set; }
[NetFieldOffset(50, 1)] public byte GPUEngine { get; set; }
[NetFieldOffset(51, 3)] public byte PowerUsage { get; set; }
[NetFieldOffset(54, 3)] public byte PowerUsageTrend { get; set; }
[NetFieldOffset(57, 1)] public byte Type { get; set; }
[NetFieldOffset(58, 2)] public byte Status { get; set; }
}
添加單元測試如下:
/// <summary>
/// 極限優(yōu)化字段數(shù)據(jù)類型
/// </summary>
private SystemProcess3 _codeWFObject3 = new SystemProcess3()
{
PID = 10565,
Name = "碼界工坊",
Publisher = "沙漠盡頭的狼",
CommandLine = "dotnet CodeWF.Tools.dll",
ProcessData = new SystemProcessData()
{
CPU = 23,
Memory = 1,
Disk = 1,
Network = 0,
GPU = 22,
GPUEngine = 1,
PowerUsage = 1,
PowerUsageTrend = 0,
Type = 0,
Status = 1
}
};
/// <summary>
/// 二進(jìn)制極限序列化測試
/// </summary>
[Fact]
public void Test_SerializeToBytes3_Success()
{
var buffer = SerializeHelper.SerializeByNative(_codeWFObject3, 1);
_testOutputHelper.WriteLine($"序列化后二進(jìn)制長度:{buffer.Length}");
var deserializeObj = SerializeHelper.DeserializeByNative<SystemProcess3>(buffer);
Assert.Equal("碼界工坊", deserializeObj.Name);
Assert.Equal(23, deserializeObj.ProcessData.CPU);
Assert.Equal(1, deserializeObj.ProcessData.PowerUsage);
}
測試輸出:
標(biāo)準(zhǔn)輸出:?
序列化后二進(jìn)制長度:86
99又優(yōu)化到86個(gè)字節(jié),13個(gè)字節(jié)哦,有極限網(wǎng)絡(luò)環(huán)境下非??捎^,比如100萬數(shù)據(jù),那不就是12.4MB了?關(guān)于位域序列化和反序列的代碼這里不細(xì)說了,很枯燥,站長可能也說不清楚,代碼長這樣:
public partial class SerializeHelper
{
public static byte[] FieldObjectBuffer<T>(this T obj) where T : class
{
var properties = typeof(T).GetProperties();
var totalSize = 0;
// 計(jì)算總的bit長度
foreach (var property in properties)
{
if (!Attribute.IsDefined(property, typeof(NetFieldOffsetAttribute)))
{
continue;
}
var offsetAttribute =
(NetFieldOffsetAttribute)property.GetCustomAttribute(typeof(NetFieldOffsetAttribute))!;
totalSize = Math.Max(totalSize, offsetAttribute.Offset + offsetAttribute.Size);
}
var bufferLength = (int)Math.Ceiling((double)totalSize / 8);
var buffer = new byte[bufferLength];
foreach (var property in properties)
{
if (!Attribute.IsDefined(property, typeof(NetFieldOffsetAttribute)))
{
continue;
}
var offsetAttribute =
(NetFieldOffsetAttribute)property.GetCustomAttribute(typeof(NetFieldOffsetAttribute))!;
dynamic value = property.GetValue(obj)!; // 使用dynamic類型動態(tài)獲取屬性值
SetBitValue(ref buffer, value, offsetAttribute.Offset, offsetAttribute.Size);
}
return buffer;
}
public static T ToFieldObject<T>(this byte[] buffer) where T : class, new()
{
var obj = new T();
var properties = typeof(T).GetProperties();
foreach (var property in properties)
{
if (!Attribute.IsDefined(property, typeof(NetFieldOffsetAttribute)))
{
continue;
}
var offsetAttribute =
(NetFieldOffsetAttribute)property.GetCustomAttribute(typeof(NetFieldOffsetAttribute))!;
dynamic value = GetValueFromBit(buffer, offsetAttribute.Offset, offsetAttribute.Size,
property.PropertyType);
property.SetValue(obj, value);
}
return obj;
}
/// <summary>
/// 將值按位寫入buffer
/// </summary>
/// <param name="buffer"></param>
/// <param name="value"></param>
/// <param name="offset"></param>
/// <param name="size"></param>
private static void SetBitValue(ref byte[] buffer, int value, int offset, int size)
{
var mask = (1 << size) - 1;
buffer[offset / 8] |= (byte)((value & mask) << (offset % 8));
if (offset % 8 + size > 8)
{
buffer[offset / 8 + 1] |= (byte)((value & mask) >> (8 - offset % 8));
}
}
/// <summary>
/// 從buffer中按位讀取值
/// </summary>
/// <param name="buffer"></param>
/// <param name="offset"></param>
/// <param name="size"></param>
/// <param name="propertyType"></param>
/// <returns></returns>
private static dynamic GetValueFromBit(byte[] buffer, int offset, int size, Type propertyType)
{
var mask = (1 << size) - 1;
var bitValue = (buffer[offset / 8] >> (offset % 8)) & mask;
if (offset % 8 + size > 8)
{
bitValue |= (buffer[offset / 8 + 1] << (8 - offset % 8)) & mask;
}
dynamic result = Convert.ChangeType(bitValue, propertyType); // 根據(jù)屬性類型進(jìn)行轉(zhuǎn)換
return result;
}
}
3. 優(yōu)化效果與總結(jié)
通過逐步優(yōu)化,我們從最初的Json序列化366字節(jié)減小到了使用普通二進(jìn)制序列化的152字節(jié),再進(jìn)一步使用位域技術(shù)優(yōu)化到了86字節(jié)。這種優(yōu)化在網(wǎng)絡(luò)傳輸中是非??捎^的,尤其是在需要傳輸大量數(shù)據(jù)的情況下。
本文通過一個(gè)示例案例,探討了C#對象二進(jìn)制序列化的優(yōu)化方法。通過使用位域技術(shù),我們實(shí)現(xiàn)了對數(shù)據(jù)包大小的極限壓縮,提高了網(wǎng)絡(luò)傳輸?shù)男?。這對于開發(fā)C/S程序來說是一種樂趣,也是追求極致性能的一種體現(xiàn)。
最后,我們提供了本文測試源碼的Github鏈接,供讀者參考和學(xué)習(xí)。文章來源:http://www.zghlxwxcb.cn/news/detail-815917.html
- https://github.com/dotnet9/CsharpSocketTest
彩蛋:該倉庫有上篇《C#百萬對象序列化深度剖析:如何在網(wǎng)絡(luò)傳輸中實(shí)現(xiàn)速度與體積的完美平衡 (dotnet9.com)》案例代碼,也附帶了TCP、UDP服務(wù)端與客戶端聯(lián)調(diào)測試程序哦。文章來源地址http://www.zghlxwxcb.cn/news/detail-815917.html
到了這里,關(guān)于C#對象二進(jìn)制序列化優(yōu)化:位域技術(shù)實(shí)現(xiàn)極限壓縮的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!