Chinaunix首页 | 论坛 | 博客
  • 博客访问: 30364
  • 博文数量: 6
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 91
  • 用 户 组: 普通用户
  • 注册时间: 2014-10-19 20:11
文章分类

全部博文(6)

文章存档

2016年(1)

2014年(5)

我的朋友

分类: Java

2014-10-20 21:48:24

上篇,我们对HSQLDB的入口,Server.java做了分析。Server主要工作就是启动Tcp监听,等待客户端来进行连接。
我们知道,在计算机中,不能是数据也好,逻辑也好,最终都是通过二进制来进行存储、传输的。
一段数据,以二进制形式从一台计算机,通过网络,传输到另外一台计算机,必然需要双方遵守一些约定,以确保接收方做的事情与发送方的要求是一致的——这就是通信协议,如我们常见的http就是一种通信协议。


上篇结尾中说到,Server接收到请求之后,就转到ServerConnection来处理,ServerConnection就负责了对通信协议的解析,将不同的指令,转到相应的函数中处理。
HSQLDB支持3种协议:odbc、hsql_stream_protocal和http。下面通过源码来分析,这些协议在Hsqldb中是如何处理的,如果你清楚二进制协议是怎么回事,你大概可以略过这篇文章。

我们先看构造函数:

点击(此处)折叠或打开

  1. ServerConnection(Socket socket, Server server) {

  2.         RowOutputBinary rowOutTemp = new RowOutputBinary(mainBuffer);

  3.         rowIn = new RowInputBinary(rowOutTemp);
  4.         rowOut = rowOutTemp;

  5.         //
  6.         Thread runnerThread;

  7.         this.socket = socket;
  8.         this.server = server;
  9.         mThread = mCurrentThread.getAndIncrement();

  10.         synchronized (server.serverConnSet) {
  11.             server.serverConnSet.add(this);
  12.         }
  13.     }
其中的rowIn, rowOut,是用来读写数据的。
将socket对象和server对象都保存起来,并将客户端连接数增加1。

ServerConnection本身是实现了Runnable接口,也就是说ServerConnection的入口函数就是run方法

点击(此处)折叠或打开

  1. public void run() {

  2.         int msgType;

  3.         init();

  4.         if (session != null) {
  5.             try {
  6.                 while (keepAlive) {
  7.                     msgType = dataInput.readByte();

  8.                     if (msgType < ResultConstants.MODE_UPPER_LIMIT) {
  9.                         receiveResult(msgType);
  10.                     } else {
  11.                         receiveOdbcPacket((char) msgType);
  12.                     }
  13.                 }
  14.             } catch (CleanExit ce) {
  15.                 keepAlive = false;
  16.             } catch (IOException e) {

  17.                 // fredt - is thrown when connection drops
  18.                 server.printWithThread(mThread + ":disconnected " + user);
  19.             } catch (HsqlException e) {

  20.                 // fredt - is thrown in unforeseen circumstances
  21.                 if (keepAlive) {
  22.                     server.printStackTrace(e);
  23.                 }
  24.             } catch (Throwable e) {

  25.                 // fredt - is thrown in unforeseen circumstances
  26.                 if (keepAlive) {
  27.                     server.printStackTrace(e);
  28.                 }
  29.             }
  30.         }

  31.         close();
  32.     }
在这里,先是初始化init,然后一直处理客户端的数据receiveResult。我们先来看init,然后再看receiveResult。(知道init是怎样一个流程,则发现receiveResult也是差不多的)

点击(此处)折叠或打开

  1. private void init() {

  2.         runnerThread = Thread.currentThread();
  3.         keepAlive = true;

  4.         try {
  5.             socket.setTcpNoDelay(true);

  6.             dataInput = new DataInputStream(
  7.                 new BufferedInputStream(socket.getInputStream()));
  8.             dataOutput = new DataOutputStream(socket.getOutputStream());

  9.             int firstInt = handshake();

  10.             switch (streamProtocol) {

  11.                 case HSQL_STREAM_PROTOCOL :
  12.                     if (firstInt
  13.                             != ClientConnection
  14.                                 .NETWORK_COMPATIBILITY_VERSION_INT) {
  15.                         if (firstInt == -1900000) {
  16.                             firstInt = -2000000;
  17.                         }

  18.                         String verString =
  19.                             ClientConnection.toNetCompVersionString(firstInt);

  20.                         throw Error.error(
  21.                             null, ErrorCode.SERVER_VERSIONS_INCOMPATIBLE, 0,
  22.                             new String[] {
  23.                             verString, HsqlDatabaseProperties.THIS_VERSION
  24.                         });
  25.                     }

  26.                     Result resultIn = Result.newResult(dataInput, rowIn);

  27.                     resultIn.readAdditionalResults(session, dataInput, rowIn);

  28.                     Result resultOut;

  29.                     resultOut = setDatabase(resultIn);

  30.                     resultOut.write(session, dataOutput, rowOut);
  31.                     break;

  32.                 case ODBC_STREAM_PROTOCOL :
  33.                     odbcConnect(firstInt);
  34.                     break;

  35.                 default :

  36.                     // Protocol detection failures should already have been
  37.                     // handled.
  38.                     keepAlive = false;
  39.             }
  40.         } catch (Exception e) {

  41.             // Only "unexpected" failures are caught here.
  42.             // Expected failures will have been handled (by sending feedback
  43.             // to user-- with an output Result for normal protocols), then
  44.             // continuing.
  45.             StringBuffer sb = new StringBuffer(mThread
  46.                                                + ":Failed to connect client.");

  47.             if (user != null) {
  48.                 sb.append(" User '" + user + "'.");
  49.             }

  50.             server.printWithThread(sb.toString() + " Stack trace follows.");
  51.             server.printStackTrace(e);
  52.         }
  53.     }
通过在handshake函数中,读到的第一个字节的信息,取出了当前的通信协议,ServerConnection支持两种协议:odbc和HSQL_STREAM_PROTOCOL,值得注意的是,当使用HSQL_STREAM_PROTOCOL时,第一个字节值为当前协议版本号。
下面,我们将仅对HSQL_STREAM_PROTOCOL进行分析,因为odbc也是大同小异的。

当HSQL_STREAM_PROTOCOL版本号没有问题
,程序中使用Result对客户端与服务端的数据进行抽象,也就是客户端请求为一个Result,服务端响应也是一个Result。对于客户端发来的数据,在服务端就是read操作,要发往客户端的数据,就是write操作。

点击(此处)折叠或打开

  1. Result resultIn = Result.newResult(dataInput, rowIn);

  2. resultIn.readAdditionalResults(session, dataInput, rowIn);

  3. Result resultOut;

  4. resultOut = setDatabase(resultIn);

  5. resultOut.write(session, dataOutput, rowOut);
先初始化Result对象,我们知道一个协议中包含很多命令(也就是很多种请求),如:连接、断开连接、执行sql语句,每个命令还包含相应的参数,如执行sql语句,就要把sql语句传过来)。我们接下来就看newResult中是怎么处理的:


点击(此处)折叠或打开

  1. private static Result newResult(Session session, DataInput dataInput,
  2.                                     RowInputBinary in,
  3.                                     int mode)
  4.                                     throws IOException, HsqlException {

  5.         Result result = newResult(mode);
  6.         int length = dataInput.readInt();

  7.         in.resetRow(0, length);

  8.         byte[] byteArray = in.getBuffer();
  9.         final int offset = 4;

  10.         dataInput.readFully(byteArray, offset, length - offset);

  11.         switch (mode) {

  12.             case ResultConstants.GETSESSIONATTR :
  13.                 result.statementReturnType = in.readByte();
  14.                 break;

  15.             case ResultConstants.DISCONNECT :
  16.             case ResultConstants.RESETSESSION :
  17.             case ResultConstants.STARTTRAN :
  18.                 break;

  19.             case ResultConstants.PREPARE :
  20.                 result.setStatementType(in.readByte());

  21.                 result.mainString = in.readString();
  22.                 result.rsProperties = in.readByte();
  23.                 result.generateKeys = in.readByte();

  24.                 if (result.generateKeys == ResultConstants
  25.                         .RETURN_GENERATED_KEYS_COL_NAMES || result
  26.                         .generateKeys == ResultConstants
  27.                         .RETURN_GENERATED_KEYS_COL_INDEXES) {
  28.                     result.generatedMetaData = new ResultMetaData(in);
  29.                 }
  30.                 break;

  31.             case ResultConstants.CLOSE_RESULT :
  32.                 result.id = in.readLong();
  33.                 break;

  34.             case ResultConstants.FREESTMT :
  35.                 result.statementID = in.readLong();
  36.                 break;

  37.             case ResultConstants.EXECDIRECT :
  38.                 result.updateCount = in.readInt();
  39.                 result.fetchSize = in.readInt();
  40.                 result.statementReturnType = in.readByte();
  41.                 result.mainString = in.readString();
  42.                 result.rsProperties = in.readByte();
  43.                 result.queryTimeout = in.readShort();
  44.                 result.generateKeys = in.readByte();

  45.                 if (result.generateKeys == ResultConstants
  46.                         .RETURN_GENERATED_KEYS_COL_NAMES || result
  47.                         .generateKeys == ResultConstants
  48.                         .RETURN_GENERATED_KEYS_COL_INDEXES) {
  49.                     result.generatedMetaData = new ResultMetaData(in);
  50.                 }
  51.                 break;

  52.             case ResultConstants.CONNECT :
  53.                 result.databaseName = in.readString();
  54.                 result.mainString = in.readString();
  55.                 result.subString = in.readString();
  56.                 result.zoneString = in.readString();
  57.                 result.updateCount = in.readInt();
  58.                 break;

  59.             case ResultConstants.ERROR :
  60.             case ResultConstants.WARNING :
  61.                 result.mainString = in.readString();
  62.                 result.subString = in.readString();
  63.                 result.errorCode = in.readInt();
  64.                 break;

  65.             case ResultConstants.CONNECTACKNOWLEDGE :
  66.                 result.databaseID = in.readInt();
  67.                 result.sessionID = in.readLong();
  68.                 result.databaseName = in.readString();
  69.                 result.mainString = in.readString();
  70.                 break;

  71.             case ResultConstants.UPDATECOUNT :
  72.                 result.updateCount = in.readInt();
  73.                 break;

  74.             case ResultConstants.ENDTRAN : {
  75.                 int type = in.readInt();

  76.                 result.setActionType(type); // endtran type

  77.                 switch (type) {

  78.                     case ResultConstants.TX_SAVEPOINT_NAME_RELEASE :
  79.                     case ResultConstants.TX_SAVEPOINT_NAME_ROLLBACK :
  80.                         result.mainString = in.readString(); // savepoint name
  81.                         break;

  82.                     case ResultConstants.TX_COMMIT :
  83.                     case ResultConstants.TX_ROLLBACK :
  84.                     case ResultConstants.TX_COMMIT_AND_CHAIN :
  85.                     case ResultConstants.TX_ROLLBACK_AND_CHAIN :
  86.                     case ResultConstants.PREPARECOMMIT :
  87.                         break;

  88.                     default :
  89.                         throw Error.runtimeError(ErrorCode.U_S0500, "Result");
  90.                 }

  91.                 break;
  92.             }
  93.             case ResultConstants.SETCONNECTATTR : {
  94.                 int type = in.readInt(); // attr type

  95.                 result.setConnectionAttrType(type);

  96.                 switch (type) {

  97.                     case ResultConstants.SQL_ATTR_SAVEPOINT_NAME :
  98.                         result.mainString = in.readString(); // savepoint name
  99.                         break;

  100.                     // case ResultConstants.SQL_ATTR_AUTO_IPD :
  101.                     // - always true
  102.                     // default: throw - case never happens
  103.                     default :
  104.                         throw Error.runtimeError(ErrorCode.U_S0500, "Result");
  105.                 }

  106.                 break;
  107.             }
  108.             case ResultConstants.PREPARE_ACK :
  109.                 result.statementReturnType = in.readByte();
  110.                 result.statementID = in.readLong();
  111.                 result.rsProperties = in.readByte();
  112.                 result.metaData = new ResultMetaData(in);
  113.                 result.parameterMetaData = new ResultMetaData(in);
  114.                 break;

  115.             case ResultConstants.CALL_RESPONSE :
  116.                 result.updateCount = in.readInt();
  117.                 result.fetchSize = in.readInt();
  118.                 result.statementID = in.readLong();
  119.                 result.statementReturnType = in.readByte();
  120.                 result.rsProperties = in.readByte();
  121.                 result.metaData = new ResultMetaData(in);
  122.                 result.valueData = readSimple(in, result.metaData);
  123.                 break;

  124.             case ResultConstants.EXECUTE :
  125.                 result.updateCount = in.readInt();
  126.                 result.fetchSize = in.readInt();
  127.                 result.statementID = in.readLong();
  128.                 result.rsProperties = in.readByte();
  129.                 result.queryTimeout = in.readShort();

  130.                 Statement statement =
  131.                     session.statementManager.getStatement(session,
  132.                         result.statementID);

  133.                 if (statement == null) {

  134.                     // invalid statement
  135.                     result.mode = ResultConstants.EXECUTE_INVALID;
  136.                     result.valueData = ValuePool.emptyObjectArray;

  137.                     break;
  138.                 }

  139.                 result.statement = statement;
  140.                 result.metaData = result.statement.getParametersMetaData();
  141.                 result.valueData = readSimple(in, result.metaData);
  142.                 break;

  143.             case ResultConstants.UPDATE_RESULT : {
  144.                 result.id = in.readLong();

  145.                 int type = in.readInt();

  146.                 result.setActionType(type);

  147.                 result.metaData = new ResultMetaData(in);
  148.                 result.valueData = readSimple(in, result.metaData);

  149.                 break;
  150.             }
  151.             case ResultConstants.BATCHEXECRESPONSE :
  152.             case ResultConstants.BATCHEXECUTE :
  153.             case ResultConstants.BATCHEXECDIRECT :
  154.             case ResultConstants.SETSESSIONATTR : {
  155.                 result.updateCount = in.readInt();
  156.                 result.fetchSize = in.readInt();
  157.                 result.statementID = in.readLong();
  158.                 result.queryTimeout = in.readShort();
  159.                 result.metaData = new ResultMetaData(in);

  160.                 result.navigator.readSimple(in, result.metaData);

  161.                 break;
  162.             }
  163.             case ResultConstants.PARAM_METADATA : {
  164.                 result.metaData = new ResultMetaData(in);

  165.                 result.navigator.read(in, result.metaData);

  166.                 break;
  167.             }
  168.             case ResultConstants.REQUESTDATA : {
  169.                 result.id = in.readLong();
  170.                 result.updateCount = in.readInt();
  171.                 result.fetchSize = in.readInt();

  172.                 break;
  173.             }
  174.             case ResultConstants.DATAHEAD :
  175.             case ResultConstants.DATA :
  176.             case ResultConstants.GENERATED : {
  177.                 result.id = in.readLong();
  178.                 result.updateCount = in.readInt();
  179.                 result.fetchSize = in.readInt();
  180.                 result.rsProperties = in.readByte();
  181.                 result.metaData = new ResultMetaData(in);
  182.                 result.navigator = new RowSetNavigatorClient();

  183.                 result.navigator.read(in, result.metaData);

  184.                 break;
  185.             }
  186.             case ResultConstants.DATAROWS : {
  187.                 result.metaData = new ResultMetaData(in);
  188.                 result.navigator = new RowSetNavigatorClient();

  189.                 result.navigator.read(in, result.metaData);

  190.                 break;
  191.             }
  192.             default :
  193.                 throw Error.runtimeError(ErrorCode.U_S0500, "Result");
  194.         }

  195.         return result;
  196.     }
在一个二进制内容的协议中,字节摆放的先后顺序是严格要求的,这点与一些字符串协议有着区别(如http中,"url?p1=&p2=",与"url?p2=&p1=" 在服务器上的处理并无任何区别)
在不同的命令(请求)中,协议严格规定了字节的先后摆放顺序,以prepare命令来说

点击(此处)折叠或打开

  1. case ResultConstants.PREPARE :
  2.                 result.setStatementType(in.readByte());

  3.                 result.mainString = in.readString();
  4.                 result.rsProperties = in.readByte();
  5.                 result.generateKeys = in.readByte();

  6.                 if (result.generateKeys == ResultConstants
  7.                         .RETURN_GENERATED_KEYS_COL_NAMES || result
  8.                         .generateKeys == ResultConstants
  9.                         .RETURN_GENERATED_KEYS_COL_INDEXES) {
  10.                     result.generatedMetaData = new ResultMetaData(in);
  11.                 }
  12.                 break;
在命令标识字节之后,第1个字节为statementType, 第2段为执行的sql语句,sql语句之后为rsProperties,后面依此类推。
in.readByte之类的,都很平常,不过是InputStream往前读了一个字节。
我们感兴趣的是readString,我们知道一个sql语句是不定长的,那么in.readString怎么知道该读多长的内容作为字符串呢?
进入到readString方法中一窥究竟

点击(此处)折叠或打开

  1. public String readString() throws IOException {

  2.         int length = readInt();
  3.         String s = StringConverter.readUTF(buffer, pos, length);

  4.         s = ValuePool.getString(s);
  5.         pos += length;

  6.         return s;
  7.     }
原来,对于每一个字符串,在其开头部分,先是放置一个int,告知后面字符串长度,然后接下来这么长的内容是字符串的内容。这在二进制协议中,对于不定长数据通常的一个手法。
这里还有一个ValuePool.getString方法,进入之后好像是做缓存计数器,具体做什么用,我还不清楚。

现在我们再回到上面init函数部分,看看

点击(此处)折叠或打开

  1. Result resultOut;

  2.                     resultOut = setDatabase(resultIn);

  3.                     resultOut.write(session, dataOutput, rowOut);
setDatabase是服务器端的处理,我们这里先略过,在这篇文章里,我们关注的是数据如何解析(上面已经知道),数据是如何返回的。
write函数如下:

点击(此处)折叠或打开

  1. public void write(SessionInterface session, DataOutputStream dataOut,
  2.                       RowOutputInterface rowOut)
  3.                       throws IOException, HsqlException {

  4.         rowOut.reset();
  5.         rowOut.writeByte(mode);

  6.         int startPos = rowOut.size();

  7.         rowOut.writeSize(0);

  8.         switch (mode) {

  9.             case ResultConstants.GETSESSIONATTR :
  10.                 rowOut.writeByte(statementReturnType);
  11.                 break;

  12.             case ResultConstants.DISCONNECT :
  13.             case ResultConstants.RESETSESSION :
  14.             case ResultConstants.STARTTRAN :
  15.                 break;

  16.             case ResultConstants.PREPARE :
  17.                 rowOut.writeByte(statementReturnType);
  18.                 rowOut.writeString(mainString);
  19.                 rowOut.writeByte(rsProperties);
  20.                 rowOut.writeByte(generateKeys);

  21.                 if (generateKeys == ResultConstants
  22.                         .RETURN_GENERATED_KEYS_COL_NAMES || generateKeys == ResultConstants
  23.                         .RETURN_GENERATED_KEYS_COL_INDEXES) {
  24.                     generatedMetaData.write(rowOut);
  25.                 }
  26.                 break;

  27.             case ResultConstants.FREESTMT :
  28.                 rowOut.writeLong(statementID);
  29.                 break;

  30.             case ResultConstants.CLOSE_RESULT :
  31.                 rowOut.writeLong(id);
  32.                 break;

  33.             case ResultConstants.EXECDIRECT :
  34.                 rowOut.writeInt(updateCount);
  35.                 rowOut.writeInt(fetchSize);
  36.                 rowOut.writeByte(statementReturnType);
  37.                 rowOut.writeString(mainString);
  38.                 rowOut.writeByte(rsProperties);
  39.                 rowOut.writeShort(queryTimeout);
  40.                 rowOut.writeByte(generateKeys);

  41.                 if (generateKeys == ResultConstants
  42.                         .RETURN_GENERATED_KEYS_COL_NAMES || generateKeys == ResultConstants
  43.                         .RETURN_GENERATED_KEYS_COL_INDEXES) {
  44.                     generatedMetaData.write(rowOut);
  45.                 }
  46.                 break;

  47.             case ResultConstants.CONNECT :
  48.                 rowOut.writeString(databaseName);
  49.                 rowOut.writeString(mainString);
  50.                 rowOut.writeString(subString);
  51.                 rowOut.writeString(zoneString);
  52.                 rowOut.writeInt(updateCount);
  53.                 break;

  54.             case ResultConstants.ERROR :
  55.             case ResultConstants.WARNING :
  56.                 rowOut.writeString(mainString);
  57.                 rowOut.writeString(subString);
  58.                 rowOut.writeInt(errorCode);
  59.                 break;

  60.             case ResultConstants.CONNECTACKNOWLEDGE :
  61.                 rowOut.writeInt(databaseID);
  62.                 rowOut.writeLong(sessionID);
  63.                 rowOut.writeString(databaseName);
  64.                 rowOut.writeString(mainString);
  65.                 break;

  66.             case ResultConstants.UPDATECOUNT :
  67.                 rowOut.writeInt(updateCount);
  68.                 break;

  69.             case ResultConstants.ENDTRAN : {
  70.                 int type = getActionType();

  71.                 rowOut.writeInt(type); // endtran type

  72.                 switch (type) {

  73.                     case ResultConstants.TX_SAVEPOINT_NAME_RELEASE :
  74.                     case ResultConstants.TX_SAVEPOINT_NAME_ROLLBACK :
  75.                         rowOut.writeString(mainString); // savepoint name
  76.                         break;

  77.                     case ResultConstants.TX_COMMIT :
  78.                     case ResultConstants.TX_ROLLBACK :
  79.                     case ResultConstants.TX_COMMIT_AND_CHAIN :
  80.                     case ResultConstants.TX_ROLLBACK_AND_CHAIN :
  81.                     case ResultConstants.PREPARECOMMIT :
  82.                         break;

  83.                     default :
  84.                         throw Error.runtimeError(ErrorCode.U_S0500, "Result");
  85.                 }

  86.                 break;
  87.             }
  88.             case ResultConstants.PREPARE_ACK :
  89.                 rowOut.writeByte(statementReturnType);
  90.                 rowOut.writeLong(statementID);
  91.                 rowOut.writeByte(rsProperties);
  92.                 metaData.write(rowOut);
  93.                 parameterMetaData.write(rowOut);
  94.                 break;

  95.             case ResultConstants.CALL_RESPONSE :
  96.                 rowOut.writeInt(updateCount);
  97.                 rowOut.writeInt(fetchSize);
  98.                 rowOut.writeLong(statementID);
  99.                 rowOut.writeByte(statementReturnType);
  100.                 rowOut.writeByte(rsProperties);
  101.                 metaData.write(rowOut);
  102.                 writeSimple(rowOut, metaData, (Object[]) valueData);
  103.                 break;

  104.             case ResultConstants.EXECUTE :
  105.                 rowOut.writeInt(updateCount);
  106.                 rowOut.writeInt(fetchSize);
  107.                 rowOut.writeLong(statementID);
  108.                 rowOut.writeByte(rsProperties);
  109.                 rowOut.writeShort(queryTimeout);
  110.                 writeSimple(rowOut, metaData, (Object[]) valueData);
  111.                 break;

  112.             case ResultConstants.UPDATE_RESULT :
  113.                 rowOut.writeLong(id);
  114.                 rowOut.writeInt(getActionType());
  115.                 metaData.write(rowOut);
  116.                 writeSimple(rowOut, metaData, (Object[]) valueData);
  117.                 break;

  118.             case ResultConstants.BATCHEXECRESPONSE :
  119.             case ResultConstants.BATCHEXECUTE :
  120.             case ResultConstants.BATCHEXECDIRECT :
  121.             case ResultConstants.SETSESSIONATTR : {
  122.                 rowOut.writeInt(updateCount);
  123.                 rowOut.writeInt(fetchSize);
  124.                 rowOut.writeLong(statementID);
  125.                 rowOut.writeShort(queryTimeout);
  126.                 metaData.write(rowOut);
  127.                 navigator.writeSimple(rowOut, metaData);

  128.                 break;
  129.             }
  130.             case ResultConstants.PARAM_METADATA : {
  131.                 metaData.write(rowOut);
  132.                 navigator.write(rowOut, metaData);

  133.                 break;
  134.             }
  135.             case ResultConstants.SETCONNECTATTR : {
  136.                 int type = getConnectionAttrType();

  137.                 rowOut.writeInt(type); // attr type / updateCount

  138.                 switch (type) {

  139.                     case ResultConstants.SQL_ATTR_SAVEPOINT_NAME :
  140.                         rowOut.writeString(mainString); // savepoint name
  141.                         break;

  142.                     // case ResultConstants.SQL_ATTR_AUTO_IPD // always true
  143.                     // default: // throw, but case never happens
  144.                     default :
  145.                         throw Error.runtimeError(ErrorCode.U_S0500, "Result");
  146.                 }

  147.                 break;
  148.             }
  149.             case ResultConstants.REQUESTDATA : {
  150.                 rowOut.writeLong(id);
  151.                 rowOut.writeInt(updateCount);
  152.                 rowOut.writeInt(fetchSize);

  153.                 break;
  154.             }
  155.             case ResultConstants.DATAROWS :
  156.                 metaData.write(rowOut);
  157.                 navigator.write(rowOut, metaData);
  158.                 break;

  159.             case ResultConstants.DATAHEAD :
  160.             case ResultConstants.DATA :
  161.             case ResultConstants.GENERATED :
  162.                 rowOut.writeLong(id);
  163.                 rowOut.writeInt(updateCount);
  164.                 rowOut.writeInt(fetchSize);
  165.                 rowOut.writeByte(rsProperties);
  166.                 metaData.write(rowOut);
  167.                 navigator.write(rowOut, metaData);
  168.                 break;

  169.             default :
  170.                 throw Error.runtimeError(ErrorCode.U_S0500, "Result");
  171.         }

  172.         rowOut.writeIntData(rowOut.size() - startPos, startPos);
  173.         dataOut.write(rowOut.getOutputStream().getBuffer(), 0, rowOut.size());

  174.         int count = getLobCount();
  175.         Result current = this;

  176.         for (int i = 0; i < count; i++) {
  177.             ResultLob lob = current.lobResults;

  178.             lob.writeBody(session, dataOut);

  179.             current = current.lobResults;
  180.         }

  181.         if (chainedResult == null) {
  182.             dataOut.writeByte(ResultConstants.NONE);
  183.         } else {
  184.             chainedResult.write(session, dataOut, rowOut);
  185.         }

  186.         dataOut.flush();
  187.     }
与newResult差不多,之前是逐个位置的读数据,现在是逐个位置的写入数据。跟不同的命令/请求需要用不同的读方法一样,写入内容时,也是根据命令/请求内容的不同,写入不同的数据。
writeByte之类的比较容易理解,我们这里同样关注一下writeString


点击(此处)折叠或打开

  1. public void writeString(String s) {

  2.         int temp = count;

  3.         writeInt(0);

  4.         if (s != null && s.length() != 0) {
  5.             StringConverter.stringToUTFBytes(s, this);
  6.             writeIntData(count - temp - INT_STORE_SIZE, temp);
  7.         }
  8.     }
这里先writeInt(0), 这个位置其实起到占位作用,因为这个位置本身需要写入字符串的长度。然后再写入字符串内容,之后再返回到长度的写入位置,写入真实的长度。

[总结]
至此,我们通过分析ServerConnection和Result,得知了HSQL_Stream_Protocol的解析和返回过程。作为二进制协议,在写代码之前是应该有文档规定的,文档的内容就是什么内容,存在协议的什么位置。当然,通过源代码,我们也可以逆推出文档。

协议解析出来了,处理之后也返回回去了,在它们之间存在一个处理过程,在下一篇文章中将对处理过程进行分析。

[相关源码文件]
ServerConnection.java
WebServerConnection.java
result目录(Result.java在此目录中)
rowio目录(字节读写就靠这个)

[思考]
命令/请求与回复/响应,都在Result里,是因为各种命令的参数信息、响应的返回的内容,基本类似,如果各种命令的参数差别极大(比如一个命令有100项参数信息,另一个命令只有1项参数),这样的情况下,都放在Result里还合适吗?或者,阅读源码,在Result能找到处理办法吗?
阅读(4133) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:HSQLDB源码阅读 (三)命令的处理

给主人留下些什么吧!~~