java - 在 java 中通过 objectoutputstream 发送字节数组

标签 java sockets arrays objectoutputstream

我正在尝试为相当复杂的 Java 服务器编写一个上传系统。我在下面列出的两个小程序中重现了错误。基本上,我使用 ObjectOutputStream/ObjectInputStream 通过客户端/服务器进行通信。这是一个要求;我有数千行代码围绕这个 ObjectOutputStream/ObjectInputStream 设置工作得很好,所以我必须能够在上传完成后仍然使用这些流。

要访问文件(在客户端读取的文件和在服务器上写入的文件),使用 FileInputStream 和 FileOutputStream。我的客户端看起来 运行良好;它读取文件并在每次迭代时发送一个不同的字节数组(它一次读取 1MB,因此可以处理大文件而不会溢出堆)。但是,在服务器上,字节数组似乎总是发送的第一个数组(文件的第一个 1MB)。这不符合我对ObjectInputStream/ObjectOutputStream的理解。我正在寻求解决此问题的有效解决方案,或者就此问题进行足够的教育以形成我自己的解决方案。

客户端代码如下:

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

public class stupidClient
{
  public static void main(String[] args)
  {
    new stupidClient();
  }

  public stupidClient()
  {
    try
    {
      Socket s = new Socket("127.0.0.1",2013);//connect
      ObjectOutputStream output = new ObjectOutputStream(s.getOutputStream());//init stream

      //file to be uploaded
      File file = new File("C:\\Work\\radio\\upload\\(Op. 9) Nocturne No. 1 in  Bb Minor.mp3");
      long fileSize = file.length();
      output.writeObject(file.getName() + "|" + fileSize);//send name and size to server

      FileInputStream fis = new FileInputStream(file);//open file
      byte[] buffer = new byte[1024*1024];//prepare 1MB buffer
      int retVal = fis.read(buffer);//grab first MB of file
      int counter = 0;//used to track progress through upload

      while (retVal!=-1)//until EOF is reached
      {
        System.out.println(Math.round(100*counter/fileSize)+"%");//show current progress to system.out
        counter += retVal;//track progress

        output.writeObject("UPACK "+retVal);//alert server upload packet is incoming, with size of packet read

        System.out.println(""+buffer[0]+" "+buffer[1]+" "+buffer[2]);//preview first 3 bytes being sent
        output.writeObject(buffer);//send bytes
        output.flush();//make sure all bytes read are gone

        retVal = fis.read(buffer);//get next MB of file
      }
      System.out.println(Math.round(100*counter/fileSize)+"%");//show progress at end of file
      output.writeObject("UPLOAD_COMPLETE");//let server know protocol is finished
      output.close();
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
  }
}

以下是我的服务器代码:

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

public class stupidServer
{
  Socket s;
  ServerSocket server;

  public static void main(String[] args)
  {
    new stupidServer();
  }

  public stupidServer()
  {
    try 
    {
      //establish connection and stream
      server = new ServerSocket(2013);
      s = server.accept();
      ObjectInputStream input = new ObjectInputStream(s.getInputStream());
      String[] args = ((String)input.readObject()).split("\\|");//args[0] will be file name, args[1] will be file size
      String fileName = args[0];
      long filesize = Long.parseLong(args[1]);

      String upack = (String)input.readObject();//get upload packet(string reading UPACK [bytes read])
      FileOutputStream outStream = new FileOutputStream("C:\\"+fileName.trim());

      while (!upack.equalsIgnoreCase("UPLOAD_COMPLETE"))//until protocol is complete
      {
        int bytes = Integer.parseInt(upack.split(" ")[1]);//get number of bytes being written
        byte[] buffer = new byte[bytes];
        buffer = (byte[])input.readObject();//get bytes sent from client

        outStream.write(buffer,0,bytes);//go ahead and write them bad boys to file
        System.out.println(buffer[0]+" "+buffer[1]+" "+buffer[2]);//peek at first 3 bytes received
        upack = (String)input.readObject();//get next 'packet' - either another UPACK or a UPLOAD_COMPLETE
      }
      outStream.flush();
      outStream.close();//make sure all bytes are in file
      input.close();//sign off
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
  } 
}

一如既往,非常感谢您的宝贵时间!

最佳答案

您的直接问题是 ObjectOutputStream 使用 ID 机制来避免多次通过流发送相同的对象。客户端将发送此 ID 用于 buffer 的第二次和后续写入,服务器将使用其缓存值。

这个紧迫问题的解决方案是添加对 reset() 的调用:

output.writeObject(buffer);//send bytes
output.reset(); // force buffer to be fully written on next pass through loop

除此之外,您通过在它们之上分层您自己的协议(protocol)来滥用对象流。例如,将文件名和文件大小写为由“|”分隔的单个字符串;只需将它们写成两个单独的值即可。每次写入的字节数也是如此。

关于java - 在 java 中通过 objectoutputstream 发送字节数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17662538/

相关文章:

java - 有关执行 GroupSequence 以按特定顺序评估 validator 注释的问题

java - 使用复选框在文本区域包装文本

java - SmartXLS 中列号和行号的公式地址 (java)

c - 为数组成员设置计时器

javascript - 在 IE 中,Javascript 数组项未定义

java - 相当于 conserve String 的环境变量

java - 对于数据报接收器来说,多少个线程比较合适?

c - TCC 和winsock.h

c - 通过 UDP 套接字发送消息时出现问题

ruby - 从 Ruby 中的键数组的散列中获取值的方法