ArticleDirectory
- First, develop a TCP Service
- Client implementation
Although beetle provides excellent binary serialization performance, you need to manually describe the process through writer and reader. In fact, there are not many scenarios that care about these performance, in many cases, the automatic serialization FunctionProgramBoth programming and maintenance play an extremely convenient role. During the design, components use interfaces to describe message read/write operations. Therefore, protobuf support is more convenient during expansion.
Protobuf is an object serialization and deserialization solution developed by Googler. It is implemented on different language platforms such as C ++, Java, and net. Protobuf-net and protobuf-CSHARP-port are implemented in. Net respectively. protobuf-net is selected here. From the test point of view protobuf-net serialization volume and performance are relatively good, detailed can view: http://www.servicestack.net/benchmarks/NorthwindDatabaseRowsSerialization.1000000-times.2010-02-06.html
Because the component only supports processing iMessage objects, you must implement an iMessage for protobuf-net serialization. The serialized information of protobuf-net is closely related to the object content that does not include the object type information. Simply put, protobuf-net cannot deserialize the object based on the serialized information, in the deserialization process, the data must be explicitly specified based on that type of object. Therefore, a simple protocol must be developed for network transmission using protobuf-net serialized objects. The following is a messageadapter that uses protobuf.net to serialize objects for object data transmission.
The following is a message based on protobuf-Net.
Public class protobufadapter: iMessage {public object message {Get; set;} public static bool send (beetle. tcpchannel channel, object MSG) {protobufadapter adapter = new protobufadapter (); adapter. message = MSG; return channel. send (adapter);} public void load (beetle. bufferreader reader) {string type = reader. readstring (); beetle. bytearraysegment segment = marraypool. pop (); 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, type. getType (type);} marraypool. push (segment);} public void save (beetle. bufferwriter writer) {writer. write (message. getType (). fullname); beetle. bytearraysegment segment = marraypool. pop (); 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); marraypool. push (segment);} Private Static bytearraypool marraypool = new bytearraypool (100,102 4*8 );}
Protocol encapsulation is very simple. before writing a protobuf serialized object, first write a message type name with the leading length description, and then write a protobuf object sequence information stream with the leading length description. During reading, the type description name is read first, and the type of the relevant name is constructed and deserialized into a specific object in combination with the information stream.
The next step is to implement a coprocessor based on the size of the first 4 bytes description for this message.
Public class headsizepackage: beetle. headsizeofpackage {public headsizepackage (beetle. tcpchannel channel): Base (Channel) {} protected override beetle. iMessage readmessagebytype (beetle. bufferreader reader, out object typetag) {typetag = "protobufadapter"; return New protobufadapter ();} protected override void writemessagetype (beetle. iMessage MSG, beetle. bufferwriter writer ){}}
After the above protocols are encapsulated, the specific protocols are as follows:
After the protocol is developed, you can use beetle to build protobuf-based object transmission.
First, develop a TCP Service
Tcputils. Setup (200, 1, 1); tcpserver Server = new tcpserver (); server. channelconnected + = onconnected; server. channeldisposed + = ondisposed; server. Open (8340 );
AboveCodeIt is easy to initialize the component information, build a tcpserver, bind a connection access event and a connection disconnection event, and then bind the TCP Service on the 8340 side of all IP addresses. We need to do something during connection access.
Static void onconnected (Object sender, channeleventargs e) {e. channel. setpackage <messages. headsizepackage> (). receivemessage = onmessagereceive; E. channel. channelerror + = onerror; E. channel. beginreceive (); console. writeline ("{0} connected! ", E. Channel. endpoint );}
set a protocol subcontractor for the current TCP channel in the access event, and specify the corresponding message receiving event. Similarly, bind an error event to the TCP channel, in the process of message event processing, as long as you do not enable the thread to process the logic, exceptions in the process will trigger this event; you don't have to worry that exceptions will affect the entire server. This component is secure enough to ensure that the service can run continuously. After the TCP channel information is set, you can call the beginreceive () method to enter the data receiving status. The following is the Message Processing Event code:
Static void onmessagereceive (packetrecievemessagerargs e) {messages. protobufadapter adapter = (messages. protobufadapter) E. message; If (adapter. message is messages. register) {onregister (E. channel, (messages. register) adapter. message);} else if (adapter. message is messages. query) {onquery (E. channel, (messages. query) adapter. message);} else {}} static void onregister (beetle. tcpchannel channel, messages. register e) {console. writeline ("{0} register \ t Username: {1}; PWD: {2}; email: {3}", channel. endpoint, E. username, E. PWD, E. email);} static void onquery (beetle. tcpchannel channel, messages. query e) {console. writeline ("{0} QUERY \ t Customer: {1}", channel. endpoint, E. customerid); messages. order order = new messages. order (); Order. orderid = 10248; Order. customerid = "wilmk"; Order. employeeid = 5; Order. orderdate = 629720352000000000; Order. requireddate = 629744544000000000; Order. shipaddress = "59 Rue de l 'abbaye"; Order. shipcity = "Reims"; Order. shipcountry = "France"; Order. shipname = "Vins et alcools chevalier"; Order. shippostalcodes = "51100"; Order. shipregion = "RJ"; messages. protobufadapter. send (Channel, order );}
In this example, only two types of message objects are processed, namely, register and query. Only one simple output is made when Register is received, and an order object is returned when query is received.
Client implementation
The client must first access the service.
Private void upload connect_click (Object sender, eventargs e) {try {mchannel = tcpserver. createclient (txtipaddress. text, 8340); mchannel. setpackage <messages. headsizepackage> (). receivemessage = receivemessage; mchannel. channeldisposed + = ondisplsed; mchannel. beginreceive (); cmdregister. enabled = true; your query. enabled = true; Connect. enabled = false;} catch (exception E _) {MessageBox. show (E _. message );}}
After the connection is successfully created, the same thing to do is to set the subcontracted object and message receiving event. After the completion, the beginreceive () connection is called to receive the data status. At this time, we can send related objects to the server.
Private void cmdregister_click (Object sender, eventargs e) {messages. register Reg = new messages. register (); Reg. email = txtemail. text; Reg. pwd = txtpwd. text; Reg. username = txtusername. text; messages. protobufadapter. send (mchannel, Reg);} private void upload query_click (Object sender, eventargs e) {messages. query query = new messages. query (); query. customerid = txtcustomerid. text; messages. protobufadapter. send (mchannel, query );}
In this way, the example of transmitting protobuf.net serialized objects through beetle is completed.
Download complete code
C # game server mmrpg group: 136485198