Java 套接字程序中的线程面临死锁

Java 套接字程序中的线程面临死锁,java,multithreading,sockets,Java,Multithreading,Sockets,我正在开发一个程序,用户可以在其中下载许多文件。现在,我首先将文件列表发送给用户。因此,用户从列表中一次选择一个文件,并提供存储该文件的路径。反过来,它还为服务器提供文件所在的路径 我之所以采用这种方法,是因为我希望提供类似流的体验,而不受文件大小限制 这是我的密码 1) 这是每次启动应用程序时启动的服务器 public class FileServer extends Thread { private ServerSocket socket = null; public F

我正在开发一个程序,用户可以在其中下载许多文件。现在,我首先将文件列表发送给用户。因此,用户从列表中一次选择一个文件,并提供存储该文件的路径。反过来,它还为服务器提供文件所在的路径

我之所以采用这种方法,是因为我希望提供类似流的体验,而不受文件大小限制

这是我的密码

1) 这是每次启动应用程序时启动的服务器

public class FileServer extends Thread {

    private ServerSocket socket = null;

    public FileServer() {
        try {
            socket = new ServerSocket(Utils.tcp_port);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public void run() {

        try {

            System.out.println("request received");
            new FileThread(socket.accept()).start();

        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

}
2) 该线程分别为每个客户端运行,并将请求的文件一次发送给用户8kb的数据

public class FileThread extends Thread {

    private Socket socket;
    private String filePath;



    public String getFilePath() {
        return filePath;
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }

    public FileThread(Socket socket) {
        this.socket = socket;
        System.out.println("server thread" + this.socket.isConnected());
        //this.filePath = filePath;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        try

        {
            ObjectInputStream ois=new ObjectInputStream(socket.getInputStream());
            try {
                           //************NOTE
                filePath=(String) ois.readObject();             
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            File f = new File(this.filePath);

            byte[] buf = new byte[8192];

            InputStream is = new FileInputStream(f);
            BufferedInputStream bis = new BufferedInputStream(is);

            ObjectOutputStream oos = new ObjectOutputStream(
                    socket.getOutputStream());
            int c = 0;

            while ((c = bis.read(buf, 0, buf.length)) > 0) {
                oos.write(buf, 0, c);
                oos.flush();
                // buf=new byte[8192];
            }

            oos.close();
            //socket.shutdownOutput();
            // client.shutdownOutput();
            System.out.println("stop");
            // client.shutdownOutput();
            ois.close();
//          Thread.sleep(500);

            is.close();
            bis.close();
            socket.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }

    }

}
注意:这里filePath表示文件在服务器上的路径。连接到服务器的客户端提供此路径。我正在通过套接字管理它,并且我正在成功地接收此路径

3) FileReceiverThread负责从服务器接收数据,并从该缓冲区数据构造文件

public class FileReceiveThread extends Thread {

    private String fileStorePath;
    private String sourceFile;
    private Socket socket = null;

    public FileReceiveThread(String ip, int port, String fileStorePath,
            String sourceFile) {
        this.fileStorePath = fileStorePath;
        this.sourceFile = sourceFile;
        try {
            socket = new Socket(ip, port);
            System.out.println("receive file thread " + socket.isConnected());
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            ObjectOutputStream oos = new ObjectOutputStream(
                    socket.getOutputStream());
            oos.writeObject(sourceFile);
            oos.flush();
            // oos.close();
            File f = new File(fileStorePath);

            OutputStream os = new FileOutputStream(f);
            BufferedOutputStream bos = new BufferedOutputStream(os);

            byte[] buf = new byte[8192];
            int c = 0;

            //************ NOTE

            ObjectInputStream ois = new ObjectInputStream(
                    socket.getInputStream());

            while ((c = ois.read(buf, 0, buf.length)) > 0) {
                // ois.read(buf);
                bos.write(buf, 0, c);
                bos.flush();
                // buf = new byte[8192];
            }

            ois.close();
            oos.close();
            //
            os.close();
            bos.close();

             socket.close();
            //Thread.sleep(500);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

}
注意:现在我面临的问题是在第一次请求文件时,程序的结果与我的预期相同。我能够在第一时间传输任何大小的文件。现在,当请求第二个文件时(例如,我已将文件a、b、c、d发送给用户,并且用户已成功接收到文件a,现在他正在请求文件b),程序将在这种情况下面临死锁。它正在等待套接字的输入流。我放置了断点并试图调试它,但它并没有第二次进入FileThread的run方法。我在这里找不出错误。基本上,我正在制作一个在局域网上工作的局域网信使。我使用SWT作为UI框架。

一个更基本的问题

您只处理第一个套接字

while(true) {
    new FileThread(socket.accept()).start();
}

根据Peter Lawrey的建议,我从源代码中删除了所有冗余流代码。现在更改的源代码如下,问题仍然存在

1) 文件服务器中没有更改。原来如此

2) 文件线程

public class FileThread extends Thread {

    private Socket socket;
    private String filePath;

    public String getFilePath() {
        return filePath;
    }

    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }

    public FileThread(Socket socket) {
        this.socket = socket;
        System.out.println("server thread" + this.socket.isConnected());
        // this.filePath = filePath;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        try

        {
            OutputStream oos = socket.getOutputStream();
            oos.flush();

            InputStream ois = socket.getInputStream();
            byte[] buf = new byte[8192];

            ois.read(buf);
            filePath = new String(buf);
            System.out.println(filePath);

            File f = new File(this.filePath);

            InputStream is = new FileInputStream(f);

            int c = 0;

            while ((c = is.read(buf, 0, buf.length)) > 0) {
                oos.write(buf, 0, c);
                oos.flush();
            }

            oos.close();
            System.out.println("stop");
            ois.close();

            is.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        }

    }

}
3) FileReceiverThread

public class FileReceiveThread extends Thread {

    private String fileStorePath;
    private String sourceFile;
    private Socket socket = null;

    public FileReceiveThread(String ip, int port, String fileStorePath,
            String sourceFile) {
        this.fileStorePath = fileStorePath;
        this.sourceFile = sourceFile;
        try {
            socket = new Socket(ip, port);
            System.out.println("receive file thread " + socket.isConnected());
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void run() {
        try {
            OutputStream oos = socket.getOutputStream();

            oos.write(sourceFile.getBytes());
            oos.flush();

            File f = new File(fileStorePath);

            OutputStream os = new FileOutputStream(f);

            byte[] buf = new byte[8192];
            int c = 0;

            // ************ NOTE

            InputStream ois = socket.getInputStream();

            while ((c = ois.read(buf, 0, buf.length)) > 0) {

                os.write(buf, 0, c);
                os.flush();

            }

            ois.close();
            oos.close();

            os.close();

        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

}

我还缺少什么吗?

在FileReceiveThread.run中slippery@gnat:我不明白你在说什么…你能详细说明一下吗?顺便说一句:你应该在创建ObjectInputStream之前创建并刷新ObjectOutputStream,否则会导致死锁。你应该只使用ObjectInput/OutputStream发送对象,而不是原始数据。你不应该只是打印一个异常并继续,就好像它没有发生一样。好吧,这里对于每个请求的文件,单独的线程将运行,所以我认为每个共享同一服务器的客户机将有单独的套接字。您是否想说,一旦服务器的输入/输出流被使用,它们将不可用于任何其他客户端?如果你知道这个问题,请提供任何好的教程链接。。正如你所看到的,我也错过了第一次。。)