通过 WAN 发送文件卡住了(Java 套接字)
Sending file over WAN stuck (Java Socket)
我在使用 java 套接字通过 Internet 发送文件时遇到了一个非常奇怪的问题。我有一个 Java 服务器,在 LAN 中工作得很好,它可以通信并传输 运行 文件。
问题出在 WAN 中:当我 运行 远程 PC 上的服务器时,客户端可以与服务器通信,但当它尝试向服务器发送文件时,他会卡在 0%。它通常发生在大文件(>= 100 MB)上,但有时也会发生在小文件上。
请有人帮助我 :),谢谢。
服务器接收码:
public void ReceiveFile(int fileSize, Socket sock, String fileName, String cmrId, PrintWriter pw){
folderCheck(cmrId);
FileOutputStream fos= null;
BufferedOutputStream bos= null;
try {
int ret;
int bytesRead=0;
fos= new FileOutputStream(cmrId+"/"+fileName); //receive file to User Dedicated folder
bos= new BufferedOutputStream(fos);
//InputStream input= sock.getInputStream();
byte[] bytesArray= new byte[fileSize];
DataInputStream dis= new DataInputStream(sock.getInputStream());
ret= dis.read(bytesArray, 0, bytesArray.length);
bytesRead= ret;
//System.out.println("CmrFoldMan -- Received " + bytesRead + " of " + fileSize); //debug
while(bytesRead<fileSize){
ret= dis.read(bytesArray, bytesRead, (bytesArray.length-bytesRead));
if(ret>=0) bytesRead+=ret;
//System.out.println("CmrFoldMan -- Received " + bytesRead + " of " + fileSize); //debug
}
bos.write(bytesArray, 0, bytesRead);
bos.flush();
upHist= new UpdateHistory(fileName, fileSize, cmrId);
upHist.update();
daysLimit.deleteFilesLimit(fileSize, cmrId); //delete files that exceed memory limit
} catch (IOException ex) {
Logger.getLogger(CmrFolderManager.class.getName()).log(Level.SEVERE, null, ex);
}
finally{
try {
fos.close();
bos.close();
} catch (IOException ex) {
Logger.getLogger(CmrFolderManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
客户端发送代码:
public long upload(String fileToSend){
long uploadTimerStart = System.currentTimeMillis(); //start timer
if(contactServerCheckError()) return -1;
try{
pw.println(fileSize);
pw.println(fileName);
Socket sendSock= new Socket(ip, filePort); //connecting to sending file port
DataOutputStream dos= new DataOutputStream(sendSock.getOutputStream());
File file= new File(fileToSend);
int arraySize= (int)file.length(); //used for println only
byte[] array= new byte[1024]; //array is 1024 to use progress bar
fis= new FileInputStream(file);
bis= new BufferedInputStream(fis);
int len;
int tmpBytes=0;
while((len= bis.read(array))>0){
//System.out.println("SendFile " + tmpBytes + " bytes " + "of " + arraySize); //debug
dos.write(array, 0, len);
dos.flush();
tmpBytes+=len;
updateProgressBars(tmpBytes);
updateLabelsPercentage(tmpBytes);
}
} catch (FileNotFoundException ex) {
Logger.getLogger(SendFile.class.getName()).log(Level.SEVERE, null, ex);
return -1;
} catch (IOException ex) {
Logger.getLogger(SendFile.class.getName()).log(Level.SEVERE, null, ex);
return -1;
}
finally{
try{
if(bis!=null) bis.close();
if(os!=null) os.close();
//if(sock!=null) sock.close();
} catch (IOException ex) {
Logger.getLogger(SendFile.class.getName()).log(Level.SEVERE, null, ex);
JOptionPane.showMessageDialog(null, "ERROR " + ex);
return -1;
}
}
long uploadTimerEnd = System.currentTimeMillis(); //end timer
long uploadTimerDelta= uploadTimerEnd - uploadTimerStart;
return uploadTimerDelta;
}
好吧...对于初学者...据我所知,在接收代码中您正在创建一个字节数组,它是目标文件的大小,
byte[] bytesArray= new byte[fileSize];
然后你继续从输入流读取到字节数组,直到它已满,
while(bytesRead<fileSize){
ret= dis.read(bytesArray, bytesRead, (bytesArray.length-bytesRead));
然后你一次性写到文件里
bos.write(bytesArray, 0, bytesRead);
如您所述,对于 100MB 的文件,这意味着您拥有 100MB 的内存。这不是……好主意。
fos= new FileOutputStream(cmrId+"/"+fileName);
InputStream is = sock.getInputStream());
int read = 0;
byte[] buf = new byte[1024];
while( (read = is.read(buf)) != -1) {
fos.write(buf, 0, read);
}
上面的代码抛弃了您正在使用的 DataInputStream(据我所知它没有添加任何内容)并且一次最多读取 1024 个字节并将其以块的形式写入 FileOutputStream 而不会在其中保存超过 1 千字节的内容记忆。试一试,看看它是否更可靠。
我在使用 java 套接字通过 Internet 发送文件时遇到了一个非常奇怪的问题。我有一个 Java 服务器,在 LAN 中工作得很好,它可以通信并传输 运行 文件。 问题出在 WAN 中:当我 运行 远程 PC 上的服务器时,客户端可以与服务器通信,但当它尝试向服务器发送文件时,他会卡在 0%。它通常发生在大文件(>= 100 MB)上,但有时也会发生在小文件上。
请有人帮助我 :),谢谢。
服务器接收码:
public void ReceiveFile(int fileSize, Socket sock, String fileName, String cmrId, PrintWriter pw){
folderCheck(cmrId);
FileOutputStream fos= null;
BufferedOutputStream bos= null;
try {
int ret;
int bytesRead=0;
fos= new FileOutputStream(cmrId+"/"+fileName); //receive file to User Dedicated folder
bos= new BufferedOutputStream(fos);
//InputStream input= sock.getInputStream();
byte[] bytesArray= new byte[fileSize];
DataInputStream dis= new DataInputStream(sock.getInputStream());
ret= dis.read(bytesArray, 0, bytesArray.length);
bytesRead= ret;
//System.out.println("CmrFoldMan -- Received " + bytesRead + " of " + fileSize); //debug
while(bytesRead<fileSize){
ret= dis.read(bytesArray, bytesRead, (bytesArray.length-bytesRead));
if(ret>=0) bytesRead+=ret;
//System.out.println("CmrFoldMan -- Received " + bytesRead + " of " + fileSize); //debug
}
bos.write(bytesArray, 0, bytesRead);
bos.flush();
upHist= new UpdateHistory(fileName, fileSize, cmrId);
upHist.update();
daysLimit.deleteFilesLimit(fileSize, cmrId); //delete files that exceed memory limit
} catch (IOException ex) {
Logger.getLogger(CmrFolderManager.class.getName()).log(Level.SEVERE, null, ex);
}
finally{
try {
fos.close();
bos.close();
} catch (IOException ex) {
Logger.getLogger(CmrFolderManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
客户端发送代码:
public long upload(String fileToSend){
long uploadTimerStart = System.currentTimeMillis(); //start timer
if(contactServerCheckError()) return -1;
try{
pw.println(fileSize);
pw.println(fileName);
Socket sendSock= new Socket(ip, filePort); //connecting to sending file port
DataOutputStream dos= new DataOutputStream(sendSock.getOutputStream());
File file= new File(fileToSend);
int arraySize= (int)file.length(); //used for println only
byte[] array= new byte[1024]; //array is 1024 to use progress bar
fis= new FileInputStream(file);
bis= new BufferedInputStream(fis);
int len;
int tmpBytes=0;
while((len= bis.read(array))>0){
//System.out.println("SendFile " + tmpBytes + " bytes " + "of " + arraySize); //debug
dos.write(array, 0, len);
dos.flush();
tmpBytes+=len;
updateProgressBars(tmpBytes);
updateLabelsPercentage(tmpBytes);
}
} catch (FileNotFoundException ex) {
Logger.getLogger(SendFile.class.getName()).log(Level.SEVERE, null, ex);
return -1;
} catch (IOException ex) {
Logger.getLogger(SendFile.class.getName()).log(Level.SEVERE, null, ex);
return -1;
}
finally{
try{
if(bis!=null) bis.close();
if(os!=null) os.close();
//if(sock!=null) sock.close();
} catch (IOException ex) {
Logger.getLogger(SendFile.class.getName()).log(Level.SEVERE, null, ex);
JOptionPane.showMessageDialog(null, "ERROR " + ex);
return -1;
}
}
long uploadTimerEnd = System.currentTimeMillis(); //end timer
long uploadTimerDelta= uploadTimerEnd - uploadTimerStart;
return uploadTimerDelta;
}
好吧...对于初学者...据我所知,在接收代码中您正在创建一个字节数组,它是目标文件的大小,
byte[] bytesArray= new byte[fileSize];
然后你继续从输入流读取到字节数组,直到它已满,
while(bytesRead<fileSize){
ret= dis.read(bytesArray, bytesRead, (bytesArray.length-bytesRead));
然后你一次性写到文件里
bos.write(bytesArray, 0, bytesRead);
如您所述,对于 100MB 的文件,这意味着您拥有 100MB 的内存。这不是……好主意。
fos= new FileOutputStream(cmrId+"/"+fileName);
InputStream is = sock.getInputStream());
int read = 0;
byte[] buf = new byte[1024];
while( (read = is.read(buf)) != -1) {
fos.write(buf, 0, read);
}
上面的代码抛弃了您正在使用的 DataInputStream(据我所知它没有添加任何内容)并且一次最多读取 1024 个字节并将其以块的形式写入 FileOutputStream 而不会在其中保存超过 1 千字节的内容记忆。试一试,看看它是否更可靠。