简体   繁体   中英

DataOutputStream works only preceded by System.out.println

I got another problem with input/output streams. Here i'm sending data from a server to a client. Before sending the data, the server send a little string just to say to the client what he'll send, and so the client know which function he should use to receive.

I'm receiving the first string well, but then i don't get the good integer and after that the second string i receive is "null".

Moreover, if i do a System.out.println before using the DataOutputStream with dos.writeInt, then everything works well. I dont get it. here's the code:

Server:

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

Client:

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

End here's what i get (in Client console) when i don't do the System.out.println:

keyNumber
1801812234

null

I always get the same weird number; i've try to convert it to ASCII, but it's not readable.

Any suggestion?

In this case where binary data is sent, go entirely for DataOutputStream. (Alternatively you could go for text.)

private static DataOutputStream out;

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

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

Flushing is important with binary conversations.

The problem with wrapping classes DataOutputStream, Printer, BufferedReader and such is that they start their own "cursor" and would close the wrapped I/O on their own closing. Having several DataOutputStreams is somewhat worrying; at least not as intended.

By the way my normal pattern is to do in main : new Server().exec(); or such. That would remove all those statics.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM