Beetle在Tcp通讯中使用Protobuf
来源:互联网 发布:mac图片编辑大小 编辑:程序博客网 时间:2024/05/18 02:14
smark
Beetle可靠、高性能的.Net Socket Tcp通讯组件 支持flash amf3,protobuf,Silverlight,windows phone
Beetle在Tcp通讯中使用Protobuf
Protobuf是google制定的一种对象序列化格式,而在.net下的实现有protobuf-net.而protobuf-net在序列化方面有着出色的性能,效率是.net二进制序列化几倍,而序列化后所占的空间也少于.net二进制序列化;除了以上两个优势外Protobuf有着一个更大的优势就是和其他平台交互的兼容性,在现有大部分流行的语言平台中基本都有Protobuf的实现.因此采用protobuf进行对象序列化是个不错的选择.接下来详细讲解Beetle实现对protobuf-net支持.
定义协议格式
为了保证TCP数据流正确处理,首先要做的事情还是要制定一个处理协议,来保证数据处理的有效性.
数据包同样也是两部分组件,头描述消息总长度,消息体是主内容.由于Protobuf-net序列化的数据交不包括消息类型,所以在协议中必须包括类型名称用于提供给对方实始化对应的类型过行反序列化操作.
实现具体的分析器和消息适配器
协议制定后就可以进行分析器的实现,由于采用头4字节描述大小,所以分析器从HeadSizeOfPackage基础类派生下载重写相关方法即可;完整实现代码如下:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144using
System;
using
System.Collections.Generic;
using
System.Text;
using
Beetle;
namespace
Beetle.Packages
{
public
class
ProtobufPackage : Beetle.HeadSizeOfPackage
{
public
ProtobufPackage()
{
}
public
ProtobufPackage(Beetle.TcpChannel channel)
:
base
(channel)
{
}
protected
override
void
WriteMessageType(IMessage msg, BufferWriter writer)
{
}
public
override
object
WriteCast(
object
message)
{
MessageAdapter ma =
new
MessageAdapter();
ma.Message = message;
return
ma;
}
public
override
object
ReadCast(
object
message)
{
return
((MessageAdapter)message).Message;
}
protected
override
IMessage ReadMessageByType(BufferReader reader,
out
object
typeTag)
{
typeTag =
"ProtobufAdapter"
;
return
new
MessageAdapter();
}
static
Dictionary<
string
, Type> mTypes =
new
Dictionary<
string
, Type>(256);
static
Dictionary<Type,
string
> mNames =
new
Dictionary<Type,
string
>(256);
public
static
void
LoadAssembly()
{
try
{
string
path = AppDomain.CurrentDomain.DynamicDirectory;
LoadAssembly(path);
path = AppDomain.CurrentDomain.BaseDirectory;
LoadAssembly(path);
}
catch
{
}
}
public
static
void
LoadAssembly(
string
path)
{
if
(!
string
.IsNullOrEmpty(path))
{
foreach
(
string
item
in
System.IO.Directory.GetFiles(path,
"*.dll"
))
{
try
{
LoadAssembly(System.Reflection.Assembly.LoadFile(item));
}
catch
{
}
}
}
}
public
static
void
LoadAssembly(System.Reflection.Assembly assembly)
{
foreach
(Type t
in
assembly.GetTypes())
{
ProtoBuf.ProtoContractAttribute[] pc = Smark.Core.Functions.GetTypeAttributes<ProtoBuf.ProtoContractAttribute>(t,
false
);
if
(pc.Length > 0)
{
string
name = t.Name;
if
(!
string
.IsNullOrEmpty(pc[0].Name))
name = pc[0].Name;
mTypes.Add(name, t);
mNames.Add(t, name);
}
}
}
class
MessageAdapter : Beetle.IMessage
{
public
object
Message
{
get
;
set
;
}
public
void
Load(Beetle.BufferReader reader)
{
string
type = reader.ReadString();
Beetle.ByteArraySegment segment = ByteArraySegment;
reader.ReadByteArray(segment);
using
(System.IO.Stream stream =
new
System.IO.MemoryStream(segment.Array, 0, segment.Count))
{
Message = ProtoBuf.Meta.RuntimeTypeModel.Default.Deserialize(stream,
null
, mTypes[type]);
}
}
public
void
Save(Beetle.BufferWriter writer)
{
writer.Write(mNames[Message.GetType()]);
Beetle.ByteArraySegment segment = ByteArraySegment;
using
(System.IO.Stream stream =
new
System.IO.MemoryStream(segment.Array))
{
ProtoBuf.Meta.RuntimeTypeModel.Default.Serialize(stream, Message);
segment.SetInfo(0, (
int
)stream.Position);
}
writer.Write(segment);
}
[ThreadStatic]
private
static
ByteArraySegment mByteArraySegment =
null
;
public
ByteArraySegment ByteArraySegment
{
get
{
if
(mByteArraySegment ==
null
)
mByteArraySegment =
new
ByteArraySegment(TcpUtils.DataPacketMaxLength);
return
mByteArraySegment;
}
}
}
}
}
分析主要重写了ReadCast,WriteCast,而两个Cast方法主要是把消息进行一个适配器包装到一个IMessage对象中提供给组件处理.通过适配器MessageAdapter来实现终于对象的序列化和反序列化操作,并整合的流中.为了方便处理消息对应称名称还添加了分析程序类型来加载对应的类型和名称关系映射.接下来订制一个简单的注册对象
12345678910[ProtoContract]
public
class
Register
{
[ProtoMember(1)]
public
string
UserName {
get
;
set
; }
[ProtoMember(2)]
public
string
EMail {
get
;
set
; }
[ProtoMember(3)]
public
DateTime ResponseTime {
get
;
set
; }
}
实现相应的TCP服务
协议分析器扩展完成后就通过它来实现一个基于protobuf对象处理的TCP交互服务.
12345678910111213141516171819202122232425262728293031323334class
Program : Beetle.ServerBase<Beetle.Packages.ProtobufPackage>
{
static
void
Main(
string
[] args)
{
Beetle.Packages.ProtobufPackage.LoadAssembly(
typeof
(Program).Assembly);
Beetle.TcpUtils.Setup(
"beetle"
);
Program server =
new
Program();
server.Open(9034);
Console.WriteLine(
"server start @9034"
);
Console.Read();
}
protected
override
void
OnConnected(
object
sender, Beetle.ChannelEventArgs e)
{
base
.OnConnected(sender, e);
Console.WriteLine(
"{0} connected"
, e.Channel.EndPoint);
}
protected
override
void
OnDisposed(
object
sender, Beetle.ChannelDisposedEventArgs e)
{
base
.OnDisposed(sender, e);
Console.WriteLine(
"{0} disposed"
, e.Channel.EndPoint);
}
protected
override
void
OnError(
object
sender, Beetle.ChannelErrorEventArgs e)
{
base
.OnError(sender, e);
Console.WriteLine(
"{0} error {1}"
, e.Channel.EndPoint, e.Exception.Message);
}
protected
override
void
OnMessageReceive(Beetle.PacketRecieveMessagerArgs e)
{
Messages.Register register = (Messages.Register)e.Message;
register.ResponseTime = DateTime.Now;
e.Channel.Send(register);
}
}
TCP服务的实现和原来的实现方式一致,只是继承的ServerBase的泛型参是基于protobuf的协议分析器类型.
连接到服务进行对象通讯
同样接入服务端的代码只是改变一下泛型参类型即可
123456789101112131415161718192021222324252627282930313233343536373839404142private
void
cmdConnect_Click(
object
sender, EventArgs e)
{
try
{
channel = Beetle.TcpServer.CreateClient<Beetle.Packages.ProtobufPackage>(txtIPAddress.Text, 9034, OnReceive);
channel.ChannelDisposed += OnDisposed;
channel.ChannelError += OnError;
channel.BeginReceive();
cmdRegister.Enabled =
true
;
cmdConnect.Enabled =
false
;
}
catch
(Exception e_)
{
MessageBox.Show(e_.Message);
}
}
private
void
OnReceive(Beetle.PacketRecieveMessagerArgs e)
{
Register reg = (Register)e.Message;
Invoke(
new
Action<Register>(r =>
{
txtREMail.Text = r.EMail;
txtRName.Text = r.UserName;
txtResponseTime.Text = r.ResponseTime.ToString();
}), reg);
}
private
void
OnDisposed(
object
sender, Beetle.ChannelEventArgs e)
{
Invoke(
new
Action<Beetle.ChannelEventArgs>(s =>
{
txtStatus.Text =
"disconnect!"
;
cmdRegister.Enabled =
false
;
cmdConnect.Enabled =
true
;
}), e);
}
private
void
OnError(
object
sender, Beetle.ChannelErrorEventArgs e)
{
Invoke(
new
Action<Beetle.ChannelErrorEventArgs>(r =>
{
txtStatus.Text = r.Exception.Message;
}), e);
}
把对象发送给服务端
1234Register register =
new
Register();
register.EMail = txtEMail.Text;
register.UserName = txtName.Text;
channel.Send(register);
运行效果
下载代码:Code
总结
由于Protobuf制定的协议是开放的,所以很多平台下都有相关实现包括:c++,java,php等.通过整合protobuf作为协议载体可以方便地和其他平台进行TCP数据交互整合.
- Beetle在Tcp通讯中使用Protobuf
- Beetle使用Protobuf.net进行对象序列化传输
- 在c++中使用protobuf
- 在 Golang 中使用 Protobuf
- 在 Golang 中使用 Protobuf
- 在Unity5中使用Protobuf
- 在egret中使用protobuf
- 在VS中使用Protobuf
- 在Unity5中使用Protobuf
- iOS中tcp+protobuf
- 在lua环境中使用protobuf ,编译protobuf文件
- 在lua环境中使用protobuf
- 在lua环境中使用protobuf
- 在erlang项目中使用protobuf
- 在protobuf中使用python的extension
- 在lua环境中使用protobuf
- protobuf在iOS中得使用
- 在lua环境中使用protobuf
- 实战DeviceIoControl 之一:通过API访问设备驱动程序
- IT高管发出“暗语邮件”求救(图)
- c++编写gif动画现实控件
- C#操作符,委托,事件
- 一 JVM内存模型
- Beetle在Tcp通讯中使用Protobuf
- 【Linux基础】面向对象程序设计的特点
- wince录音实现
- Unix vs. Linux vs. BSD
- TCP状态转换图详解
- 最近在调优SliverLightweb程序,两个下手点:wcf调用方式优化;iis并发访问优化
- 数组资源(arrays)的使用
- 客户端网络
- java的锁机制