在編寫網絡應用的時候數據緩沖區是應該比較常用的方式,主要用構建一個內存區用於存儲發送的數據和接收的數據;為了更好的利用已有數據緩沖區所以構造一個緩沖池來存放相關數據方便不同連接更好地利用緩沖區,節省不停的構造新的緩沖區所帶的損耗問題。
緩沖區
其實構造一個緩沖區非常簡單,根據需分本相關大小的byte數組即可;既然是用於存放數據那就自然要實現讀和寫方法,看一下具體實現
01
public class DataBuffer : IDisposable
02
{
03
public byte[] Data;
04
private int mLength;
05
private int mPostion = 0;
06
internal int mCount = 0;
07
08
public DataBuffer(byte[] data)
09
{
10
Data = data;
11
mLength = data.Length;
12
mPostion = 0;
13
mCount = data.Length;
14
}
15
16
public DataBuffer(int length)
17
{
18
mLength = length;
19
Data = new byte[length];
20
}
21
public void From(Array source, int index, int count)
22
{
23
Array.Copy(source, index, Data, 0, count);
24
mPostion = 0;
25
mCount = count;
26
}
27
public int Write(byte[] data)
28
{
29
return Write(data, 0);
30
}
31
public int Write(byte[] data, int index)
32
{
33
int count = 0;
34
if (mPostion + (data.Length-index) > mLength)
35
{
36
count = mLength - mPostion;
37
}
38
else
39
{
40
count = data.Length - index;
41
}
42
if (count > 0)
43
{
44
Array.Copy(data, index, Data, mPostion, count);
45
46
mPostion += count;
47
mCount += count;
48
}
49
return count;
50
}
51
public ArraySegment<byte> Read(int count)
52
{
53
int end = count;
54
if (mPostion + count > mCount)
55
end = mCount - mPostion;
56
57
ArraySegment<byte> result= new ArraySegment<byte>(Data, mPostion, end);
58
mPostion += end;
59
return result;
60
}
61
public void Seek()
62
{
63
Seek(0);
64
}
65
public void Seek(int postion)
66
{
67
mPostion = 0;
68
}
69
public ArraySegment<byte> GetSegment()
70
{
71
return new ArraySegment<byte>(Data, 0, mCount);
72
}
73
internal BufferPool Pool
74
{
75
get;
76
set;
77
}
78
public void Dispose()
79
{
80
if (Pool != null)
81
{
82
mPostion = 0;
83
mCount = 0;
84
Pool.Push(this);
85
}
86
}
87
}
為了方便使用,Buffer實現了IDisposable接口,其作為就是當釋放的時候把Buffer放回到Pool裡.
Buffer提供了兩個方法分別是Write和Read用於寫和讀數據,由於緩沖區有大小限制,所以在寫的時候會返回一個成功寫入的數量;而read則返回一個ArraySegment<byte>用於描述其位置。為什麼要這樣做呢,其實有些情況一個數據成員會被寫入到不同的緩沖區,當讀出來的時候就會存要在多個緩沖區中獲取。
緩沖池
緩沖池用於發放和回收級沖區,實現一個重用的目的。池的實現並不復雜,封裝一個簡單的隊列操作即可。
01
public class BufferPool : IDisposable
02
{
03
private static List<BufferPool> mPools = new List<BufferPool>();
04
private static int mIndex = 0;
05
public static void Setup(int pools, int buffers)
06
{
07
Setup(pools, buffers, 2048);
08
}
09
public static void Setup(int pools, int buffers, int bufferlength)
10
{
11
lock (mPools)
12
{
13
for (int i = 0; i < pools; i++)
14
{
15
mPools.Add(new BufferPool(buffers, bufferlength));
16
}
17
}
18
}
19
public static void Clean()
20
{
21
lock (mPools)
22
{
23
foreach (BufferPool item in mPools)
24
{
25
item.Dispose();
26
}
27
mPools.Clear();
28
}
29
}
30
public static BufferPool GetPool()
31
{
32
lock (mPools)
33
{
34
if (mIndex == mPools.Count)
35
{
36
mIndex = 0;
37
}
38
return mPools[mIndex];
39
}
40
}
41
Queue<DataBuffer> mBuffers;
42
private int mBufferLength;
43
public BufferPool(int count, int bufferlength)
44
{
45
mBufferLength = bufferlength;
46
mBuffers = new Queue<DataBuffer>(count);
47
for (int i = 0; i < count; i++)
48
{
49
mBuffers.Enqueue(createBuffer(bufferlength));
50
}
51
}
52
private DataBuffer createBuffer(int length)
53
{
54
DataBuffer item = new DataBuffer(length);
55
item.Pool = this;
56
return item;
57
}
58
public DataBuffer Pop()
59
{
60
lock (mBuffers)
61
{
62
return mBuffers.Count > 0 ? mBuffers.Dequeue() : createBuffer(mBufferLength);
63
}
64
}
65
public void Push(DataBuffer buffer)
66
{
67
lock (mBuffers)
68
{
69
mBuffers.Enqueue(buffer);
70
}
71
}
72
private bool mDisposed = false;
73
private void OnDispose()
74
{
75
lock (mBuffers)
76
{
77
while (mBuffers.Count > 0)
78
{
79
mBuffers.Dequeue().Pool = null;
80
}
81
}
82
}
83
public void Dispose()
84
{
85
lock (this)
86
{
87
if (!mDisposed)
88
{
89
OnDispose();
90
mDisposed = true;
91
}
92
}
93
}
94
}
BufferPool實現了幾個靜態方法
Setup
主要目的是用於構造多個緩沖池,緩沖區數量和緩沖區大小。為什麼會考慮多個池呢,主要原因是在高並發的來分配處理減低池的負載。
Clean
用於清除釋放緩沖池
GetPool
平均地分發緩沖池給使用者
一個簡單的數據緩沖區和數據緩沖池已經實現了,在後面的文章裡會講述如何構造BufferWriter和BufferReader,根據對象的需要把信息分別寫入多個緩沖區和在多個緩沖區中讀取信息還原對象。
摘自 smark