有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我正在尝试连接到PostgreSQL服务器(实现wire协议),但我不知道如何动态生成字节数组的消息帧。例如,在下面的代码中,我做了很多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) 个答案

  1. # 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.这太愚蠢了。打印异常

  2. # 2 楼答案

    试试这个

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