2013-10-28 225 views
0

我正在开发客户端和服务器之间的简单文件传输应用程序。 这里是我的代码: 我的客户(发件人):EOFException或SocketException:在通过套接字传输文件时关闭套接字

try{ 
       File file_sender=XMLParser.register(peername, address, port, listfile); 
       int count; 
       byte[] buffer = new byte[1024]; 
       int len=(int) file_sender.length(); 
       byte[] mybytearray = new byte[len];  
       DataOutputStream output=new DataOutputStream(Info.connection.getOutputStream()); 
       output.writeInt(len); 
       System.out.println(len); 
       BufferedInputStream bis=new BufferedInputStream(new FileInputStream(file_sender)); 
       bis.read(mybytearray, 0, len); 
       output.write(mybytearray, 0, len); 
       bis.close(); 
       output.close(); 
       // Info.connection.close(); 
      }catch(Exception ex){ 
       System.out.println(ex.toString()); 
      } 

我的服务器(接收器):

public class IOThread extends Thread { 
private Socket connection; 
private DataInputStream input; 
public IOThread(Socket connection) throws IOException{ 
    this.connection=connection; 
    input=new DataInputStream(connection.getInputStream()); 

} 
@Override 
public void run(){ 
    while(true){ 
     try{ 
      int filesize=12022386; 
      int bytesRead; 
      int currentTot = 0; 
      byte[] bytearray = new byte [filesize]; 
      int len=input.readInt(); 
      FileOutputStream fos = new FileOutputStream("data.xml"); 
      BufferedOutputStream bos = new BufferedOutputStream(fos); 
      bytesRead=input.read(bytearray, 0,bytearray.length); 
      System.out.println(len); 
      currentTot=bytesRead; 
      do{ 
       bytesRead=input.read(bytearray, currentTot, (bytearray.length-currentTot)); 
       if(bytesRead>=0) currentTot+=bytesRead; 
       System.out.println("pos: "+currentTot); 
      } while(len!=currentTot); 
      bos.write(bytearray, 0, currentTot); 
      bos.close(); 
      //connection.close(); 
      System.out.println("Done"); 
     }catch(EOFException ex){ 
      System.out.println(ex.toString()); 
      break; 
     }catch(Exception ex){} 
    } 
} 

我想转院多个文件,所以我不希望关闭套接字。因此,我使用变量“len”来检查文件是否完全传输。

如果我在发送文件之后关闭“输出”,那么服务器发出EOFException并且文件发送成功。

当我不关闭输出时,服务器无法接收文件成功。但是服务器不会抛出EOFException。

你能帮我解决这个问题吗? 更新:这是我在控制台屏幕上输出,如果我不关闭变量 “输出” 在客户端:

POS:496和

感谢。 对不起,我可怜的英语

+0

如果您没有关闭套接字,服务器如何不成功接收文件?它会卡在循环中吗? –

+0

您的标题有误导性。 EOFException和'socket is closed'是两个单独的条件,而不是一个。 – EJP

回答

0

您的BufferedOutputStream填充似乎不正确。下面的代码必须在while循环中。

bos.write(bytearray, 0, currentTot); 

尝试这样的事情,而不是:

BufferedOutputStream buffOut=new BufferedOutputStream(fos); 
byte []arr = new byte [1024 * 1024]; 
int available = -1; 
while((available = buffIn.read(arr)) != -1) { 
    buffOut.write(arr, 0, available); 
}  
buffOut.flush(); 
buffOut.close(); 

并再次测试。

编辑:用@ Jason的正确评论更新了我的答案。

+0

您应该测试'> = 0',而不是'> 0',因为0是'read'的有效返回值,并不表示输入结束(它表示此时没有数据可用,并且基础流会阻止,基本上意味着“稍后再试”)。 –

+0

我已经编辑了我的代码按照您的指示。但字符串“完成”不显示在服务器的控制台屏幕上,意味着无法离开while循环。 – user1956702

+0

@JasonC这是不正确的。如果指定的长度为零,InputStream.read()只返回零,这是一个编程错误。如果没有数据可用,则会阻塞。零并不意味着'以后再试'。 – EJP

2

两件事情:

首先,你似乎被忽略了你的接收代码的文件长度是多少?您有:

 int filesize=12022386; 
     int bytesRead; 
     int currentTot = 0; 
     byte[] bytearray = new byte [filesize]; 
     int len=input.readInt(); 

您在上浆ByteArray的12022386个字节不管len的价值,你所要求的从输入流很多字节。其次,关闭输出流时,任何尚未写入的缓存/缓存数据将自动刷新(即,在您的情况下,发送到服务器)。

当您完成发送第一个文件以强制完成将所有数据发送到服务器时,显式刷新输出流。然后,您可以继续使用该输出流来处理其他事情。

当传输完成时,在您的发送代码中执行output.flush()

+0

我在客户端发送文件完成后添加了output.flush(),但服务器仍然无法成功接收。 – user1956702

+1

查看我的评论re:'filesize'。相反,请将您的值用于“len”。您的'read'调用可能会阻止尝试读取12022386个字节。此外,根据您的输出,您读取的文件长度超过文件长度(文件长度为246,但您至少读取了496)。 –

+0

huhuhuhuhuhuhu,非常感谢你非常非常非常非常非常。 Stackoverflow是greate。 – user1956702

2

问题是,您读取的文件大小超出文件大小,即读取的文件大小不是len,而是读取的文件大小为bytearray.length

因此,你读超过len字节,因此len!=currentTot是永远不会满足的,因为,你可以从你的样本输出,currentTot == 496len == 246看到。

,让您的while循环以下变化:

do{ 
    bytesRead=input.read(bytearray, currentTot, (len - currentTot)); 
    if(bytesRead>=0) currentTot += bytesRead; 
    System.out.println("pos: " + currentTot); 
} while(len != currentTot); 

只是为了确保你没有一个无限循环最终由于类似的错误,你可以使用currentTot < len,而不是len != currentTot作为你的条件。

此外,由于您已经在使用DataInputStream,因此请考虑使用readFully读取套接字内容。这会阻塞,直到从套接字读取给定数量的字节,从而消除您对while循环的需要。阅读更多here

+0

确切地说,我没有理解。非常感谢。 – user1956702

2

将所有循环丢弃并在发送文件后使用DataInputStream.readFully();关闭套接字;不要结束文件长度;并使用正常大小的缓冲区,例如8192字节。