【问题标题】:Java socket file transfer - Files don't transfer completelyJava 套接字文件传输 - 文件不完全传输
【发布时间】:2015-05-16 20:29:12
【问题描述】:

我正在尝试将文件从客户端发送到服务器,但仅传输了约 8kb 的较大文件(约 100kb)。例如,png 并不完全可见。 我真的不知道为什么它会提前停止。

发送小测试文件(~1 kb)效果很好。

服务器部分:

                    ServerSocket fileSocket = new ServerSocket(p);
                    boolean rdy = false;
                    while (!rdy) {
                        Socket client = fileSocket.accept();
                        String fileName = "C:/" + args[2];
                        String cmd = fileName + "\n";

                        OutputStreamWriter sWriter = new OutputStreamWriter(client.getOutputStream());
                        sWriter.write(cmd, 0, cmd.length());
                        sWriter.flush();

                        InputStream inStream = client.getInputStream();

                        FileOutputStream fileStream = new FileOutputStream(fileName);

                        byte[] buffer = new byte[client.getReceiveBufferSize()];

                        int bytesRead = 0;

                        while ((bytesRead = inStream.read(buffer)) > 0) {
                            fileStream.write(buffer, 0, bytesRead);
                        }
                        fileStream.flush();

                        ta.append("File transfered");

                        inStream.close();
                        fileStream.close();
                        rdy = true;
                    }
                    fileSocket.close();
                    return;

客户端部分:

Socket client = new Socket(ip, port);
        OutputStream outStream = client.getOutputStream();

        FileInputStream fileStream = new FileInputStream(fileName);

        byte[] buffer = new byte[(int) fileStream.getChannel().size()];

        int bytesRead = 0;

        System.out.println("Sending file: " + fileName);

        while ((bytesRead = fileStream.read(buffer)) > 0) {
            outStream.write(buffer, 0, bytesRead);
        }

        outStream.close();
        fileStream.close();
        client.close();
        return;

【问题讨论】:

  • 您正在向客户写一些东西,但从未阅读过它。试试不写。您可能会触发未告诉我们的连接重置。或者您有其他异常,请在您的问题中发布它和堆栈跟踪。
  • 客户端这行outStream.write(buffer, 0, bytesRead);不会造成数据丢失吗?难道写得比告诉的少吗?
  • @alk 不,它会阻塞,直到所有数据都传输完毕。请参阅 Javadoc。
  • 我在这里得到一个套接字异常(java.net.SocketException: Connection reset at java.net.SocketInputStream.read(Unknown Source)):while ((bytesRead = inStream.read(buffer)) > 0) { fileStream.write(buffer, 0, bytesRead); }
  • 如预期的那样。那么当你在没有写入的情况下尝试它时发生了什么?

标签: java sockets client server


【解决方案1】:

您的代码的问题在于您假设服务器端会立即接收所有数据,但事实并非如此。您应该首先告诉服务器图像文件有多大,然后发送您的数据。在服务器端,您首先读取大小,然后等待从客户端接收到所有数据。

客户

    Socket client = new Socket(ip, port);
    DataOutputStream outStream = new DataOutputStream(client.getOutputStream());

    FileInputStream fileStream = new FileInputStream(fileName);

    byte[] buffer = new byte[filename.length()];

    int bytesRead = 0;

    System.out.println("Sending file: " + fileName);
    outStream.writeInt(filename.length()); //write image size

    while ((bytesRead = fileStream.read(buffer)) > 0) {
        outStream.write(buffer, 0, bytesRead);
    }

    outStream.close();
    fileStream.close();
    client.close();
    return;

服务器

                ServerSocket fileSocket = new ServerSocket(p);
                boolean rdy = false;
                while (!rdy) {
                    Socket client = fileSocket.accept();
                    String fileName = "C:/" + args[2];
                    String cmd = fileName + "\n";

                    OutputStreamWriter sWriter = new OutputStreamWriter(client.getOutputStream());
                    sWriter.write(cmd, 0, cmd.length());
                    sWriter.flush();

                    DataInputStream inStream = new DataInputStream(client.getInputStream());

                    FileOutputStream fileStream = new FileOutputStream(fileName);

                    while(inStream.available()<4) {} //wait for the size of an int
                    int imagesize = inStream.readInt();

                    byte[] buffer = new byte[imagesize];

                    while(inStream.available()<imagesize) {} //wait for all the image data
                    inStream.readFully(buffer);
                    fileStream.write(buffer, 0, imagesize);
                    fileStream.flush();

                    ta.append("File transfered");

                    inStream.close();
                    fileStream.close();
                    rdy = true;
                }
                fileSocket.close();
                return;

【讨论】:

  • 我在客户端代码的这一行中得到一个 SocketWriteExeption:outStream.write(buffer, 0, bytesRead);
  • 他并没有假设服务器立即获得所有数据,并且他不需要在数据之前发送长度,因为他在发送后关闭,并读取到流的末尾另一端。您的 available() 循环都是完全不必要的时间、空间和 CPU 浪费,因为以下所有读取都会阻塞。您还将发送文件名的长度而不是文件的长度。完全的、未经检验的废话。
【解决方案2】:

非常感谢你们的帮助。

现在我发现了一个有趣的类,它完全符合我的需要。 希望我能对其他有同样问题的人有所帮助。

代码来自:http://www.adp-gmbh.ch

import java.io.InputStream;
import java.io.OutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileInputStream;

public class ByteStream {
  private static byte[] toByteArray(int in_int) {
    byte a[] = new byte[4];
    for (int i=0; i < 4; i++) {

      int  b_int = (in_int >> (i*8) ) & 255;
      byte b = (byte) ( b_int );

      a[i] = b;
     }
    return a;
  }

  private static int toInt(byte[] byte_array_4) {
    int ret = 0;  
    for (int i=0; i<4; i++) {
      int b = (int) byte_array_4[i];
      if (i<3 && b<0) {
        b=256+b;
      }
      ret += b << (i*8);
    }
    return ret;
  }

  public static int toInt(InputStream in) throws java.io.IOException {
    byte[] byte_array_4 = new byte[4];

    byte_array_4[0] = (byte) in.read();
    byte_array_4[1] = (byte) in.read();
    byte_array_4[2] = (byte) in.read();
    byte_array_4[3] = (byte) in.read();

    return toInt(byte_array_4);
  }

  public static String toString(InputStream ins) throws java.io.IOException {
    int len = toInt(ins);
    return toString(ins, len);
  }

  private static String toString(InputStream ins, int len) throws java.io.IOException {
    String ret=new String();
    for (int i=0; i<len;i++) {
      ret+=(char) ins.read();
    }
    return ret;
  }

  public static void toStream(OutputStream os, int i) throws java.io.IOException {
    byte [] byte_array_4 = toByteArray(i);
    os.write(byte_array_4);
  }

  public static void toStream(OutputStream os, String s) throws java.io.IOException {
    int len_s = s.length();
    toStream(os, len_s);
    for (int i=0;i<len_s;i++) {
      os.write((byte) s.charAt(i));
    }
    os.flush();
  }

  private static byte[] toByteArray(InputStream ins, int an_int) throws 
    java.io.IOException,  
    Exception{

    byte[] ret = new byte[an_int];

    int offset  = 0;
    int numRead = 0;
    int outstanding = an_int;

    while (
       (offset < an_int)
         &&
      (  (numRead = ins.read(ret, offset, outstanding)) > 0 )
    ) {
      offset     += numRead;
      outstanding = an_int - offset;
    }
    if (offset < ret.length) {
      throw new Exception("Could not completely read from stream, numRead="+numRead+", ret.length="+ret.length); // ???
    }
    return ret;
  }

  private static void toFile(InputStream ins, FileOutputStream fos, int len, int buf_size) throws 
        java.io.FileNotFoundException, 
        java.io.IOException {

    byte[] buffer = new byte[buf_size];

    int       len_read=0;
    int total_len_read=0;

    while ( total_len_read + buf_size <= len) {
      len_read = ins.read(buffer);
      total_len_read += len_read;
      fos.write(buffer, 0, len_read);
    }

    if (total_len_read < len) {
      toFile(ins, fos, len-total_len_read, buf_size/2);
    }
  }

  private static void toFile(InputStream ins, File file, int len) throws 
        java.io.FileNotFoundException, 
        java.io.IOException {

    FileOutputStream fos=new FileOutputStream(file);

    toFile(ins, fos, len, 1024);
  }

  public static void toFile(InputStream ins, File file) throws 
        java.io.FileNotFoundException, 
        java.io.IOException {

    int len = toInt(ins);
    toFile(ins, file, len);
  }

  public static void toStream(OutputStream os, File file) 
      throws java.io.FileNotFoundException,
             java.io.IOException{

    toStream(os, (int) file.length());

    byte b[]=new byte[1024];
    InputStream is = new FileInputStream(file);
    int numRead=0;

    while ( ( numRead=is.read(b)) > 0) {
      os.write(b, 0, numRead);
    }
    os.flush();
  }
}

【讨论】:

  • 所有这些只是DataOutputStreamDataInputStream 的重新实现。我在这里看不到任何能真正解决问题的东西。
猜你喜欢
  • 1970-01-01
  • 2014-10-18
  • 1970-01-01
  • 1970-01-01
  • 2015-03-06
  • 2018-08-19
  • 2011-10-13
  • 1970-01-01
相关资源
最近更新 更多