如何生成字节数组以通过网络在Java中发送数据

时间:2016-01-16 04:05:10

标签: java network-programming

我正在尝试连接到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);
    }
}

2 个答案:

答案 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;
}