Protobuf.net is the implementation of protobuf protocol on the. NET platform. It supports source. netProgram, Binary serialization of Silverlight and window phon7. this section describes how to use protobuf.net in Silverlight TCP communication. develop a communication protocol before achieving communication. It mainly describes protobuf.net serialized transmission formats and how to deserialize the obtained data.
The protocol description is divided into three parts: first, the total length of the message, followed by the message type name. The component creates the corresponding message object by the name, the end is the protobuf serialized data of the related object.
After the protocol is determined, you can proceed.CodeImplementation, because a Silverlight TCP component beetle. SL (Project address: http://beetlesl.codeplex.com/) has been written before; so it is OK to extend it directly on the basis. There are two tasks to be done: Implementing a message adapter and a protocol analyzer. Before implementation, you must reference the protobuf.net component at http://code.google.com/p/protobuf-net.
The message adapter implementation is as follows:
1 Public Class Messageadapter: beetle. iMessage 2 { 3 Public Object Message 4 { 5 Get ; 6 Set ; 7 } 8 Static Dictionary < String , Type> mtypes = New Dictionary < String , Type> ( 256 ); 9 Static Dictionary <type, String > Mnames = New Dictionary <type, String > ( 256 ); 10 Public Static Void Loadmessage (system. reflection. Assembly) 11 { 12 Foreach (Type T In Assembly. gettypes ()) 13 { 14 Protobuf. protocontractattribute [] Pc = (protobuf. protocontractattribute []) T. getcustomattributes ( Typeof (Protobuf. protocontractattribute ), False ); 15 If (PC. length> 0 ) 16 { 17 String Name = T. Name; 18 Nameattribute [] NA = (nameattribute []) T. getcustomattributes ( Typeof (Nameattribute ),False ); 19 If (PC. length> 0 ) 20 If (Na. length> 0 ) 21 { 22 Name = Na [ 0 ]. Name; 23 } 24 Mtypes. Add (name, t ); 25 Mnames. Add (T, name ); 26 } 27 } 28 } 29 Public Static Void Send (beetle. tcpchannel channel,Object Message) 30 { 31 Messageadapter MA = New Messageadapter (); 32 Ma. Message = Message; 33 Channel. Send (MA ); 34 } 35 Public Void Load (beetle. bufferreader) 36 { 37 String Type = Reader. readstring (); 38 Byte [] DATA = Reader. readbytearray (); 39 Using (System. Io. Stream stream = New System. Io. memorystream (data, 0 , Data. Length )) 40 { 41 Message = protobuf. Meta. runtimetypemodel. Default. deserialize (stream, Null , Mtypes [type]); 42 } 43 44 } 45 Public Void Save (beetle. bufferwriter writer) 46 { 47 Writer. Write (mnames [message. GetType ()]); 48 Byte [] Data; 49 Using (System. Io. Stream stream = New System. Io. memorystream ()) 50 { 51 Protobuf. Meta. runtimetypemodel. Default. serialize (stream, message ); 52 53 Data = New Byte [Stream. Length]; 54 Stream. Position = 0 ; 55 Stream. Read (data, 0 , Data. Length ); 56 57 } 58 59 Writer. Write (data ); 60 61 62 } 63 }
The implementation of the entire process is relatively simple, that is, writing serialized information into bufferwriter based on the content of the Protocol, and obtaining the message from bufferreader in the same way.
Implementation of subcontractors
Beetle. SL already provides a package based on the header Description Size, so the implementation is simpler.
Public Class Protobufheadsizepackage: beetle. headsizeofpackage { Public Protobufheadsizepackage (){} Protected Override Void Writemessagetype (iMessage MSG, bufferwriter writer ){} Protected Override IMessage readmessagebytype (bufferreader reader, Out Object Typetag) {typetag = " Messageadapter " ; Return New Messageadapter ();}}
To easily define connections, tcpchannel is inherited to implement a protobufchannel.
Public ClassProtobufchannel: tcpchannel {PublicProtobufchannel ():Base(NewProtobufheadsizepackage ()){}}
After completing the following work, you can use protobuf.net to process objects in Silverlight TCP communication. Below are some simple information.
[Protocontract] Public Class Search {[protomember ( 1 )] Public String CompanyName { Get ; Set ;} [Protomember ( 2 )] Public String City {Get ; Set ;} [Protomember ( 3 )] Public String Region { Get ; Set ;} [Protocontract] Public Class Searchresult {[protomember ( 1 )] Public List <customer> MERs { Get ; Set ;} [Protocontract] Public Class Getcustomerorders {[protomember ( 1 )] Public String Customerid { Get ; Set ;} [Protocontract] Public Class Customerorders {[protomember ( 1 )] Public Ilist <order> Orders { Get ; Set ;}}
After the message is set, you can define the connection.
PrivateProtobufchannel mchannel =NewProtobufchannel ();Private VoidUsercontrol_loaded (ObjectSender, routedeventargs e) {messageadapter. loadmessage (This. GetType (). Assembly); mchannel. Connected+ =Onconnected; mchannel. disposed+ =Ondisposed; mchannel. Receive+ =Onreceive; mchannel. Error+ =Onerror ;}
After the connection is created, bind related events. The main events include connection success, connection release, connection handling error, and Data Receiving Event. After defining these events, you only need to call a simple connect method to connect to the TCP Service of the specified IP port.
Private VoidCmdconnect_click (ObjectSender, routedeventargs e) {mchannel. Connect (txtip. Text,4520);}
After the connection, you can directly use the channel to send protobuf.net serializable objects.
Private VoidCmdsearch_click (ObjectSender, routedeventargs e) {packages. Search search=NewPackages. Search (); search. companyName=Txtcompany. Text; messageadapter. Send (mchannel, search );}
Data events can be output based on different message types.
Private Void Onreceive ( Object Sender, eventchannelreceiveargs e) {messageadapter Adapter =(Messageadapter) E. message; If (Adapter. Message Is Packages. searchresult) {packages. searchresult = (Packages. searchresult) Adapter. message; This . Dispatcher. begininvoke () => {Dgcustomers. itemssource = Searchresult. MERs ;});} Else If (Adapter. MessageIs Packages. customerorders) {packages. customerorders orders = (Packages. customerorders) Adapter. message; This . Dispatcher. begininvoke () => {Dborders. itemssource = Orders. Orders ;});}}
The preceding is a simple data query example.
Demo
Specific Code can go to http://beetlesl.codeplex.com/get