简体   繁体   English

尝试从InputStream重复读取时发生空指针异常

[英]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. 但是当我希望客户端和服务器连接保持不变时,客户端可以一个接一个地向服务器发送多个指令,我在服务器上得到一个Null指针异常,并且消息java.net.SocketException: Socket is closed在客户。 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) . Connection类代码行switch(clientMsg)发生错误。 It seems to me that for some reason the BufferedReader in goes null , but I might be mistaken about that. 在我看来,由于某些原因的BufferedReader innull ,但我可能是弄错了这一点。 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() 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. 在sendFile()中,关闭数据输出流,关闭底层连接的输出流。

According to the documentation of Socket.getOutputStream(): 根据Socket.getOutputStream()的文档:

"Closing the returned OutputStream will close the associated socket". “关闭返回的OutputStream将关闭相关的套接字”。

Since you already closed stream, it will also close socket as well as Eyal mentioned. 由于你已经关闭了流,它也将关闭套接字以及Eyal提到的。 However, at the moment you close the stream, server side will aware of that and return -1 for read() results. 但是,在关闭流时,服务器端将知道这一点并返回-1以获取read()结果。 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. 要解决此问题,可能需要更改Client类,以便Client应创建套接字连接,发送文件,关闭套接字。 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. 或者也许在Client类的while循环中,1)取ip,port和filename发送2)创建新的Thread并提供这些信息让线程打开连接,发送文件,关闭连接3)同时,客户端(同时) )可以保持从用户发送下一个ip,port和filename。 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. 关于服务器中的NPE,readLine()在流结束时返回null。 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. 您应该在调用后立即对其进行测试,如果为null则关闭套接字并退出读取循环。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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