Java Chat socket编写麻烦

时间:2011-09-11 08:53:14

标签: java sockets chat

我写了一个很好的聊天客户端,直到我决定添加一些文件发送者的东西,它应该从客户端发送文件到服务器。在我添加文件发件人的行后,它不再显示消息。

我认为麻烦就在这里,在run()中有两个try语句。

   public void run(){

    InputStream input = null;

    try{
        input = socket.getInputStream();
        BufferedReader inReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        BufferedWriter outReader = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));

        //Citeste calea fisierului
        String filename = inReader.readLine();
        if(filename.equals("")){
            //Trimit status READY la client
            outReader.write("READY\n");
            outReader.flush();
        }

        FileOutputStream wr = new FileOutputStream(new File("C://tmp/"+filename));
        byte[] buffer = new byte[socket.getReceiveBufferSize()];
        int bytesReceived = 0;
        while((bytesReceived = input.read(buffer)) > 0){
            wr.write(buffer,0,bytesReceived);
        }

    }

    catch(IOException e){
        Logger.getLogger(ConectareClient.class.getName()).log(Level.SEVERE,null,e);
    }

    try{
        //Inregistreaza firul curent in listaObiecte
        listaObiecte.addElement(this);

        System.out.println("\n Fir de executie nou");
        System.out.println(this.toString());
        System.out.println(listaObiecte.toString());

        //Bucla
        while(true){
            //Se citeste mesajul din fluxul de intrare trimis de client
            String mesaj = fluxIntrare.readUTF();
            //Se transmite mesajul catre toti clientii conectati
            transmite(mesaj);
        }
    }
  //Tratare exceptie conexiune 
  catch (IOException e){
      e.printStackTrace();
  }
  finally{
        //Stergere fir curent din listaObiecte
        listaObiecte.removeElement(this);

        System.out.println("\n Fir de executie inchis");
        System.out.println(this.toString());
        System.out.println(listaObiecte.toString());

        try{
            //Inchidere socket
            socket.close();
            input.close();
        }
        //Tratare exceptie conexiune 
        catch (IOException e){
            e.printStackTrace();
        }    
  }  
}

    private static void transmite(String mesaj){
    //Enumerare generata de lista firelor de executie
    Enumeration enm = listaObiecte.elements();

    //Cat timp mai sunt elemente in enumerare
    while(enm.hasMoreElements()){
        //Se initializeaza cu null referinta firului curent
        ConectareClient firDestinatie = null;

        //Se protejeaza vectorul firelor de acces simultan
        synchronized(listaObiecte){
            //Se memoreaza referinta catre firul curent
            firDestinatie = (ConectareClient) enm.nextElement();
        }
    //Referinta valida
        if(firDestinatie != null){
            try{
                //Se protejeaza fluxul de iesire de acces simultan
                synchronized(firDestinatie.fluxIesire){
                    //Scriere mesaj in flux de iesire
                    firDestinatie.fluxIesire.writeUTF(mesaj);
                }
                //Mesajul este transmis
                firDestinatie.fluxIesire.flush();
            }
            catch(IOException e){
                firDestinatie.stop();
            }
        }
    }       
}

您可以在此下载所有源文件。 http://www.megaupload.com/?d=ULFDBP6M

感谢。

2 个答案:

答案 0 :(得分:1)

我已经下载并尝试了您的代码。简而言之,您的问题是线程死锁。你有两个线程,一个在服务器端,一个在客户端,每个都在等待另一个人做某事,这样第一个线程也可以继续。

更多细节,这是什么了:

  • ClientChat类在第260行将文件名发送到服务器,然后在继续实际文件发送之前等待服务器发送回来的东西(带有“READY”的字符串)

  • 另一方面,ConectareClient类在第38行停止等待从客户端发送的内容,然后继续(并发送“READY”状态消息,而客户端正在等待)。 / p>

我给你的建议是:

这看起来很像一些尘土飞扬的老教授给你的作业:而且看起来这个人没有先完成软件开发的基础知识就把这个给了你。我不打算在这里做编辑,但这里有一些可能对你有所帮助的实用指南:

  • 使用Eclipse等IDE。不要使用记事本在命令行中编写代码。在这种情况下,Eclipse会让您受益匪浅,因为您可以轻松地调试代码以消除这些琐碎的错误。这是你应该做的:下载Eclipse,创建一个Java标准项目,复制所有.java文件并将它们粘贴到Eclipse项目的“src”文件夹中。然后在我上面提到的行中添加一些断点,启动客户端和服务器,尝试发送文件并查看代码中发生的事情。

  • 进行单元测试!无论你的教授和你的同事怎么说,这都非常重要。进行单元测试对编码有双重好处:1。它可以帮助您轻松发现这种重构回归错误。 2.它将强制你编写好的干净代码,每个任务都有单独的方法等。

  • 虽然拥有服务器/客户端低级线程和套接字知识并不坏,但实现您在此项目中尝试执行的操作的更好方法是使用Java Messenger Service。它是一个完全符合您需要的框架,即以同步或异步方式发送和接收所有类型的东西(基元,对象等),并且所有脚手架已经为您完成,您只需要实现业务逻辑。查一下,它可能对你有很大的帮助。

答案 1 :(得分:0)

看起来ConnectareClient.java中存在一个小的逻辑错误。发送“READY”的条件,我认为应该是NOT条件,否则它永远不会将该回复发送给客户端并继续写入文件。我已经尝试过,我可以看到文件正从客户端复制到服务器。

以下是我在ConnectareClient.java中所做的代码更改


//Citeste calea fisierului
String filename = inReader.readLine();

// this seems should be a NOT condition
if(!filename.equals("")){
    //Trimit status READY la client
    outReader.write("READY\n");
    outReader.flush();
}