如何在线程“主” java.io.EOFException中修复异常? (Java套接字)

时间:2019-07-08 18:58:44

标签: java sockets file-handling

我想使用Java套接字创建一个简单的多文件传输程序。

服务器输出:

I am server
The server is listening...
Client are connected
Files Selected : 2
README.txt
vcruntime140.dll
Server Closed!

客户端输出:

i am client
Server are connected
filecount : 2
filenames : README.txt
     

线程“ main”中的异常java.io.EOFException在    java.io.DataInputStream.readFully(未知源)   java.io.DataInputStream.readLong(未知源),位于   socket.client.main(client.java:32)

这是我的服务器代码!服务器是发件人。

public static void main(String[] args) throws Exception {

    System.out.println("i am server");
    System.out.println("");
    server = new ServerSocket(12345);
    System.out.println("Server is listening...");
    client = server.accept();
    System.out.println("Client are connected");
    dos = new DataOutputStream(client.getOutputStream());


    dir = "C:\\Users\\Nitesh Rathi\\Downloads\\vcruntime140";
    files = new File(dir).listFiles();
    System.out.println("Files Selected : " + files.length);

    dos.writeInt(files.length);

    byte[] b = new byte[4096];

    for (File file : files)
    {
        long length = file.length();
        dos.writeLong(length);

        String filename = file.getName();
        dos.writeUTF(filename);

        System.out.println(file.getName());
        fis = new FileInputStream(file);

        while (fis.read(b) != -1)
        {
            fis.read(b, 0, b.length);
            dos.write(b, 0, b.length);
        }
    }

    System.out.println("");
    fis.close();
    client.close();
    server.close();
    System.out.println("Server Closed!");
}

这是我的客户代码!客户是接收者。

public static void main(String[] args) throws Exception {

    System.out.println("i am client");
    System.out.println("");
    soc = new Socket("localhost", 12345);
    System.out.println("Server are connected");
    dis = new DataInputStream(soc.getInputStream());

    int filecount = dis.readInt();
    File[] files = new File[filecount];

    System.out.println("filecount : " + filecount);
    byte[] b = new byte[1024];

    for (int i=0;i<filecount;i++)
    {
        long filelength = dis.readLong();
        String filename = dis.readUTF();
        System.out.println("filenames : "+filename);

        files[i] = new File(dirPath + "/" + filename);
        fos = new FileOutputStream(files[i]);

        for(int j = 0; j < filelength; j++)
        {
            fos.write(b);
            dis.read(b);
        }

    }

    System.out.println("data received!");

    fos.flush();
    fos.close();
    soc.close();

    System.out.println("client closed!");
}

我希望客户端的输出如下: 文件数:2 文件名:README.txt vcruntime140.dll

2 个答案:

答案 0 :(得分:1)

在服务器端,您每次从输入文件流读取时,每次循环迭代都两次调用fis.read()。您每次迭代仅需要调用一次,并且需要将fis.read()的返回值传递给dos.write(),以便它知道要写入的正确字节数。

在客户端,在读取文件流时,您正在调用fos.write(),然后才调用dis.read()用数据填充b。而且您循环了很多次,因为您没有使用每次迭代实际读取的字节数来更新j循环计数器。

请尝试以下类似操作:

服务器:

public static void main(String[] args) throws Exception
{
    System.out.println("i am server");
    System.out.println("");

    ServerSocket server = new ServerSocket(12345);
    System.out.println("Server is listening...");

    Socket client = server.accept();
    System.out.println("Client is connected");

    DataOutputStream dos = new DataOutputStream(client.getOutputStream());

    String dir = "C:\\Users\\Nitesh Rathi\\Downloads\\vcruntime140";
    Files[] files = new File(dir).listFiles();

    System.out.println("Files Selected : " + files.length);
    dos.writeInt(files.length);

    byte[] b = new byte[4096];

    for (File file : files)
    {
        long filelength = file.length();
        dos.writeLong(filelength);

        String filename = file.getName();
        dos.writeUTF(filename);
        System.out.println(filename);

        FileInputStream fis = new FileInputStream(file);
        DataInputStream dis = DataInputStream(fis);

        int loops = (int) (filelength / (long) b.length);
        int remainder = (int) (filelength % (long) b.length);

        for (int j = 0; j < loops; j++) 
        {
            dis.readFully(b);
            dos.write(b);
        }

        if (remainder > 0)
        {
            dis.readFully(b, 0, remainder);
            dos.write(b, 0, remainder);
        }
    }

    System.out.println("");

    dos.close();
    server.close();

    System.out.println("Server Closed!");
}

客户:

public static void main(String[] args) throws Exception
{
    System.out.println("i am client");
    System.out.println("");

    Socket soc = new Socket("localhost", 12345);
    System.out.println("Server is connected");

    DataInputStream dis = new DataInputStream(soc.getInputStream());

    int filecount = dis.readInt();
    File[] files = new File[filecount];
    System.out.println("filecount : " + filecount);

    byte[] b = new byte[1024];

    for (int i = 0; i < filecount; i++)
    {
        long filelength = dis.readLong();
        String filename = dis.readUTF();
        System.out.println("filename : " + filename);

        files[i] = new File(dirPath + "/" + filename);

        FileOutputStream fos = new FileOutputStream(files[i]);

        int loops = (int) (filelength / (long) b.length);
        int remainder = (int) (filelength % (long) b.length);

        for (int j = 0; j < loops; j++)
        {
            dis.readFully(b);
            fos.write(b);
        }

        if (remainder > 0)
        {
            dis.readFully(b, 0, remainder);
            fos.write(b, 0, remainder);
        }
    }

    System.out.println("data received!");

    dis.close();

    System.out.println("client closed!");
}

答案 1 :(得分:-1)

仅举一个使用Google Gauva library如何使代码更干净的示例,这是您的代码已更改为使用Guava,ByteStreamsFiles的几个实用程序类

import com.google.common.io.ByteStreams;
import com.google.common.io.Files;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class ClientServerGuava {
    private static final int PORT = 12345;

    public static void main(String[] args) throws IOException {
        Thread serverThread = new ServerThread();
        serverThread.start();
        runClient();
    }

    private static void runClient() throws IOException {
        System.out.println("i am client");
        System.out.println("");
        Socket soc = new Socket("localhost", PORT);
        System.out.println("Server are connected");
        DataInputStream dis = new DataInputStream(soc.getInputStream());

        int filecount = dis.readInt();
        File[] files = new File[filecount];

        System.out.println("filecount : " + filecount);
        byte[] b = new byte[1024];

        for (int i=0;i<filecount;i++)
        {
            long filelength = dis.readLong();
            String filename = dis.readUTF();
            System.out.println("filenames : "+filename);

            files[i] = new File(filename);
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(files[i]));
            InputStream limitedStream = ByteStreams.limit(dis, filelength);
            ByteStreams.copy(limitedStream, bos);
            bos.close();

        }

        System.out.println("data received!");
        dis.close();
        soc.close();

        System.out.println("client closed!");
    }

    private static class ServerThread extends Thread {

        private static final String DIR = "C:\\Users\\Nitesh Rathi\\Downloads\\vcruntime140";

        @Override
        public void run() {
            try {
                System.out.println("i am server");
                System.out.println("");
                ServerSocket server = new ServerSocket(PORT);
                System.out.println("Server is listening...");
                Socket client = server.accept();
                System.out.println("Client are connected");
                DataOutputStream dos = new DataOutputStream(client.getOutputStream());


                String dir = DIR;
                File[] files = new File(dir).listFiles();
                System.out.println("Files Selected : " + files.length);

                dos.writeInt(files.length);

                for (File file : files) {
                    dos.writeLong(file.length());
                    dos.writeUTF(file.getName());

                    System.out.println(file.getName());

                    Files.copy(file, dos);
                }

                System.out.println("");
                dos.close();
                client.close();
                server.close();
                System.out.println("Server Closed!");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

注意消除读取循环。您确实应该学习如何编写读取循环的代码,但是在实践中,依靠受支持的,经过分析的,成熟的,优化的库可能会更好地为您服务。我相信Apache commons-io具有类似的功能。