DataOutputStream 仅在 System.out.println 之前有效

DataOutputStream works only preceded by System.out.println

我在 input/output 流中遇到了另一个问题。在这里,我将数据从服务器发送到客户端。在发送数据之前,服务器发送一个小字符串来告诉客户端他将发送什么,这样客户端就知道他应该使用哪个函数来接收。

我很好地接收了第一个字符串,但后来我没有得到正确的整数,之后我收到的第二个字符串是 "null"。

此外,如果我在将 DataOutputStream 与 dos.writeInt 一起使用之前执行 System.out.println,则一切正常。 我不明白。这是代码:

服务器:

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.SecureRandom;


public class Server {

    private static OutputStream out;

    static byte[] generateRandomBytes(int len) {
        SecureRandom random = new SecureRandom();
        byte[] bytes = new byte[len];
        random.nextBytes(bytes);
        return bytes;
    }

    public static void sendType(String type) {
        PrintWriter textWriter = new PrintWriter(out);
        textWriter.println(type);
        textWriter.flush();
    }

    public static void sendKeyNumber(int keyNumber) {
        sendType("keyNumber");
        try {
            DataOutputStream dos = new DataOutputStream(out);
            //System.out.println("Sending key number: " + keyNumber);
            dos.writeInt(keyNumber);
            //dos.flush();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
    }

    public static void sendKey(byte[] key) {
        sendType("key");
        try {
            DataOutputStream dos = new DataOutputStream(out);
            //System.out.println("key length to send: " +key.length);
            dos.writeInt(key.length); // write length of the byte array
            //dos.flush();
            dos.write(key);
            //dos.flush();
            System.out.println("key send: " +key);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Socket clientSocket ;        
        System.out.println("ouverture du server");
        try {
            ServerSocket serverSocket = new ServerSocket(2004);
            clientSocket = serverSocket.accept(); 
            out = clientSocket.getOutputStream();

            sendKeyNumber(0);
            byte[] keyBytes = generateRandomBytes(32);
            sendKey(keyBytes);

            clientSocket.close();


        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

客户:

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.crypto.spec.SecretKeySpec;



public class Main {

    static InputStream in;

    public static int receiveKeyNumber() {
        DataInputStream dis = new DataInputStream(in);
        int keyNumber = 0;
        try {
            keyNumber = dis.readInt();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return keyNumber;
    }

    public static SecretKeySpec receiveKey() {
        DataInputStream dIn = new DataInputStream(in);
        int length;
        byte[] keyBytes = null;
        try {
            length = dIn.readInt();                   // read length of incoming message
            System.out.println("key length: " + length);
            if(length!=32) {
                System.err.println("Incorrect size for key: "+ length);
            }       
            else {
                keyBytes = new byte[length];
                dIn.readFully(keyBytes, 0, keyBytes.length); 
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } 
        SecretKeySpec aesKey = new SecretKeySpec(keyBytes, "AES");
        return aesKey;
    }


    public static void main(String[] args) {

        Socket clientSocket;
        try {
            clientSocket = new Socket(InetAddress.getLocalHost(),2004);

            in = clientSocket.getInputStream();
            while(!clientSocket.isClosed()) {
                BufferedReader textReader = new BufferedReader(new InputStreamReader(in));
                String type = textReader.readLine();
                System.out.println(type);

                if(type.equals("keyNumber")) {
                    int KN = receiveKeyNumber();
                    System.out.println(KN);
                }

                if(type.equals("key")) {
                    SecretKeySpec key = receiveKey();
                    System.out.println(key);
                }
            }

            clientSocket.close();

        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }       
    }
}

这是我不执行 System.out.println 时(在客户端控制台中)得到的结果:

keyNumber
1801812234

null

我总是得到同样奇怪的数字;我尝试将其转换为 ASCII,但它不可读。

有什么建议吗?

在发送二进制数据的情况下,请完全使用 DataOutputStream。 (或者你可以去文本。)

private static DataOutputStream out;

out = new DataOutputStream(clientSocket.getOutputStream());

public static void sendType(String type) {
    out.writeUTF(type);
    out.flush();
}

刷新对于二元对话很重要。

包装 类 DataOutputStream、Printer、BufferedReader 等的问题在于它们会启动自己的 "cursor" 并会在自己关闭时关闭包装的 I/O。拥有多个 DataOutputStreams 有点令人担忧;至少不是预期的那样。

顺便说一下,我的正常模式是 main: new Server().exec(); 之类的。 这将消除所有这些静电。