在编写网络应用的时候数据缓冲区是应该比较常用的方式,主要用构建一个内存区用于存储发送的数据和接收的数据;为了更好的利用已有数据缓冲区所以构造一个缓冲池来存放相关数据方便不同连接更好地利用缓冲区,节省不停的构造新的缓冲区所带的损耗问题。
缓冲区
其实构造一个缓冲区非常简单,根据需分本相关大小的byte数组即可;既然是用于存放数据那就自然要实现读和写方法,看一下具体实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
public
class
DataBuffer : IDisposable
{
public
byte
[] Data;
private
int
mLength;
private
int
mPostion = 0;
internal
int
mCount = 0;
public
DataBuffer(
byte
[] data)
{
Data = data;
mLength = data.Length;
mPostion = 0;
mCount = data.Length;
}
public
DataBuffer(
int
length)
{
mLength = length;
Data =
new
byte
[length];
}
public
void
From(Array source,
int
index,
int
count)
{
Array.Copy(source, index, Data, 0, count);
mPostion = 0;
mCount = count;
}
public
int
Write(
byte
[] data)
{
return
Write(data, 0);
}
public
int
Write(
byte
[] data,
int
index)
{
int
count = 0;
if
(mPostion + (data.Length-index) > mLength)
{
count = mLength - mPostion;
}
else
{
count = data.Length - index;
}
if
(count > 0)
{
Array.Copy(data, index, Data, mPostion, count);
mPostion += count;
mCount += count;
}
return
count;
}
public
ArraySegment<
byte
> Read(
int
count)
{
int
end = count;
if
(mPostion + count > mCount)
end = mCount - mPostion;
ArraySegment<
byte
> result=
new
ArraySegment<
byte
>(Data, mPostion, end);
mPostion += end;
return
result;
}
public
void
Seek()
{
Seek(0);
}
public
void
Seek(
int
postion)
{
mPostion = 0;
}
public
ArraySegment<
byte
> GetSegment()
{
return
new
ArraySegment<
byte
>(Data, 0, mCount);
}
internal
BufferPool Pool
{
get
;
set
;
}
public
void
Dispose()
{
if
(Pool !=
null
)
{
mPostion = 0;
mCount = 0;
Pool.Push(
this
);
}
}
}
|
为了方便使用,Buffer实现了IDisposable接口,其作为就是当释放的时候把Buffer放回到Pool里.
Buffer提供了两个方法分别是Write和Read用于写和读数据,由于缓冲区有大小限制,所以在写的时候会返回一个成功写入的数量;而read则返回一个ArraySegment<byte>用于描述其位置。为什么要这样做呢,其实有些情况一个数据成员会被写入到不同的缓冲区,当读出来的时候就会存要在多个缓冲区中获取。
缓冲池
缓冲池用于发放和回收级冲区,实现一个重用的目的。池的实现并不复杂,封装一个简单的队列操作即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
public
class
BufferPool : IDisposable
{
private
static
List<BufferPool> mPools =
new
List<BufferPool>();
private
static
int
mIndex = 0;
public
static
void
Setup(
int
pools,
int
buffers)
{
Setup(pools, buffers, 2048);
}
public
static
void
Setup(
int
pools,
int
buffers,
int
bufferlength)
{
lock
(mPools)
{
for
(
int
i = 0; i < pools; i++)
{
mPools.Add(
new
BufferPool(buffers, bufferlength));
}
}
}
public
static
void
Clean()
{
lock
(mPools)
{
foreach
(BufferPool item
in
mPools)
{
item.Dispose();
}
mPools.Clear();
}
}
public
static
BufferPool GetPool()
{
lock
(mPools)
{
if
(mIndex == mPools.Count)
{
mIndex = 0;
}
return
mPools[mIndex];
}
}
Queue<DataBuffer> mBuffers;
private
int
mBufferLength;
public
BufferPool(
int
count,
int
bufferlength)
{
mBufferLength = bufferlength;
mBuffers =
new
Queue<DataBuffer>(count);
for
(
int
i = 0; i < count; i++)
{
mBuffers.Enqueue(createBuffer(bufferlength));
}
}
private
DataBuffer createBuffer(
int
length)
{
DataBuffer item =
new
DataBuffer(length);
item.Pool =
this
;
return
item;
}
public
DataBuffer Pop()
{
lock
(mBuffers)
{
return
mBuffers.Count > 0 ? mBuffers.Dequeue() : createBuffer(mBufferLength);
}
}
public
void
Push(DataBuffer buffer)
{
lock
(mBuffers)
{
mBuffers.Enqueue(buffer);
}
}
private
bool
mDisposed =
false
;
private
void
OnDispose()
{
lock
(mBuffers)
{
while
(mBuffers.Count > 0)
{
mBuffers.Dequeue().Pool =
null
;
}
}
}
public
void
Dispose()
{
lock
(
this
)
{
if
(!mDisposed)
{
OnDispose();
mDisposed =
true
;
}
}
}
}
|
BufferPool实现了几个静态方法
Setup
主要目的是用于构造多个缓冲池,缓冲区数量和缓冲区大小。为什么会考虑多个池呢,主要原因是在高并发的来分配处理减低池的负载。
Clean
用于清除释放缓冲池
GetPool
平均地分发缓冲池给使用者
一个简单的数据缓冲区和数据缓冲池已经实现了,在后面的文章里会讲述如何构造BufferWriter和BufferReader,根据对象的需要把信息分别写入多个缓冲区和在多个缓冲区中读取信息还原对象。