我正在尝试连接到PostgreSQL服务器(实现有线协议),但我无法弄清楚如何动态生成字节数组的消息帧。例如,在下面的代码中,我正在进行大量的System.arraycopy
调用,将所有生成的字节推送到单个字节数组中,似乎必须有更好的方法。
import java.io.*;
import java.net.Socket;
import java.nio.ByteBuffer;
public class Connection {
public void connect(String hostName, int port) {
try {
Socket dbSocket = new Socket(hostName, port);
DataOutputStream dOut = new DataOutputStream(dbSocket.getOutputStream());
byte[] message = buildStartupMessage("sa");
dOut.write(message);
DataInputStream dIn = new DataInputStream(dbSocket.getInputStream());
byte bytes;
while((bytes = dIn.readByte()) != 0) {
System.out.println(bytes);
}
} catch(Exception e) {
System.out.println("Got an exception");
}
}
public byte[] buildStartupMessage(String username) {
// Postgres startup message format:
// 32 bit length
// 32 bit protocol
// string name
// null byte
// string value
// null byte
byte nullbyte = 0;
byte[] valbytes = username.getBytes();
byte[] namebytes = "user".getBytes();
System.out.println("number of bytes for sa is: " + valbytes.length);
int length = 4 + 4 + valbytes.length + namebytes.length + 2;
byte[] lengthbytes = ByteBuffer.allocate(4).putInt(length).array();
byte[] protocolbytes = ByteBuffer.allocate(4).putInt(3).array();
byte[] startupmessage = new byte[length];
int currIndex = 0;
System.arraycopy(lengthbytes, 0, startupmessage, currIndex, lengthbytes.length);
currIndex += lengthbytes.length;
System.arraycopy(protocolbytes, 0, startupmessage, currIndex, protocolbytes.length);
currIndex += protocolbytes.length;
System.arraycopy(namebytes, 0, startupmessage, currIndex, namebytes.length);
currIndex += namebytes.length;
startupmessage[currIndex] = nullbyte;
currIndex++;
System.arraycopy(valbytes, 0, startupmessage, currIndex, valbytes.length);
currIndex += valbytes.length;
startupmessage[currIndex] = nullbyte;
return startupmessage;
}
public static void main(String[] args) {
Connection conn = new Connection();
conn.connect("localhost", 5432);
}
}
答案 0 :(得分:1)
别。使用DataOutputStream
的原语直接写出你想要的东西。例如:
dos.writeInt(length); // total length
dos.writeInt(3); // protocol
dos.writeBytes("user");
dos.writeByte(0); // null terminator
dos.writeBytes(username); // username
dos.writeByte(0); // null terminator
...根据协议,通过DataInputStream
阅读时反过来。将缓冲流放在数据流下以节省系统调用。
但是......真正的问题是'为什么'?您当然应该使用PostgresSQL JDBC驱动程序与服务器通信,而不是尝试自己滚动整个协议。供应商已经为您完成了这项工作。不要这样做。
注意当你遇到异常时,不要打印Got an exception.
它是asinine。打印例外。
答案 1 :(得分:0)
试试这个。
public byte[] buildStartupMessage(String username) {
ByteBuffer b = ByteBuffer.allocate(100);
b .putInt(0) // length (dummy)
.putInt(3) // protocol
.put("user".getBytes()) // name
.put((byte)0) // null byte
.put(username.getBytes()) // val
.put((byte)0); // null byte
int length = b.position();
b.rewind();
b.putInt(length); // length (actual)
byte[] r = new byte[length];
b.rewind();
b.get(r, 0, length); // copy to byte array
return r;
}