java - 聊天程序在文件传输期间挂起?

时间:2012-01-16 15:04:25

标签: java

我有一个java聊天服务器&客户端,工作正常。我分别做了一个服务器到客户端文件传输程序,它也工作正常。但是当我尝试将文件传输集成到聊天中时,文件正在转移,但在此期间,聊天程序只是冻结,以至于我甚至无法在聊天框中输入内容,并且当转移结束时事情变得正常了。如何使其正常,如聊天和文件传输并排发生,没有一个受到另一个的影响?

我的文件传输在服务器和客户端都有while循环,我想知道这是因为while循环,我应该在文件传输的服务器和客户端代码上创建线程。 我的聊天系统就像在服务器上,用户连接,线程在服务器上为该用户启动,从用户读取,然后将这些消息从用户发送给每个人。 在客户端上,线程用于从服务器读取,当用户键入消息时,它将其发送到服务器,然后服务器将消息返回给连接的每个人。

我认为这个问题出现在客户端,因为我刚刚和我的朋友在互联网上测试了这个问题,我是服务器,用于Chat& amp;文件传输,我的聊天框很好,我能够输入,但他的聊天客户端freezd时间文件传输发生。

我不知道代码的哪一部分导致了这个问题,所以我会在有人要求时用代码更新它。

谢谢, 任何帮助都值得赞赏。

[编辑 - 客户端上的文件传输]

public class FileClient{


JFrame jfr;
JTextField Jtf = new JTextField(4);
public static void main (String [] args ) {

 // new FileClient().go();

 }

public void go(String ip){
    try{
    JFrame jfr = new JFrame("File Transfer");
            JPanel panel = new JPanel();
    JLabel jl = new JLabel("Progress:");
    jfr.getContentPane().add(BorderLayout.CENTER,panel);
    panel.add(jl);
    panel.add(Jtf);
    Jtf.setEditable(false);
    jfr.setSize(200,70);
    jfr.setVisible(true);
    jfr.setDefaultCloseOperation(jfr.EXIT_ON_CLOSE);
}catch(Exception e){e.printStackTrace();}
long start = System.currentTimeMillis();
    int read;
    int totalRead = 0;
    try{
    Socket sock = new Socket(ip,4243);
    System.out.println("Connecting...");
    InputStream is = sock.getInputStream();
    BufferedInputStream bis = new BufferedInputStream(new ProgressMonitorInputStream(jfr,"reading",is));

    byte [] mybytearray  = new byte [512];
    int buff =1024;
    byte[] nameByte = new byte [50];
    byte[] nameByteSize = new byte [2];
    byte[] Size = new byte [10];
    byte[] SizeSize =new byte [1];

    int num = is.read(nameByte,0,50);
    int nameSize = is.read(nameByteSize,0,2);
    int sz = is.read(Size,0,10);
    int yy = is.read(SizeSize,0,1);
    float w;

    String Size1 = RemoveNameStuffing(new String(Size),new String(SizeSize));
    int tt = Integer.parseInt(Size1);
    System.out.println("tt"+tt);
     name"+new String(nameByte));
    String name = RemoveNameStuffing(new String(nameByte),new String(nameByteSize));
    File f1=new File(name);

    FileOutputStream fos = new FileOutputStream(f1);
    BufferedOutputStream bos = new BufferedOutputStream(fos);

    while ((read = bis.read(mybytearray,0,mybytearray.length)) != -1) {
            bos.write(mybytearray, 0 , read);
            totalRead += read; 
            w=((float)totalRead/tt)*100;
            System.out.println("progress:"+w+"%");
            Jtf.setText(w+"%");
    }


    bos.flush();
    long end = System.currentTimeMillis();
    System.out.println(end-start);
    bos.close();
    sock.close();
    }catch(IOException e){e.printStackTrace();}
}

public static String RemoveNameStuffing(String s, String n){

    s=s.substring(0,Integer.parseInt(n));
    System.out.println("s:"+s);

    return s;

}

}

[编辑 - 这就是我如何将文件转移代码转移到聊天室中]

public class AcceptFileButtonListener implements ActionListener {

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
      FileCl.go(JTip.getText());
    }

}

[编辑 - 文件传输服务器代码 - 缓冲区大小512]

//Waiting for connection
//Sending name in bytes
//While{
   send files as bytes
   }

[上面的服务器(FT服务器)代码被调用]

public void actionPerformed(ActionEvent e) {

        FileSv.go();

    }

并且我的服务器也会在按下按钮时冻结,即使FT服务器甚至没有连接(我认为这个cud帮助)。

我有一个聊天服务器和客户端,两者都有线程可以互相读取。我试图将我的文件传输服务器和客户端集成到现有的聊天服务器和聊天客户端。 最初当用户连接到聊天服务器时,它会为它启动一个线程。现在要向该用户发送文件,我在服务器上创建了1个按钮(文件发送),在客户端创建了1个按钮(接受文件),现在当我点击服务器上的“文件发送”时,我的文件传输服务器代码被执行,并且文件转移服务器等待不同端口上的连接(我的聊天服务器现在冻结,它有一个textField,现在没有响应),现在如果我正在与之聊天的用户,点击“接受文件”文件传输客户端代码被执行。 FT服务器开始发送字节,FT客户端rcvs它。服务器和客户端CHAT窗口都没有响应时间传输,并且在传输过程中我从客户端聊天框发送的任何内容都会在传输后更新。 这是为了清除混乱。即使这没有用,我也会上传整个代码(太大了)

2 个答案:

答案 0 :(得分:3)

当您需要异步操作时,您遇到了使用同步操作的迹象。

我的猜测是你的应用程序有一个线程,或者你的远程通信有一个线程。您可能没有使用java的nio类进行异步通信。

您可以查看nio类或在单独的线程中执行当前的文件发送和文件接收代码。

前者的实现可以在一个体面的nio教程中找到(这里是one)。

后者的常见实现是使用命令模式发送消息/文件,以及使用生产者/消费者线程的命令队列。你可以对待" Runnable"接口作为您的Command类。

public class MessageCommand implements Runnable {
    private String message;
    public MessageCommand(String message) { this.message = message; }
    public void run() { /* code to send the message goes here */ }
}

public class FileCommand implements Runnable {
    private File file; /* or byte[] or whatever */
    public MessageCommand(File file) { this.file = file; }
    public void run() { /* code to send the file goes here */ }
}

然后有某种Queue<Runnable>,可能是ConcurrentLinkedQueue,它接受这些类型的对象,并使用生产者/消费者。请注意,您还需要在代码的接收部分上分离一个单独的线程。否则,您将能够异步发送,但会在接收时阻塞(这可能对消息有效,但对文件很烦)。

答案 1 :(得分:1)

好的,要扩展我的评论 - 你说when clicked on a button on the clientchat window, FileTransferClient side is initiated, which works on while loop to read byte from server.

您是否在Swing Event线程中运行文件传输代码?如果是这样,你需要将它包装在Runnable对象中,确保它在while循环的迭代之间产生一些处理时间,并使用SwingUtilities调用它。

如果您在按钮上启动单独的线程以便传输文件,您仍然需要在发送循环的循环之间产生处理时间,或者您不会在聊天处理线程中产生任何处理时间

编辑:修改您的动作侦听器调用以执行以下操作:

 @Override
public void actionPerformed(ActionEvent e) {
    // TODO Auto-generated method stub
  SwingUtilities.invokeLater(
      new Runnable() { 
         public void run() {
            FileCl.go(JTip.getText());
         }
      }
   );
}

这样做是将文件下载的CPU和IO密集处理移动到Swing事件线程外部的新线程中。