我写了一个很好的聊天客户端,直到我决定添加一些文件发送者的东西,它应该从客户端发送文件到服务器。在我添加文件发件人的行后,它不再显示消息。
我认为麻烦就在这里,在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
感谢。
答案 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();
}