nginx+tomcat使用apache的FtpClient上传图片时由于多线程问题导致的文件大小为0的问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zkn_CS_DN_2013/article/details/52918768

最近遇到这样一个问题:通过nginx反向代理上传图片时,发现上传之后的文件大小为0,并且nginx出现504错误,也就是说上传图片失败,但有时又不为0,,也就是说可以正常上传图片,直接通过ssh客户端工具上传图片也是没问题的。

nginx出现504网关超时错误是因为上游upstream服务器tomcat请求时响应时间过长,nginx迟迟无法收到tomcat的返回,于是出现超时错误,为什么会出现这种错误呢?

刚开始以为是nginx超时参数配置不当引起的,于是不断的对nginx相关超时参数和缓存参数进行调整,无果,

client_max_body_size         10m;
client_body_buffer_size       128k;
proxy_connect_timeout        90;
proxy_send_timeout          90;
proxy_read_timeout          90;
proxy_buffer_size           4k;
proxy_buffers             4 32k;
proxy_busy_buffers_size       64k;
proxy_temp_file_write_size     64k;

问题依旧。

难道是防火墙iptables问题,各种关闭防火墙,重试,依然无果,问题依旧。

难道是linux目录权限问题,各种授权777,重试,问题依旧。

研究了ftp的主动模式和被动模式:

 1.FTP的PORT(主动模式)和PASV(被动模式)

    (1) PORT(主动模式)

    PORT中文称为主动模式,工作的原理: FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,客户端随机开放一个端口(1024以上),发送 PORT命令到FTP服务器,告诉服务器客户端采用主动模式并开放端口;FTP服务器收到PORT主动模式命令和端口号后,通过服务器的20端口和客户端开放的端口连接,发送数据,原理如下图:

    (2) PASV(被动模式)
    PASV是Passive的缩写,中文成为被动模式,工作原理:FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,发送PASV命令到FTP服务器, 服务器在本地随机开放一个端口(1024以上),然后把开放的端口告诉客户端, 客户端再连接到服务器开放的端口进行数据传输,原理如下图:

 

    2.两种模式的比较

     从上面的运行原来看到,主动模式和被动模式的不同简单概述为: 主动模式传送数据时是“服务器”连接到“客户端”的端口;被动模式传送数据是“客户端”连接到“服务器”的端口。

    主动模式需要客户端必须开放端口给服务器,很多客户端都是在防火墙内,开放端口给FTP服务器访问比较困难。

    被动模式只需要服务器端开放端口给客户端连接就行了。

   3.不同工作模式的网络设置

    我在实际项目中碰到的问题是,FTP的客户端和服务器分别在不同网络,两个网络之间有至少4层的防火墙,服务器端只开放了21端口, 客户端机器没开放任何端口。FTP客户端连接采用的被动模式,结果客户端能登录成功,但是无法LIST列表和读取数据。很明显,是因为服务器端没开放被动模式下的随机端口导致。

    由于被动模式下,服务器端开放的端口随机,但是防火墙要不能全部开放,解决的方案是,在ftp服务器配置被动模式下开放随机端口在 50000-60000之间(范围在ftp服务器软件设置,可以设置任意1024上的端口段),然后在防火墙设置规则,开放服务器端50000-60000之间的端口端。

    主动模式下,客户端的FTP软件设置主动模式开放的端口段,在客户端的防火墙开放对应的端口段。

java中,内网用被动模式 ,外网连接时用主动模式,服务器相应改动(只用上线功能用被动模式去连接ftp报错连接不上)

FTPClient ftpClient = new FTPClient();

ftpClient.connect(url, port);

ftpClient.enterLocalActiveMode();    //主动模式
// ftpClient.enterLocalPassiveMode(); 被动模式
ftpClient.setControlEncoding("UTF-8");
ftpClient.changeWorkingDirectory(path);


难道是FtpClient主动被动模式的问题,于是各种设置:

本地被动模式:ftp.enterLocalPassiveMode();

远程本地模式:ftp.enterRemotePassiveMode();

问题依旧!



正愁闷之际,突然想到了多线程问题,难道是多线程惹的祸,于是修改成多线程模式,本地进行测试:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;



public class Test {
	public static boolean uploadFile(String url,int port,String username, String password, String path, final String filename, final InputStream input) throws InterruptedException {  
	    boolean success = false;  
	    final FTPClient ftp = new FTPClient();  
	    try {  
	        int reply;  
	        ftp.connect(url, port);//连接FTP服务器  
	        //如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器  
	        ftp.login(username, password);//登录  
	        ftp.setConnectTimeout(60);
//	        ftp.setSoTimeout(1);
	        reply = ftp.getReplyCode();  
	        if (!FTPReply.isPositiveCompletion(reply)) {  
	            ftp.disconnect();  
	            return success;  
	        }  
	        
	       ftp.setBufferSize(1);
		   ftp.setControlEncoding("UTF-8");

		   ftp.setFileType(2);
	       boolean b =  ftp.changeWorkingDirectory(path);  
	       System.out.println(b+"=====================");
	       final int[] a = new int[]{1,2};
	       List<Integer> l = new ArrayList<Integer>();
	       l.add(1);
	       l.add(2);
	       final Iterator<Integer>  itr = l.iterator();
	       for(int i=0;i<2;i++){
	    	   
	    	 new Thread(new Runnable() {
	    		   @Override
	    		   public void run() {
	    			   try {
	    				   String s = UUID.randomUUID().toString();
	    				   System.out.println(s);
	    				   ftp.storeFile(s+filename, new FileInputStream(new File("E:/temp/"+itr.next()+".png")));
	    			   } catch (IOException e) {
	    				   e.printStackTrace();
	    			   } 
	    		   }
	    	   }).start();
	    	   
	       }
	       Thread.currentThread().join();
//	        ftp.storeFile(filename, input);           
	        input.close(); 
//	        ftp.enterLocalPassiveMode();
//	        ftp.enterRemotePassiveMode();
	        ftp.logout();  
	        success = true;  
	    } catch (IOException e) {  
	        e.printStackTrace();  
	    } finally {  
	        if (ftp.isConnected()) {  
	            try {  
	                ftp.disconnect();  
	            } catch (IOException ioe) {  
	            }  
	        }  
	    }  
	    return success;
	}
	
	public static void main(String[] args) throws InterruptedException {
		try {  
	        FileInputStream in=new FileInputStream(new File("E:/temp/1.png"));  
	        boolean flag = uploadFile("192.168.47.43", 21, "mcip", "mcip", "/opt/mcipftp/ag", "xxx5.png", in);  
	        System.out.println(flag);  
	    } catch (FileNotFoundException e) {  
	        e.printStackTrace();  
	    } 
	}
	
}

问题果然重现!!!


对其进行多线程控制:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;



public class Test {
	public static boolean uploadFile(String url,int port,String username, String password, String path, final String filename, final InputStream input) throws InterruptedException {  
	    boolean success = false;  
	    final FTPClient ftp = new FTPClient();  
	    try {  
	        int reply;  
	        ftp.connect(url, port);//连接FTP服务器  
	        //如果采用默认端口,可以使用ftp.connect(url)的方式直接连接FTP服务器  
	        ftp.login(username, password);//登录  
	        ftp.setConnectTimeout(60);
//	        ftp.setSoTimeout(1);
	        reply = ftp.getReplyCode();  
	        if (!FTPReply.isPositiveCompletion(reply)) {  
	            ftp.disconnect();  
	            return success;  
	        }  
	        
	       ftp.setBufferSize(1);
		   ftp.setControlEncoding("UTF-8");

		   ftp.setFileType(2);
	       boolean b =  ftp.changeWorkingDirectory(path);  
	       System.out.println(b+"=====================");
	       final int[] a = new int[]{1,2};
	       List<Integer> l = new ArrayList<Integer>();
	       l.add(1);
	       l.add(2);
	       final Iterator<Integer>  itr = l.iterator();
	       for(int i=0;i<2;i++){
	    	   
	    	 new Thread(new Runnable() {
	    		   @Override
	    		   public void run() {
	    			   try {
	    				   String s = UUID.randomUUID().toString();
	    				   System.out.println(s);
	    				   //解决图片上传之后大小为0的问题
	    				   synchronized (itr) {
	    					   ftp.storeFile(s+filename, new FileInputStream(new File("E:/temp/"+itr.next()+".png")));
						}
	    			   } catch (IOException e) {
	    				   e.printStackTrace();
	    			   } 
	    		   }
	    	   }).start();
	    	   
	       }
	       Thread.currentThread().join();
//	        ftp.storeFile(filename, input);           
	        input.close(); 
//	        ftp.enterLocalPassiveMode();
//	        ftp.enterRemotePassiveMode();
	        ftp.logout();  
	        success = true;  
	    } catch (IOException e) {  
	        e.printStackTrace();  
	    } finally {  
	        if (ftp.isConnected()) {  
	            try {  
	                ftp.disconnect();  
	            } catch (IOException ioe) {  
	            }  
	        }  
	    }  
	    return success;
	}
	
	public static void main(String[] args) throws InterruptedException {
		try {  
	        FileInputStream in=new FileInputStream(new File("E:/temp/1.png"));  
	        boolean flag = uploadFile("192.168.47.43", 21, "mcip", "mcip", "/opt/mcipftp/ag", "xxx5.png", in);  
	        System.out.println(flag);  
	    } catch (FileNotFoundException e) {  
	        e.printStackTrace();  
	    } 
	}
	
}


问题解决!!!!!

阅读更多
换一批

没有更多推荐了,返回首页