想要深入理解ORB的工作过程与原理,学习与了解GIOP消息格式必不可少。我们知道GIOP是独立于具体通信的更高级别的抽象,因此这里针对GIOP在TCP/IP上的实现IIOP协议进行学习与分析(IIOP是规范中要求所有的ORB厂商都必要实现的协议,因此GIOP规范中也对IIOP协议进行了具体的定义)。

根据CORBA Specification的相关阐述,GIOP规范主要包括了以下三个方面:

1、Common Data Representation(CDR) definition(公共数据表达定义),CDR定义了IDL数据类型序列化为底层的byte流的规范。

2、GIOP Message Formats(GIOP消息格式),GIOP消息是ORB之间的通信最小单元。GIOP消息的类型有对象请求,对象定位和通信连接管理等等。

3、GIOP Transport Assumptions(GIOP传输层注意项,不知道这里翻译成”注意项“是否合适)。GIOP规范描述了一些底层协议的实现在传输GIOP消息时需要关注的事项,GIOP给出了一些假设/建议,另外规范还描述了应该如何去管理连接(建立与断开),保证GIOP消息顺序等等。

通常情况下我们并不会去关注第三点。

好了,我们一点一点学习以上三点(大部分情况下我只是作为规范的搬运工而已)。

Common Data Representation(CDR):

CDR描述了IDL数据类型应该如何序列化。包括了以下几点:

1、Byte Ordering,也就是我们所说的大端小端,这里不多陈述大端小端的知识了,读者如有不懂可以自行baidu/google之。每个GIOP消息/Encapsulation(Encapsulation的阐述请点这里)都包含了一个用于标识大小端的标识。

2、Aligned Primitive Types基本类型(如int, short, string)的对齐,就像我们在c/c++接触到的内存对齐情况一样,如此可以使得我们更快地序列化/反序列化消息。

3、Complete OMG IDL Mapping完整的IDL类型映射:CDR描述了所有IDL类型的底层表示,除了基本类型以外,还包括了可以传输的pseudo-object(伪对象)比如TypeCodes(用于在DII和Any中表示参数的类型信息),Object Reference和异常等等(说它们是伪对象,是因为它们并不是真实的对象,而是对象的另一种表达,比如Object Reference可以用来传送一个对象,但Object Reference只是一个IOR)。

首先来看一下第二点,基本类型的序列化。

首先在边界对齐上,数据类型必须对齐到它的大小的倍数的位置上。比如依次序列化下面的struct:

  1. module alignmenttest{
  2. struct TestStruct{
  3. short sa;
  4. short sb;
  5. char ca;
  6. char cb;
  7. long la;
  8. }
  9. }
  1. octet index-------------------
  2. 0
  3. 1 short sa
  4. -------------------
  5. 2
  6. 3 short sb
  7. -------------------
  8. 4 char ca
  9. -------------------
  10. 5 char cb
  11. -------------------
  12. 6
  13. 7
  14. -------------------
  15. 8
  16. 9
  17. 10 long la
  18. 11
  19. -------------------

这与我们的C语言在大部分机器的上的内存对齐规则是一致的。因此GIOP甚至可以不经过任何处理直接搬到内存中去就可以操作,使用。

Encapsulation

这里不知道怎么去翻译这个词,也许用”封装“比较合适吧,它就像是我们C语言中的struct,java中的class,代表一个集合,并且可以相互嵌套。GIOP规范这里所指的Encapsulation,还有以下两个含义:

1、Encapsulation与Encapsulation,Message之间的Byte Ordering可以是不相同的,即使它们之间是嵌套关系。

2、Encapsulation是一个抽象的表示,通常具体地它将会被编码成sequence<octet>,编码成sequence<octet>时,第一个octet代表着Byte Ordering。

Value Types

valuetype类似于一个加强版本的struct,但valuetype支持继承并且可以定义本地方法(包括构造函数)等而struct不支持,详细请看CORBA规范的说明。基于上面这些特性,在传输valuetype时候,需要包含valuetype的基类信息以便客户端进行向上转类等操作。在进行序列化的时候,需要首先序列化基类的元素,再序列化子类的元素。valuetype支持自定义序列化,但客户端和服务端的一致性由用户自己保证。需要注意的是,valuetype中的方法是作用于本地的,它并不会像interface中的方法论一样被传递到远程Servant。

Pseudo-Object Types 伪对象类型

这里主要说一下TypeCode,关于Object Reference的说明在后面IIOP消息中会有说明。TypeCode的作用上面已经提到,这里再重复一遍,TypeCode提供了一块数据中各个成员的信息,一般在确定动态类型Any的时候会用到。比如:

  1. module...{
  2. interface...{
  3. void add(in long a, n long b, Any c);
  4. }
  5. }

在运行时Any c的具体类型才可以得知,那么在传输c的时候,需要附上c的序列化结构信息,服务端才能正确地反序列化/还原c,我们可以看一下Any类型的序列化过程相关代码:

  1. public class CDROutputStream_1_0 extends CDROutputStreamBase {
  2. ....
  3. public void write_any(Any any) {
  4. if (any == null) {
  5. throw wrapper.nullParam();
  6. }
  7.  
  8. write_TypeCode(any.type());//首先写出TypeCode信息
  9. any.write_value(parent);//写出值信息。
  10. }
  11. ....
  12. }

下面是写出TypeCode信息的相关代码,它根据当前any类型的_kind来写出相对应的信息。比如对应于struct类型,那么写出的TypeCode信息将包括struct中每个成员的类型信息,这可能是为了应对IDL在客户端与服务端不致的问题。

  1. public final class TypeCodeImpl extends TypeCode {
  2. ....
  3. public void write_value(TypeCodeOutputStream tcos) {
  4. ...
  5. TypeCodeOutputStream topStream = tcos.getTopLevelStream();
  6.  
  7. if (_kind == tk_indirect) {
  8. // The encoding used for indirection is the same as that used for recursive ,
  9. // TypeCodes i.e., a 0xffffffff indirection marker followed by a long offset
  10. // (in units of octets) from the beginning of the long offset.
  11. int pos = topStream.getPositionForID(_id);
  12. int topPos = tcos.getTopLevelPosition();
  13. tcos.writeIndirection(tk_indirect, pos);
  14. return;
  15. }
  16.  
  17. tcos.write_long(_kind);
  18.  
  19. // Bug fix 5034649:
  20. // Do this AFTER the write of the _kind in case the alignment
  21. // for the long changes the position.
  22. topStream.addIDAtPosition(_id, tcos.getTopLevelPosition()-4);
  23.  
  24. switch (typeTable[_kind]) {
  25. case EMPTY:
  26. // nothing more to marshal
  27. break;
  28.  
  29. case SIMPLE:
  30. switch (_kind) {
  31. case TCKind._tk_string:
  32. case TCKind._tk_wstring:
  33. // marshal the bound on string length
  34. tcos.write_long(_length);
  35. break;
  36.  
  37. case TCKind._tk_fixed:
  38. tcos.write_ushort(_digits);
  39. tcos.write_short(_scale);
  40. break;
  41.  
  42. default:
  43. // unknown typecode kind
  44. throw wrapper.invalidSimpleTypecode() ;
  45. }
  46. break;
  47.  
  48. case COMPLEX:
  49. TypeCodeOutputStream _encap = tcos.createEncapsulation(tcos.orb());
  50.  
  51. switch(_kind) {
  52. case TCKind._tk_objref:
  53. case TCKind._tk_abstract_interface:
  54. _encap.write_string(_id);
  55. _encap.write_string(_name);
  56. break;
  57.  
  58. case TCKind._tk_union:
  59. _encap.write_string(_id);
  60. _encap.write_string(_name);
  61. _discriminator.write_value(_encap);
  62. _encap.write_long(_defaultIndex);
  63. _encap.write_long(_memberCount);
  64.  
  65. for (int i=0; i < _memberCount; i++) {
  66. if (i == _defaultIndex) {
  67. _encap.write_octet(_unionLabels[i].extract_octet());
  68. } else {
  69. switch (realType(_discriminator).kind().value()) {
  70. case TCKind._tk_short:
  71. _encap.write_short(_unionLabels[i].extract_short());
  72. break;
  73. case TCKind._tk_long:
  74. _encap.write_long(_unionLabels[i].extract_long());
  75. break;
  76. case TCKind._tk_ushort:
  77. _encap.write_short(_unionLabels[i].extract_ushort());
  78. break;
  79. case TCKind._tk_ulong:
  80. _encap.write_long(_unionLabels[i].extract_ulong());
  81. break;
  82. case TCKind._tk_float:
  83. _encap.write_float(_unionLabels[i].extract_float());
  84. break;
  85. case TCKind._tk_double:
  86. _encap.write_double(_unionLabels[i].extract_double());
  87. break;
  88. case TCKind._tk_boolean:
  89. _encap.write_boolean(_unionLabels[i].extract_boolean());
  90. break;
  91. case TCKind._tk_char:
  92. _encap.write_char(_unionLabels[i].extract_char());
  93. break;
  94. case TCKind._tk_enum:
  95. _encap.write_long(_unionLabels[i].extract_long());
  96. break;
  97. case TCKind._tk_longlong:
  98. _encap.write_longlong(_unionLabels[i].extract_longlong());
  99. break;
  100. case TCKind._tk_ulonglong:
  101. _encap.write_longlong(_unionLabels[i].extract_ulonglong());
  102. break;
  103. case TCKind._tk_wchar:
  104. _encap.write_wchar(_unionLabels[i].extract_wchar());
  105. break;
  106. default:
  107. throw wrapper.invalidComplexTypecode() ;
  108. }
  109. }
  110. _encap.write_string(_memberNames[i]);
  111. _memberTypes[i].write_value(_encap);
  112. }
  113. break;
  114.  
  115. case TCKind._tk_enum:
  116. _encap.write_string(_id);
  117. _encap.write_string(_name);
  118. _encap.write_long(_memberCount);
  119.  
  120. for (int i=0; i < _memberCount; i++) {
  121. _encap.write_string(_memberNames[i]);
  122. }
  123. break;
  124.  
  125. case TCKind._tk_sequence:
  126. lazy_content_type().write_value(_encap);
  127. _encap.write_long(_length);
  128. break;
  129.  
  130. case TCKind._tk_array:
  131. _contentType.write_value(_encap);
  132. _encap.write_long(_length);
  133. break;
  134.  
  135. case TCKind._tk_alias:
  136. case TCKind._tk_value_box:
  137. _encap.write_string(_id);
  138. _encap.write_string(_name);
  139. _contentType.write_value(_encap);
  140. break;
  141.  
  142. case TCKind._tk_struct:
  143. case TCKind._tk_except:
  144. _encap.write_string(_id);
  145. _encap.write_string(_name);
  146. _encap.write_long(_memberCount);
  147.  
  148. for (int i=0; i < _memberCount; i++) {
  149. _encap.write_string(_memberNames[i]);
  150. _memberTypes[i].write_value(_encap);
  151. }
  152. break;
  153.  
  154. case TCKind._tk_value:
  155. _encap.write_string(_id);
  156. _encap.write_string(_name);
  157. _encap.write_short(_type_modifier);
  158.  
  159. if (_concrete_base == null) {
  160. _orb.get_primitive_tc(TCKind._tk_null).write_value(_encap);
  161. } else {
  162. _concrete_base.write_value(_encap);
  163. }
  164.  
  165. _encap.write_long(_memberCount);
  166.  
  167. for (int i=0; i < _memberCount; i++) {
  168. _encap.write_string(_memberNames[i]);
  169. _memberTypes[i].write_value(_encap);
  170. _encap.write_short(_memberAccess[i]);
  171. }
  172. break;
  173.  
  174. default:
  175. throw wrapper.invalidTypecodeKindMarshal() ;
  176. }
  177.  
  178. // marshal the encapsulation
  179. _encap.writeOctetSequenceTo(tcos);
  180. break;
  181. }
  182. }
  183. ...
  184. }

Object Reference,对象引用

传送对象引用一般情况下传送它的IOR就可以了,IOR至少包含了以下信息:

1、版本信息,以保证低版本的ORB不会乱去解析高版本的IOR表示。

2、传输层面对象宿主机器的地址。

3、对象ID,用于唯一定位目标对象 。

Abstract Interface,抽象接口

Abstract Interface是一种比较特殊的类型,它是一个方法集合,interface和valuetype类型可以继承它,比如:

  1. abstract interface Describable {
  2. string get_description();
  3. };
  4. interface Example {
  5. void display (in Describable anObject);
  6. };
  7. interface Account : Describable {// passed by reference
  8. // add Account methods here
  9. };
  10. valuetype Currency supports Describable {// passed by value
  11. // add Currency methods here
  12. };

如上面,如果在运行时anObject参数是Account,那么在序列化的时候,首先用一个boolean为true的值以表明它是一个Object Reference,然后紧接着这个对象的IOR。

  1. ---------------
  2. TRUE
  3. ---------------
  4. IOR
  5. ---------------

如果在运行时anObject参数是Currency,那么在序列化的时候,首先用一个boolean为false值以表明它是一个valuetype,然后紧接着它的值。

  1. ---------------
  2. FALSE
  3. ---------------
  4. Value
  5. ---------------

GIOP消息格式

首先我们来看一下GIOP消息的IDL声明:

  1. module GIOP { // IDL extended for version 1.1 and 1.2
  2. struct Version {
  3. octet major;
  4. octet minor;
  5. };
  6.  
  7. #ifndef GIOP_1_1
  8. // GIOP 1.0
  9. enum MsgType_1_0 { // Renamed from MsgType
  10. Request, Reply, CancelRequest,
  11. LocateRequest, LocateReply,
  12. CloseConnection, MessageError
  13. };
  14. #else
  15.  
  16. // GIOP 1.1
  17. enum MsgType_1_1 {
  18. Request, Reply, CancelRequest,
  19. LocateRequest, LocateReply,
  20. CloseConnection, MessageError,
  21. Fragment
  22. // GIOP 1.1 addition
  23. };
  24.  
  25. #endif // GIOP_1_1
  26.  
  27. // GIOP 1.0
  28. struct MessageHeader_1_0 { // Renamed from MessageHeader
  29. char magic [4];
  30. Version GIOP_version;
  31. boolean byte_order;
  32. octet message_type;
  33. unsigned long message_size;
  34. };
  35.  
  36. // GIOP 1.1
  37. struct MessageHeader_1_1 {
  38. char magic [4];
  39. Version GIOP_version;
  40. octet flags;
  41. // GIOP 1.1 change
  42. octet message_type;
  43. unsigned long message_size;
  44. };
  45.  
  46. // GIOP 1.2
  47. typedef MessageHeader_1_1 MessageHeader_1_2;
  48. };

magic表明这是一个GIOP消息,它的值为字符串GIOP的byte:"GIOP".getBytes("ISO8859-1")

GIOP_Version包含这个消息所使用的GIOP协议的版本信息,需要注意的是,它和IIOP版本号是两码事,虽然它们的IDL描述是一样的

byte_order只在GIOP 1.0版本中被使用,它指定后面元素如message_size(比如占据4个字节整形)是大端表示还是小端表示的。

flags在GIOP 1.1和1.2版本中使用,它和byte_ordfer一样都只占据一个字节,只不过flag中用bit表示一些信息:

  1. |7|6|5|4|3|2|1|0|
  2. | | | | | | | |
  3. | | | | | | | ->byte order, 0: big-endian, 1: little-endian
  4. | | | | | | ---->后面是否还有fragments, 0: No, 1: Yes
  5. ---------------->保留

message_type,它的值表明了消息的类型,下面是消息类型的列表。

Message Type Originator Value GIOP Versions
Request Client 0 1.0, 1.1, 1.2
Reply Server 1 1.0, 1.1, 1.2
CancleRequest Client 2 1.0, 1.1, 1.2
LocateRequest Client 3 1.0, 1.1, 1.2
LocateReply Server 4 1.0, 1.1, 1.2
CloseConnection Server 5 1.0, 1.1, 1.2
MessageError Both 6 1.0, 1.1, 1.2
Fragment Both 7 1.1, 1.2

message_size表明消息头后面的还有多个字节 (消息体Message Body的长度,不包括12个字节的消息头),这是一个unsigned long类型,它的字节顺序与上面byte_order域与flags域所指定的字节顺序是一致的。注意对于GIOP1.2,message_size + 12(消息头长度)的和一定需要可以被8整除(也许为了内存对齐)。

下面介绍一下消息类型,因为篇幅原因,这里只对Request Message和Reply Message介绍。

Request Message

Request Header的IDL定义:

  1. module GIOP { // IDL extended for version 1.1 and 1.2
  2.  
  3. // GIOP 1.0
  4. struct RequestHeader_1_0 { // Renamed from RequestHeader
  5. IOP::ServiceContextList
  6. service_context;
  7. unsigned long request_id;
  8. boolean response_expected;
  9. sequence <octet> object_key;
  10. string operation;
  11. Principal requesting_principal;
  12. };
  13.  
  14. // GIOP 1.1
  15. struct RequestHeader_1_1 {
  16. IOP::ServiceContextList service_context
  17. unsigned long request_id;
  18. octet reserved[3];
  19. sequence<octet> object_key;
  20. string operation;
  21. Principal requesting_principal;
  22. };
  23.  
  24. // GIOP 1.2
  25. typedef short AddressingDisposition;
  26. const short KeyAddr=0;
  27. const short ProfileAddr=1;
  28. const short ReferenceAddr=2;
  29.  
  30. struct IORAddressingInfo {
  31. unsigned long selected_profile_index;
  32. IOP::IOR ior;
  33. };
  34.  
  35. union TargetAddress switch (AddressingDisposition) {
  36. case KeyAddr: sequence<octet> object_key;
  37. case ProfileAddr: IOP::TaggedProfile profile;
  38. case ReferenceAddr: IORAddressingInfo ior;
  39. };
  40.  
  41. struct RequestHeader_1_2 {
  42. unsigned long request_id;
  43. octet response_flags;
  44. octet reserved[3];
  45. TargetAddress target;
  46. string operation;
  47. IOP::ServiceContextList service_context;
  48. // Principal not in GIOP 1.2
  49. };
  50. };

request_id用于将服务器的响应信息与客户端发送的请求信息对应起来,因为客户端的同时可能向服务端发送多个对象的请求,而它们可以共用一个连接,服务器返回的信息将包含客户端发送的request_id,客户端利用request_id来完成响应信息的分发。

response_flags用于表示此请求是否需要返回值,它的最低位是1的话表示需要返回值,如何需要返回值,并且在DII中INV_NO_RESPONSE标志位没有被设置,那么response_flags必须设置为0x03。

如果此请求不需要返回值,或者在DII调用中设置了INV_NO_RESPONSE标志位,那么response_flags可以设置为0x00或者0x01

reserved的值应该设置为,它为未来保留使用。

object_key,在GIOP 1.0和1.1中,用于标识服务端的目标对象,它其实就是IOR IIOPProfile中的object_key的值。

target,但从GIOP 1.2开始,更换为使用target域来标识调用的目标。

operation是idl中定义的interface中的目标方法名。

service_context包含了从客户端传递到服务端的Service Context信息。

requesting_principal,在GIOP 1.0和GIOP 1.1版本中,它包含了关于客户端身份信息的类,用于访问控制和其它目的。在它已经被弃用,并且在GIOP 1.2中不再包含这部分信息。

Request Body

在GIOP 1.0和1.1中,Request Body被序列化成Encapsulation并立即被附在消息头的后面。从GIOP 1.2开始,Request Body的开始位置是对齐到8字节的,如果消息头被修改之后,Request Body不需要重新序列化。Request包括了以下几项内容(按顺序序列化):

1、所有的in和inout参数,按照它们在方法参数中出现的先后顺序(从左到右)。

2、可选的Context pseudo object(Context伪对象),这些Context pseudo object被序列化成sequence<String>,每个Context pseudo object被序列化成一对String,Property Name和Property Value。只有操作的IDL定义包含有一个Conext Expression的情况下才会出现Context pseudo object,并且只会包含Context Expression中声明的成员。

比如下面方法的

  1. double example(in short m, out string str, inout p)

它的Request Body的将会是下面的结构:

  1. struct example_body{
  2. short m;
  3. long p;
  4. }

Reply Message

只有Request Message中的response expected位被设置为TRUE的情况下,服务器才会发送对应的Reply Message。Reply Message包括了所有的inout和out参数,并且可以包含有异常值。同样Reply Message包括了Reply Header和Reply Body两部分。

Reply Header

首先来看一下它的IDL定义:

  1. module GIOP { // IDL extended for 1.2
  2.  
  3. #ifndef GIOP_1_2
  4. // GIOP 1.0 and 1.1
  5. enum ReplyStatusType_1_0 { // Renamed from ReplyStatusType
  6. NO_EXCEPTION,
  7. USER_EXCEPTION,
  8. SYSTEM_EXCEPTION,
  9. LOCATION_FORWARD
  10. };
  11.  
  12. // GIOP 1.0
  13. struct ReplyHeader_1_0 { // Renamed from ReplyHeader
  14. IOP::ServiceContextList service_context;
  15. unsigned long request_id;
  16. ReplyStatusType_1_0 reply_status;
  17. };
  18.  
  19. // GIOP 1.1
  20. typedef ReplyHeader_1_0 ReplyHeader_1_1;
  21. // Same Header contents for 1.0 and 1.1
  22. #else
  23. // GIOP 1.2
  24. enum ReplyStatusType_1_2 {
  25. NO_EXCEPTION,
  26. USER_EXCEPTION,
  27. SYSTEM_EXCEPTION,
  28. LOCATION_FORWARD,
  29. LOCATION_FORWARD_PERM,// new value for 1.2
  30. NEEDS_ADDRESSING_MODE // new value for 1.2
  31. };
  32.  
  33. struct ReplyHeader_1_2 {
  34. unsigned long request_id;
  35. ReplyStatusType_1_2 reply_status;
  36. IOP:ServiceContextList service_context
  37. };
  38. #endif // GIOP_1_2
  39. };

request_id用于把Reply Message与对应的Request Message关联起来,并不是每个对象的请求会单独占用整个连接,多个对象的请求可以通过单个连接发送到服务端。Reply Message中的request_id与对应的Request Message中的request_id的值是一致的。

reply_status用于表示对应请求的完成状态和Reply Body的内容 ,如何方法请求调用成功完成,那么它的值是NO_EXCEPTION,并且Reply Body中包含返回值。否则Reply Body中的内容将会是:

1、异常值。

2、要求客户端重发请求到另一个服务端地址上的对象。

3、要求客户端提供更多用于定位对象的信息。

service_context包含了服务端发送给客户端的ORB service信息

Reply Body

和Request Body一样,在GIOP 1.0和1.1中,Reply Header紧接着就是Reply Body。从GIOP 1.2开始,Reply Body的起始位置需要对齐到8字节。Reply Body的内容由Reply Header中的reply_status的值决定:

如果reply_status的值为NO_EXCEPTION,那么Reply Body首先序列化返回值,然后是IDL方法定义中的out和inout参数(从左到右顺序),如下面方法

  1. double example(in short m, out string str, inout long p)

那么该方法请求在NO_EXCEPTION的情况下的返回值为:

  1. struct{
  2. return double;
  3. string str;
    long p;
  4. }

如果reply_status为USER_EXCEPTION或者SYSTEM_EXCEPTION的话,那么reply body包含方法抛出的异常值。

当reply_status为SYSTEM_EXCEPTION,那么reply body的结构如下:

  1. module GIOP { // IDL
  2. struct SystemExceptionReplyBody {
  3. string exception_id;
  4. unsigned long minor_code_value;
  5. unsigned long completion_status;
  6. };
  7. };

minor_code_value的高20位表示厂商Minor Codeset ID(VMCID),低12位表示minor code。一些厂商(可以是多个)可能想定义一些特有的异常MInor code,那么它们应该向OMG去申请这个VMCID。注意OMG标准的VMCID为0x4f4d0('O', 'M')。

如果reply_status的值为LOCATION_FORWARD的话,那么Reply Body包含了一个对象的IOR,然后客户端ORB负责将原来的请求重新发送到这个IOR指定的对象上,这个过程对于客户端应用程序是透明的(客户端并不能知道这些过程)。

如果replay_status的值为LOCATION_FORWARD_PERM,它的行为表现和LOCATION_FORWARD几乎是一样的,另外它被服务器用来向客户端表明 ,它可能要将当前对象的IOR替换成新的,并且新的IOR和旧的还是有效的,但推荐使用新的。

如果reply_status的值为NEED_ADDRESSING_MODE的话,Reply Body包括了一个GIOP::AddressingDisposition,客户端负责使用request addressing mode(提供更多对象信息)重新发送请求到这个对象上。同样的,重发过程对于用于程序是透明的,ORB并不会通知客户端的程序这个过程。

completion_state根据Standard Exception Definitions的IDL定义,它有COMPLETED_YES, COMPLETED_NO, COMPLETED_MAYBE三种状态。

CORBA GIOP消息格式学习的更多相关文章

  1. Lind.DDD.LindMQ~关于持久化到Redis的消息格式

    回到目录 关于持久化到Redis的消息格式,主要是说在Broker上把消息持久化的过程中,需要存储哪些类型的消息,因为我们的消息是分topic的,而每个topic又有若干个queue组成,而我们的to ...

  2. DNS消息格式

    一,简介 空谈误国,要让一大堆抽象的DNS概念落地,还是需要了解DNS消息格式的,本文会尽量详细地介绍DNS消息格式的每一个字段. 也可以移步rfc1035了解. 二,概览 DNS消息主要由五部分组成 ...

  3. Kafka的消息格式

    Commit Log Kafka储存消息的文件被它叫做log,按照Kafka文档的说法是: Each partition is an ordered, immutable sequence of me ...

  4. 【转】[WCF REST] 帮助页面与自动消息格式(JSON/XML)选择

    可以说WebHttpBinding和WebHttpBehavior是整个Web HTTP编程模型最为核心的两个类型,前者主要解决消息编码问题,而余下的工作基本上落在了终结点行为WebHttpBehav ...

  5. Web Service 消息格式

    当客户端和Web Service服务器进行通信时,他们交换消息.客户端发送请求消息到Web Service服务器. Web Service服务器响应并返回消息.这就像普通的HTTP,浏览器发送一个HT ...

  6. Kafka-Record(消息格式)

    注:本文依赖于kafka-0.10.0.1-src kafka消息格式是经过多个版本的演变的,本文只说0.10.0.1版本的消息格式. 消息格式如图1所示: 图1 CRC:用于校验消息内容.占4个字节 ...

  7. MQTT-SN协议乱翻之消息格式

    前言 紧接着上篇初步介绍,本文为第二篇,主要梳理MQTT-SN 1.2协议中定义的消息格式. 通用消息格式 消息头 其它可变部分 2/4字节表示 N字节组成 消息头部 长度 消息类型 1或3个字节 1 ...

  8. SIP消息类型和消息格式

    转自:http://blog.chinaunix.net/uid-1797566-id-2840904.html sip消息类型和消息格式 SIP是一个基于文本的协议,使用的是UTF-8字符集. SI ...

  9. 一文看懂Kafka消息格式的演变

    摘要 对于一个成熟的消息中间件而言,消息格式不仅关系到功能维度的扩展,还牵涉到性能维度的优化.随着Kafka的迅猛发展,其消息格式也在不断的升级改进,从0.8.x版本开始到现在的1.1.x版本,Kaf ...

随机推荐

  1. Sprint.Net 笔记

    有生以来写的第一份博客, 还真不会写, 请高手们指导指导. 1.引入 Spring.Core.dll 和 Common.Logging.dll 两个文 2. 在UI层的Web.conf 的 <C ...

  2. JQuery 对 Select option 的操作

    下拉框: <select id="selectID" >         <option value="1">1</option& ...

  3. session如何保存在专门的StateServer服务器中

    session保存在专门的StateServer中,该种方式,性能损失比sql略好.比inproc据说有10%-15%的性能损失.怎么使用StateServer 服务器呢? 1.初始化StateSer ...

  4. jquery 动态生成html后click事件不触发原因

    转自:http://www.iam3y.com/html/560.html 最近在做一个项目的时候,遇到动态加载微博内容,然后点击“展开评论”后获取该微博的所有评论.这里使用了动态加载的<spa ...

  5. 初识selendroid

    Testerhome社区的lihuazhang对selendroid官网的部分内容进行了翻译和讲解. 以下内容均摘自lihuazhang.感谢lihuazhang的讲解.原文地址:https://gi ...

  6. 关于MySQL中的left join、on、where的一点深入

    原文地址:http://www.oschina.net/question/89964_65912?sort=default&p=3#answers 即使你认为自己已对 MySQL 的 LEFT ...

  7. 新策略构思 dual thrust

    根据dual truest的策略,因为是针对日线级别的.同理我们可以根据60分钟级别开发出一套策略,等有时间写在下面

  8. hadoop map-red的执行过程

    hadoop的 map-red就是一个并行计算平台,我们在使用这个平台的时候,要做的事情就是提交自己定制的任务(job,主要定制map类,reduce类,combine类等类),然后设置job的各种参 ...

  9. PCL中的类

    1. PCLBase pcl_base.h中定义了PCL中的基类PCLBase,PCL中的大部分算法都使用了其中的方法. PCLBase实现了点云数据及其索引的定义和访问. 两个主要的变量input_ ...

  10. pytho day6 <正则表达式、常用模块、反射>

    本节介绍: 一:正则表达式: 正则表达并不是python 独有的.在各个语言里都有该语法的介绍.正则表达是处理字符串的强大的处理工具.拥有自己的独特的 处理方法.和处理引擎.虽然性能没有python ...