2016-12-28 92 views
0

我试图创建一个客户端/服务器程序,允许服务器和客户端向对方发送文件。我创建了套接字,并将客户端连接到服务器。我现在正在为这台计算机做同一台计算机。如果它完善了,我会把它带到另一台电脑上试试。通过java socket编程共享的文件最终在接收端被破坏

我的问题是,文件传输成功,但它已损坏。收到的文件已损坏,但原文没问题。我发生套接字异常的问题,在套接字发送文件后不断重置,但我设法解决这个问题。现在文件已发送,但尚未完成。

收到的文件大小小于发送文件的大小,这导致收到的文件无法正常工作。我通过网络发送了一个pdf文件。原文约为695kb,但收到的文件为688kb,导致文件被损坏。我也尝试发送视频,并得到相同的结果。接收到的文件比发送的文件小。

我检查了程序,但是我看不到问题来自哪里。 我试图实现的发送方法是零拷贝方法,其中来自文件的数据直接发送到套接字,从它直接读取到文件的位置。在将它发送到输出流之前,我没有使用存储在缓冲区中的其他方法。这是因为我想能够使用该程序发送大文件。大文件将填满java堆内存,此外此方法更快。

缓冲方法:

.... 
File file = new File("path to file); 
BufferedInputStream = new BufferedInputStream(new FileInputStream(file)); 
BufferedOutputStream out = new  BufferedOutputStream(socket.getOutputStream()); 

byte[] buf = new byte[length]; 
in.read(buf, 0, buf.length); 
out.write(buf, 0, buf.length); 
.... 

我没有用这个缓冲区方法。这是我的代码。这是文件服务器

import java.io.*; 
import java.net.*; 

import javax.swing.JFileChooser; 

public class ShareServer { 

    public static void main(String args[]) { 
     int port = 4991; 
     ServerSocket server; 
     Socket socket = null; 
     BufferedInputStream in = null; 
     BufferedOutputStream out = null; 

     try { 
      server = new ServerSocket(port); 
      System.out.println("Waiting for connection request.."); 

      socket = server.accept(); 

      System.out.println("Connected to " + socket.getInetAddress().getHostName()); 

      JFileChooser fc = new JFileChooser(); 
      File file = null; 

      if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) 
       file = fc.getSelectedFile(); 

      // send out the reference of the file using writeObject() method 
      new ObjectOutputStream(socket.getOutputStream()).writeObject(file); 

      in = new BufferedInputStream(new FileInputStream(file)); 
      out = new BufferedOutputStream(socket.getOutputStream()); 

      // send file 
      int b = 1; 
      while (b != -1){ 
       b = in.read(); 
       out.write(b); 
      } 

      System.out.println(file.getName() + " has been sent successfully!"); 

     } catch (Exception e) { 
      System.out.println(e.getMessage()); 
      e.printStackTrace(); 
     } 

     try { 
      in.close(); 
      out.close(); 
      socket.close(); 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

这里是Client类:

import java.io.*; 
import java.net.*; 

import javax.swing.JOptionPane; 

public class ShareClient { 
    public ShareClient() { 

    } 

    public static void main(String[] args) throws IOException, ClassNotFoundException { 

     String host = InetAddress.getLocalHost().getHostAddress(); 

     Socket socket = new Socket(host, 4991); 
     System.out.println("Connected to " + host); 

     // receive the file object. this does not contain the file data 
     File refFile = (File) new ObjectInputStream(socket.getInputStream()).readObject(); 

     System.out.println("File to receive " + refFile.getName()); 

     // create a new file based on the refFile 
     File newFile = new File(System.getProperty("user.home") + "/desktop/ReceivedFiles", refFile.getName()); 

     BufferedInputStream in = new BufferedInputStream(socket.getInputStream()); 
     BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(newFile)); 

     System.out.println("Receiving file now..."); 

     int b; 
     while ((b = in.read()) != -1) 
      out.write(b); 

     System.out.println("File has been received successfully!"); 

     socket.close(); 

    } 

} 

的服务器和客户端类的成功运行没有任何异常,并且该文件被发送,但它已损坏。它是不完整的。 请注意,通过ObjectInput和ObjectOutput流发送的文件不是真实文件,而只是一个文件对象,它具有我要发送的filie的所有信息,但不包含文件的二进制数据。

请问有人可以帮我吗?为什么文件损坏或不完整?它被读到最后(当-1)被返回时,并且所有的字节被发送,但由于某些原因,我不能解释,它最终小于原始文件的大小。

回答

1

当前,您在文件末尾写入-1(即应该停止时)。喜欢的东西,

int b = 1; 
while (b != -1){ 
    b = in.read(); 
    if (b != -1) { 
     out.write(b); 
    } 
} 

int b; 
while ((b = in.read()) != -1) { 
    out.write(b); 
} 
0

我终于得到了答案的问题!这非常简单!缓冲区。我只是添加了一小段代码来刷新服务器中的套接字输出流缓冲区,并在客户端程序中刷新fileoutputstream缓冲区,就是这样!看起来有些字节的数据留在缓冲区中,导致文件不完整。这是缓冲输入和输出的问题之一。如果你忘记刷新缓冲区,你开始遇到问题。

下面的代码:

int b = 1; 
while(b != -1){ 
    out.write(b); 
} 
out.flush(); //this solved my problem. I also did it in the client class 

非常感谢你的回答@Elliot弗里希:)