上一节是收到了欢迎语,下面开始验证阶段。
=================================
首先上代码
@Override
public byte[] toByteArray() throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int clientCapabilities = this.clientCapabilities;
if (clientCapabilities == 0) {
clientCapabilities = ClientCapabilities.LONG_FLAG |
ClientCapabilities.PROTOCOL_41 | ClientCapabilities.SECURE_CONNECTION;
if (schema != null) {
clientCapabilities |= ClientCapabilities.CONNECT_WITH_DB;
}
}
buffer.writeInteger(clientCapabilities, 4);
buffer.writeInteger(0, 4); // maximum packet length
buffer.writeInteger(collation, 1);
for (int i = 0; i < 23; i++) {
buffer.write(0);
}
buffer.writeZeroTerminatedString(username);
byte[] passwordSHA1 = "".equals(password) ? new byte[0] : passwordCompatibleWithMySQL411(password, salt);
buffer.writeInteger(passwordSHA1.length, 1);
buffer.write(passwordSHA1);
if (schema != null) {
buffer.writeZeroTerminatedString(schema);
}
return buffer.toByteArray();
}
===
具体解释如下:
长度作为3个字节写出,小端模式
然后后面跟1个字节的值,为1或者0,验证命令为1,其它为0.
然后开始写具体的一些内容如下:
clientCapabilities: 4个字节,小端模式
packet最大长度:4个字节,可以为0
collation:占1个字节。
然后写23个0,占23个字节,估计是保留位
用户名,以\0结束。
密码:密码分为2部分,长度先作为一个字节写出去,后面跟具体密码。
空密码为new byte[0].
否则需要做一个函数转换,具体代码如下:
/**
* see mysql/sql/password.c scramble(...)
*/
private static byte[] passwordCompatibleWithMySQL411(String password, String salt) {
MessageDigest sha;
try {
sha = MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
byte[] passwordHash = sha.digest(password.getBytes());
return xor(passwordHash, sha.digest(union(salt.getBytes(), sha.digest(passwordHash))));
}
======至此,发送验证命令完毕,下面开始读取响应。
这部分比较简单
1)3个字节,小端模式,表明长度
2)跳过1个字节的序列号
3)读取对应的值,值的第一个字节为0表示验证成功。0XFF表示错误,其它为未知异常。
这部分简单,不赘述。