通过socketjava发送大文件



我正在尝试通过套接字传输更大的文件。我将把文件分块传输。如代码所示。link

int count;
byte[] buffer = new byte[8192];
while ((count = in.read(buffer)) > 0)
{
  out.write(buffer, 0, count);
}

在发送这个文件之前,我想发送一个包含文件详细信息的对象。我应该使用哪个流发送Object+File。

我是流媒体的新手,可以获得任何示例代码吗。

我可以先发送对象的字节长度来读取对象、保存它并发送文件数据吗?有可能吗,有样本代码吗?

谢谢421

我不确定使用Java的序列化机制是否是进行简单文件传输的最佳方式。正如你的问题所暗示的那样,你尽量避免在任何时候都把整个文件保存在内存中。这可以使用代理模式对对象执行,但如果您只想传输文件,这可能不是最直接的解决方案。(此外,它还将有效地将您的对等应用程序绑定到Java中。)

相反,为什么不看看一个非常成功的协议,它正是你所需要的:HTTP。

Content-Type: application/octet-stream
Content-Length: 542183
542183 bytes of data follow...

为元数据头编写解析器应该不会太难。

您需要确保写入/读取的顺序。如果客户端上为write an object -> write raw bytes,则服务器上为read an object -> read raw bytes。读取时,ObjectInputStream应该能够找到序列化对象数据的边界。

如果您想使套接字连接长期有效并多次使用其流,那么将套接字的Output/InputStream封装在ObjectOutput/InputStream中不是一个好主意。当您关闭对象流时,它也会关闭底层流。

因此,您可能希望首先写入序列化对象数据的长度(文件长度包含在对象中,因此不需要显式写入),例如4字节的BigEndian编码的int。然后将对象序列化为ByteArrayOutputStream,并将字节写入其缓冲区。在服务器上,先读取4个字节,将字节解码回int,然后将这么多字节读取到byte[],用ByteArrayInputStream包裹字节数组,并从中反序列化对象。

这样写:

......
OutputStream out = socket.getOutputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);  
oos.writeObject(fileInfoObject);
oos.close();
byte[] header = encodeInteger(baos.size());
out.write(header, 0, 4);
baos.writeTo(out);
// write the file to out just as your question shows

在接收端:。。。。。。InputStream in=socket.getInputStream();

// read the int
byte[] header = new byte[4];
in.read(header, 0, 4);
int size = decodeInteger(header);
// read the object
byte[] objectbuf = new byte[size];
int count;
while((count += in.read(objectbuf)) < size); // not sure if this works...
ObjectInputStram ois = new ObjectInputStream(new ByteArrayInputStream(objectbuf));
Object fileInfoObject = ois.readObject();
ois.close();
// read the file
FileOutputStream fos = new FileOutputStream(new File("somefile"));
byte[] buffer = new byte[8192];
count = 0;
long left = castedFileInfoObject.fileSize;
// also not sure if this works, not tested.
int maxRead = buffer.length;
while (true) {
    count = in.read(buffer, 0, maxRead);
    left -= count;
    if (left < 8192) {
        maxRead = (int)left;
    }
    fos.write(buffer, 0, count);
    if (left == 0) {
        break;
    }
}

我还没有在回答中测试示例代码。。只是为了展示这个想法。

class-MyClass应该实现Serializable接口。然后,可以将此类的对象写入ObjectOutputStream,并使用writeObject和readObject方法从ObjectInputStream中读回(请参见下文)。

客户端:

Socket socket = new Socket(url, port);  
OutputStream os = socket.getOutputStream();  
ObjectOutputStream oos = new ObjectOutputStream(os);  
MyClass obj = new Myclass();  
oos.writeObject(obj);  
int count;
byte[] buffer = new byte[8192];
while ((count = in.read(buffer)) > 0) {
  out.write(buffer, 0, count);
}

服务器上:

ServerSocket sSocket = new ServerSocket(port);
Socket socket = sSocket.accept();  
InputStream is = socket.getInputStream();  
ObjectInputStream ois = new ObjectInputStream(is);  
MyClass obj = (MyClass)ois.readObject();
byte arr[];
try {
  while(arr = (byte[])ois.readObject()) {
    //do something with arr
  }
} catch(java.io.EOFException) {
  // End of data
}

如果你需要在文件完成后发送更多的数据,你需要一种方法来计算文件包含的字节数。然后,您可以通过套接字预先将字节数发送到服务器。在服务器上,只读取文件的信息字节数,然后对要发送的其余数据执行相同操作。这种预先发送文件大小的策略是推荐的,主要用于进行任何数据传输。如果可以做到这一点,就不必依赖于捕获java.io.EOFException来检测数据的末尾。

相关内容

  • 没有找到相关文章

最新更新