TCP中Java文件传输中的OutOfMemoryError

TCP中Java文件传输中的OutOfMemoryError,java,tcp,out-of-memory,file-transfer,lan,Java,Tcp,Out Of Memory,File Transfer,Lan,我用java设计了一个文件发送程序和一个文件接收程序,以了解TCP文件在局域网上的传输。 我的文件发送代码如下 import java.io.*; import java.net.*; class filesender { public static void main(String args[]) throws Exception { InputStreamReader istream = new InputStreamReader(System.in); BufferedReader buf

我用java设计了一个文件发送程序和一个文件接收程序,以了解TCP文件在局域网上的传输。 我的文件发送代码如下

import java.io.*;
import java.net.*;
class filesender {
public static void main(String args[]) throws Exception
{
InputStreamReader istream = new InputStreamReader(System.in);
BufferedReader bufRead = new BufferedReader(istream);
try
{
System.out.println("Receiver's I.P:");
String serverName = bufRead.readLine();
System.out.println("File Name:");
String filename = bufRead.readLine();
Socket Socket1 = new Socket(serverName, 6789);
DataOutputStream outToServer=new DataOutputStream(Socket1.getOutputStream());
BufferedReader go=new BufferedReader(new InputStreamReader(Socket1.getInputStream()));
File file = new File(filename);
FileInputStream fin = new FileInputStream(file);
byte sendData[] = new byte[(int)file.length()];
fin.read(sendData);
outToServer.writeBytes(filename);
outToServer.writeInt(sendData.length);
outToServer.write(sendData, 0, sendData.length);
String deliveryreport = go.readLine();
System.out.println(deliveryreport);  /*Delivery report arrived from Receiver*/
Socket1.close();
}
catch (IOException err)
{ System.out.println("SENDER Error..!"); }}}
import java.io.*;
import java.net.*;
class filereceiver {
public static void main(String args[]) throws Exception
{
try
{
String filename;
ServerSocket serverSocket = new ServerSocket(6789);
System.out.println("Waiting on Port 6789...");
Socket conSocket = serverSocket.accept();
DataInputStream dis = new DataInputStream(conSocket.getInputStream());
BufferedReader hi = new BufferedReader(new InputStreamReader(conSocket.getInputStream()));
DataOutputStream outToSender = new DataOutputStream(conSocket.getOutputStream());
int dataLength = dis.readInt();
byte[] receivedData = new byte[dataLength];
for(int i = 0; i < receivedData.length; i++)
receivedData[i] = dis.readByte();
filename = hi.readLine();
FileOutputStream fos = new FileOutputStream(filename);
fos.write(receivedData);
fos.close();
outToSender.writeBytes("File has been Sent..!");/*Delivery report to sender*/
System.out.println("File has been received..!"); /*Viewed on Receiver*/
serverSocket.close();
conSocket.close();
}
catch (IOException err)
{ System.out.println("RECEIVER Error..!"); }}}
嗯。。。我的文件接收器编码如下

import java.io.*;
import java.net.*;
class filesender {
public static void main(String args[]) throws Exception
{
InputStreamReader istream = new InputStreamReader(System.in);
BufferedReader bufRead = new BufferedReader(istream);
try
{
System.out.println("Receiver's I.P:");
String serverName = bufRead.readLine();
System.out.println("File Name:");
String filename = bufRead.readLine();
Socket Socket1 = new Socket(serverName, 6789);
DataOutputStream outToServer=new DataOutputStream(Socket1.getOutputStream());
BufferedReader go=new BufferedReader(new InputStreamReader(Socket1.getInputStream()));
File file = new File(filename);
FileInputStream fin = new FileInputStream(file);
byte sendData[] = new byte[(int)file.length()];
fin.read(sendData);
outToServer.writeBytes(filename);
outToServer.writeInt(sendData.length);
outToServer.write(sendData, 0, sendData.length);
String deliveryreport = go.readLine();
System.out.println(deliveryreport);  /*Delivery report arrived from Receiver*/
Socket1.close();
}
catch (IOException err)
{ System.out.println("SENDER Error..!"); }}}
import java.io.*;
import java.net.*;
class filereceiver {
public static void main(String args[]) throws Exception
{
try
{
String filename;
ServerSocket serverSocket = new ServerSocket(6789);
System.out.println("Waiting on Port 6789...");
Socket conSocket = serverSocket.accept();
DataInputStream dis = new DataInputStream(conSocket.getInputStream());
BufferedReader hi = new BufferedReader(new InputStreamReader(conSocket.getInputStream()));
DataOutputStream outToSender = new DataOutputStream(conSocket.getOutputStream());
int dataLength = dis.readInt();
byte[] receivedData = new byte[dataLength];
for(int i = 0; i < receivedData.length; i++)
receivedData[i] = dis.readByte();
filename = hi.readLine();
FileOutputStream fos = new FileOutputStream(filename);
fos.write(receivedData);
fos.close();
outToSender.writeBytes("File has been Sent..!");/*Delivery report to sender*/
System.out.println("File has been received..!"); /*Viewed on Receiver*/
serverSocket.close();
conSocket.close();
}
catch (IOException err)
{ System.out.println("RECEIVER Error..!"); }}}
import java.io.*;
导入java.net。*;
类文件接收器{
公共静态void main(字符串args[])引发异常
{
尝试
{
字符串文件名;
ServerSocket ServerSocket=新的ServerSocket(6789);
System.out.println(“等待端口6789…”);
Socket conSocket=serverSocket.accept();
DataInputStream dis=新的DataInputStream(conSocket.getInputStream());
BufferedReader hi=新的BufferedReader(新的InputStreamReader(conSocket.getInputStream());
DataOutputStream outToSender=新的DataOutputStream(conSocket.getOutputStream());
int dataLength=dis.readInt();
字节[]接收数据=新字节[dataLength];
for(int i=0;i
好的,这些文件被正确编译和执行,但是当我尝试传输一个文件时,两个程序都会给出如下错误

给发件人程序一个IOException err//“发件人错误”////////////

接收程序说 //////////线程“main”java.lang.OutOfMemoryError中的异常:filereceiver.main处的java堆空间(filereceiver.java:17)////////////


为什么会发生这些错误?任何人都可以解释?

这一行,因为您正试图将整个流分配到RAM中

byte[] receivedData = new byte[dataLength];
当你的流很小的时候,它是可以的。但是对于大的流,分配一个小的缓冲区(例如10K)并分块读取

@nos还对服务器先写入文件名,然后写入文件长度给出了评论。您必须按照写入数据的顺序读取数据。但即使在读取了正确的数据后,您最终也会遇到我描述的问题。您肯定需要分块读取数据并边读边处理

此外,由于您将文件名发送给接收方,因此最好定义适当的结构/头/协议,以便接收方可以轻松处理传入的数据

  • 1字节表示文件名长度
  • 以下字节是实际的文件名
  • 8字节表示文件内容的长度
  • 以下字节是文件的内容

  • 在接收器端,您读取第一个字节以了解文件名要读取多少字节。然后读取8个字节以了解内容要读取多少字节。

    尝试使用如下JVM参数增加接收器端的堆内存

    -Xms512m -Xmx1g  -XX:PermSize=512m  -XX:MaxPermSize=1g
    

    缩进代码,以大写字母开头类名。您可能希望打印堆栈跟踪而不是自己的错误消息。类似于
    e.printStackTrace()
    您似乎先发送文件名,然后发送文件长度。您的接收者首先尝试读取文件长度,但由于您先发送文件名,您将文件名的4个字节解释为文件长度。这似乎有点倒退。(请注意,您可能还需要知道文件名的长度,否则您不知道需要阅读多少才能了解文件名。)@KEYSER:谢谢,先生。当我让“接收者”为“接收到的文件”命名时,成功了…上面的编码尝试在不更改文件名的情况下传输文件。OutOfMemoryError意味着您尝试分配的内存超过JVM允许的内存。一次将文件分为多个部分进行流式传输,您不会遇到此问题。有很多很多示例说明了如何执行此操作。顺便说一句,不要将文本(读写器)和二进制(流式)混合使用除非行混乱。不要一次读取一个字节的文件。如果要一次读取一个文件,请确保有足够的内存来执行此操作。要更进一步,请确保立即将块写出来。如果分块读取并将其保存在内存中,稍后也会遇到同样的问题。@jgitter,是的是的。一个文件长度需要八个字节,而不是四个字节,否则+1。@EJP,是的,您可以容纳大于4GB的文件。这是一个糟糕的主意。当文件大于可用内存大小时会发生什么情况?@jgitter我同意您的观点。但这不是最终的解决方案。这是一种与增加堆内存相结合的方法。您可以如果你知道你想处理大文件,就不要保留默认的堆大小。当然可以,你只需要智能地处理它们。不管你有多少内存,你最终都必须处理更大的数据流。你应该缓冲数据并将其与磁盘一起备份。亲爱的凯瑟,不,彼得·劳瑞,匿名,jgitter,和Jay…我做到了。通过你的回答,我意识到“内存分配必须减少”。我在文件发送后立即关闭了“conSocket”。同样,在文件被重新写入后,我关闭了“serverSocket”和“conSocket”。“从接收者向发送者发送的交付报告”也被删除了。现在程序运行得很好…!但是我不确定当我像你上面描述的那样传输一些更大的文件时是否会出现问题…:)无论如何,我以后会记住你的建议。再次感谢!