Author: Dunchun Jiang Version: 1.0 Date: 26/11/2018
Here is a website introducing the theory of Wamp. But, actually, I modify some technical details in order to meet the demand of invoking API in local c# assembly base on websocket. In summary, this framework could do these:
- Open the API of c# assembly to websocket connection in a simple and quick way, even though you don't have a clear conscious about how to organize the router
- Export all c# API to js file, as a result, the front_end could invoke these API just by referencing these files
- The asynchronous invoking is also supported. In other words, even though one method invoked by remote command in your assembly needs a long time to process, the later remote command will not be blocked
@ to do
This framework supports two types of packet in websocket: String Mode and Byte[] Mode. Both these two modes have the same items in packet. This chart explains the structure of packet delivered between master and slaves(*
represents this item is not essential).
Items: | Packet Head | ID | Class Name | Method(Event) Name | Arg_0* |
...* |
---|---|---|---|---|---|---|
Type in C#: | byte | UInt16 | string | string | - | - |
So, what these items mean:
Packet Head: several numbers are defined to present different command of this packet. This chart explains which command type each number represents:
Number | Command |
---|---|
0 | Remote call |
8 | Feedback of successful remote call |
9 | Feedback of failed remote call |
10 | Remote subscribe |
11 | Subscribed event invoked |
18 | Feedback of successful remote subscribe |
19 | Feedback of failed remote subscribe |
20 | Remote unsubscribe |
28 | Feedback of successful remote unsubscribe |
29 | Feedback of failed remote unsubscribe |
30 | Remote register |
38 | Feedback of successful remote register |
39 | Feedback of failed remote register |
101 | An error happened |
ID: No matter calling a method or subscribing a event, the Wamp slaves need to generate a unique ID, and send it to Wamp master. After that, the master will send it back to slave in the feedback message. This ID make sure that all message could be send back to the slave where it came from.
Class Name: The name of a class in c# assembly.
Method(Event) Name: The name of a method(event) belong to the class mentioned above in c# assembly.
Arg_n: Wamp message will have this item in 3 occasions. Firstly, the slave should send the arguments when remotely call a method, if this method needs. Secondly, the master would send a argument back in the feedback message of a remote call, if this method has return value. Finally, the master would send arguments back when a subscribed event invoked, if this event delivers parameters out.
Well, it's very simple to orgnaise a packet in string mode, converting all items to string, then splitting them by '|'
is enough. You might wonder why we still need byte[] mode if string mode is so simple and both the master and slaves could decode the packet very easy. The reason is the packet in byte[] mode is smaller than string mode in most occasion.
Like the string mode, all items in byte[] need to be converted to byte array. Then the master and salves need to decode packet and get all items according to every item's length in the packet(byte array). This chart shows every items' length.(*
represents this item is not essential, ***
represents this item will be explained latter)
Items: | Packet Head | ID | Class Name and Method(Event) Name | Arg_0* |
...* |
---|---|---|---|---|---|
Type in C#: | byte | UInt16 | string | - | - |
Length in array: | 1 | 2 | 1+n | *** |
*** |
You might notice that the Class Name and Method(Event) Name
looks a little strange(different with the structure in packet). Actually, in byte[] mode, we use this item to merge the Class Name
and Method(Event) Name
which stores the Class Name and Method(Event) Name together, and splits them using a '|'
. Because these two items are both string
type. Another consideration is we need another byte
to illustrates this compound string's length when it was converted to byte array. As a result, this new item will occupy 1+n
bytes in the packet, the front 1
byte stores a byte representing the byte array's length(n
) converted from this compound string, the next n
bytes store the byte array converted from this compound string. Also for this reason, the length of the byte array converted from this compound string must less than 255.
Another point need to be noticed is the length of Arg_n
. I explain it in more details because it's a bit of complicated. Different types(in C#) of arguments have different length when they were converted to byte array, so, we need to label which type this argument is in packet. Several numbers(Byte) are defined to present different argument types.
Argument Type in C# | Lable |
---|---|
null | 0 |
string | 1 |
byte | 2 |
bool | 3 |
ushort | 4 |
short | 5 |
int | 6 |
float | 7 |
double | 8 |
json | 9 |
string[] | 11 |
byte[] | 12 |
bool[] | 13 |
ushort[] | 14 |
short[] | 15 |
int[] | 16 |
float[] | 17 |
double[] | 18 |
json[] | 19 |
Well, after we lable different type of arguments, storing them in packet will be easyer. Let's begin with the most typical argument's type: int
. If an argument in c# is int
, it will occupy 1+4
bytes in the packet, the front 1
stores the lable(6
) of int
, the next 4
bytes store the byte array converted from this argument. These type are similar to the int
.
Argument Type in C# | Length in Packet | Content in Packet |
---|---|---|
byte | 1+1 | 2+arg.ConvertToByteArray() |
bool | 1+1 | 3+arg.ConvertToByteArray() |
ushort | 1+2 | 4+arg.ConvertToByteArray() |
short | 1+2 | 5+arg.ConvertToByteArray() |
int | 1+4 | 6+arg.ConvertToByteArray() |
float | 1+4 | 7+arg.ConvertToByteArray() |
double | 1+8 | 8+arg.ConvertToByteArray() |
string
need to be payed more attention because arguments of string
type have a changed length when they were converted to byte array. So, we insert a int
(four bytes) to indicate this arguments' length in byte[] mode. As a result, if an argument in c# is string
, it will occupy 1+4+n
bytes in the packet, the front 1
stores the lable(1
) of string
, the next 4
bytes is a int
value store the length of byte array converted from this argument, the last n
store the real byte array converted from this argument. The arguments of json
are as same as string
.
Argument Type in C# | Length in Packet | Content in Packet |
---|---|---|
string | 1+4+n | 1+arg.ConvertToByteArray().length.ConvertToByteArray()+arg.ConvertToByteArray() |
json | 1+4+n | 9+arg.ConvertToByteArray().length.ConvertToByteArray()+arg.ConvertToByteArray() |
But we still have problem when we store arrays in packet. We need @ to do