简体   繁体   中英

Null pointer exception occurs while trying to read repeatedly from an InputStream

The code works fine when I close the client just after sending one instruction. But when I want a client and server connection to persist, so that the client can send multiple instructions to the server one after another, I get a Null pointer exception at the server and the message java.net.SocketException: Socket is closed at the client. This happens after the client sends a file to the server and the server successfully receives it. Need help. The error occurs at the Connection class code line switch(clientMsg) . It seems to me that for some reason the BufferedReader in goes null , but I might be mistaken about that. The code is as follows. Thanks.

Server

public class server {
private static ServerSocket serverSocket;
private static Socket socket = null;

public static void print(Object s) {
    System.out.println(s);
}


@SuppressWarnings("resource")
public static void main (String args[]) throws IOException {
    System.out.print("Specify listening port: ");
    Scanner _a = new Scanner(System.in);
    int a = _a.nextInt();
    try{
        serverSocket = new ServerSocket(a);
    }
    catch(IOException e) {
        System.out.println(e);
    }

    while (true) {
        try {
            socket = serverSocket.accept();
            print("Connected to " + socket);

            Thread client = new Thread(new Connection(socket));
            client.start();
        }
        catch (IOException e) {
            print(e);
        }
    }

}

}

Connection

public class Connection implements Runnable {

public static void print(Object s) {
    System.out.println(s);
}

private Socket socket;
private BufferedReader in = null;

public Connection(Socket client) {
    this.socket = client;
}

@Override
public void run(){
    try {
        in = new BufferedReader(new InputStreamReader(
                socket.getInputStream()));

        String clientMsg;
        while (true) {
            clientMsg = in.readLine();
            switch (clientMsg) {
            case "1":
                receiveFile(); //method code not included
                break;

            default:
                print("Command not recognized");
                break;
            }
            //in.close();
        }

    }//try run()
    catch (IOException e) {
        print(e);
    }
}

Client

public class client {
private static Socket connectToServer;
private static String fileName;
private static BufferedReader keybrdIn;
private static PrintStream msgToServer;

public static void println(Object e) {
    System.out.println(e);
}

public static void print(Object e) {
    System.out.print(e);
}

public static void main(String args[]) throws IOException{
    try{
        print("Enter IP: ");
        String ip = new Scanner(System.in).nextLine();          
        print("Enter port: ");
        int port = new Scanner(System.in).nextInt();
        connectToServer = new Socket(ip, port);
        keybrdIn = new BufferedReader(new InputStreamReader(System.in));
    }catch(IOException e) {
        println(e);
    }

    msgToServer = new PrintStream(connectToServer.getOutputStream());

    while (true) {
        try {
            switch(Integer.parseInt(action())) { //action() method code not included
            case 1:
                msgToServer.println("1");
                sendFile();
                break;
            default:
                println("Invalid input");
                break;
            }
        }catch (IOException e) {
            println(e);
        }
    }
}

sendFile()

public static void sendFile() throws IOException {
    print("Enter file name: ");
    fileName = keybrdIn.readLine();

    File file = new File(fileName);

    byte[] bytearray = new byte[8192];
    FileInputStream fis = new FileInputStream(file);
    BufferedInputStream bis = new BufferedInputStream(fis);
    DataInputStream dis = new DataInputStream(bis);
    OutputStream os = connectToServer.getOutputStream();
    DataOutputStream dos = new DataOutputStream(os);
    dos.writeUTF(file.getName());
    int count;
    while ((count = dis.read(bytearray)) > 0){
        dos.write(bytearray, 0, count);
    }
    dis.close();
    dos.flush();
    dos.close();
}

receiveFile()

public void receiveFile() {
    try {
        int count;

        DataInputStream clientFileStream = new DataInputStream(socket.getInputStream());

        String fileName = clientFileStream.readUTF();
        OutputStream fileOutput = new FileOutputStream("_" + fileName);

        byte[] mybytearray = new byte[8192];
        BufferedOutputStream bos = new BufferedOutputStream(fileOutput);

        System.out.println("Downloading " + fileName + " ...");
        //outToClient().writeBytes("Uploading. Please wait...\n");
        while ((count = clientFileStream.read(mybytearray)) > 0){
            bos.write(mybytearray, 0, count);
        }
        fileOutput.close();
        bos.close();
        clientFileStream.close();

    }
    catch (IOException e) {
        print(e);
    }
}

In sendFile(), you close the data output stream which closes your underlying connection's output stream.

According to the documentation of Socket.getOutputStream():

"Closing the returned OutputStream will close the associated socket".

Since you already closed stream, it will also close socket as well as Eyal mentioned. However, at the moment you close the stream, server side will aware of that and return -1 for read() results. So, even if you didn't specify file length at beginning, this will generally works well.

However, since you already closed stream, you can't reuse it no matter what. To fix this issue, probably you need to change your Client class so that Client should create socket connection, send files, close socket. That's one lifecycle of opened client socket.

Or maybe in while loop of Client class, 1) take ip, port, and filename to send 2) Create new Thread and provide those information so let thread open connection, send file, close connection 3) and in the meantime, client while() can keep take next ip, port, and filename to send from the user. By doing this, you don't need to make client program wait until file transfer to be completed.

Regarding the NPE in the server, readLine() returns null at end of stream. You are ignoring it. You should be testing for it immediately after the call, and if null close the socket and exit the read loop.

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