添加文件发送者后,Java聊天socket不显示消息
我写了一个聊天客户端,它工作得很好,直到我决定添加一些文件发送者的东西,它应该将一个文件从客户端发送到服务器。在我为文件发送者添加行之后,它不再显示消息
我认为问题在于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();
}
}
}
}
# 1 楼答案
看起来ConnectareClient中有一个小的逻辑错误。JAVA发送“READY”的条件,我认为应该是NOT条件,否则它将永远不会向客户发送回复并继续文件编写。我已经试过了,可以看到文件正在从客户端复制到服务器
下面是我在ConnectareClient中所做的代码更改。爪哇
# 2 楼答案
我已经下载并试用了你的代码。简而言之,您的问题是线程死锁。您有两个线程,一个在服务器端,一个在客户端,每个线程都在等待另一个线程执行某些操作,以便第一个线程也可以继续
更详细的情况如下:
ClientChat类在第260行将文件名发送到服务器,然后等待服务器发送回一些内容(带有“READY”的字符串),然后继续实际的文件发送
另一方面,ConectareClient类在第38行停止,等待从客户机发送一些东西,然后继续(并发送“READY”状态消息,客户机正在等待)
我给你的建议是:
这看起来很像是一个满身灰尘的老教授给你的作业指导:)而且看起来这个家伙给你的这个东西没有先学习软件开发的基础知识。我不打算在这里发表社论,但这里有一些实用的建议可以帮助你:
使用诸如Eclipse之类的IDE。不要使用记事本在命令行中编写代码。在这种情况下,Eclipse将使您受益匪浅,因为您可以轻松地调试代码,以避免出现这些微不足道的错误。这里是您应该做的:下载Eclipse,创建Java标准项目,复制您所有的应用程序。java文件并将它们粘贴到Eclipse项目的“src”文件夹中。然后在我上面提到的行中添加一些断点,启动客户端和服务器,尝试发送一个文件,看看代码中发生了什么
进行单元测试!这是非常重要的,不管你的教授和同事们怎么说。进行单元测试对您的编码有双重好处:1。它将帮助您轻松发现此类重构回归错误。2.它将迫使您编写干净的代码,每个任务都有各自的方法等。
虽然掌握服务器/客户机低级线程和套接字知识并不坏,但实现此项目的更好方法是使用Java Messenger Service。它是一个框架,可以完全按照您的要求执行,即以同步或异步的方式发送和接收所有类型的内容(原语、对象等),并且所有的搭建都已经为您完成,您只需实现业务逻辑。查一下,它可能会帮你很多忙