VSFTPD
一、简介
1、Linux的一个组件(一个软件),安装到Linux后通过java代码(FtpClient)实现文件上传(上传和下载的功能)
2、VSFTPD基于FTP协议
3、为什么使用VSFTPD
3.1 之前实现文件上传
客户端浏览器 tomcat 图片上传到tomcat
tomcat 集群
问题:
访问时跟存储不是同一个tomcat
重启容易丢失
3.2 使用VSFTP优化后
上传: 存图片需要文件夹,给到权限,可以直接创建在home下改用户拥有全部权限
客户端浏览器 tomcat集群 tomcat1 图片服务器(安装了VSFTPD的服务器)
tomcat2
3.2.1 如果希望直接在客户端直接访问图片服务器,由于VSFTPD是基于ftp协议,客户端浏览器是基于http协议
3.2.2 解决使用Nginx进行反向代理
二、VSFTPD安装
1、通过yum源安装
yum -y install vsftpd -y遇到需要确定的地方通通yes 安装完成后,有/etc/vsftpd/vsftpd.conf文件,是vsftp的配置文件
2、添加一个ftp用户
此用户是用来登录ftp服务器用的
useradd ftpuser 这样一个用户创建完成
passwd ftpuser 输入两次密码后修改密码
3、防火墙开启21端口
3.1 因为ftp默认端口是21端口,而censo是默认没有开启的,需要修改iptables文件
vim /etc/sysconfig/iptables
3.2 重启service iptables restart
3.3 修改selinux
外网可以访问上去,可是发现没办法返回目录(使用ftp主动模式,被动模式还是无法访问),也上传不了,需要修改selinux。
修改selinux:
执行以下命令查看 getsebool -a|grep ftp
allow_ftpd_full_access 和ftp_home_dir 是off状态,需要开启
setsebool -P allow_ftpd_full_access on
setsebool -P ftp_home_dir on
这样一般就没有问题了,如果还不能访问,查看ftp客户端工具是否使用了passive模式访问,如果提示Entering Passive mode,就代表是passive模式。
4、关闭匿名访问(不用用户密码也能访问)
修改 /etc/vsftpd/vsftpd.conf 文件 anonymous_enable=YES改为NO
重启ftp服务service vsftpd restart
5、开启被动模式(可能导致通过21端口连不上ftp)
默认是开启的,但是要指定一个端口范围,打开vsftpd.conf文件,在后面加上
pasv_min_port=30000
pasv_max_port=30999
表示端口范围为 30000~30999,这个可以随意改动。改完重启vsftpd。
同时,在防火墙里放开这个端口段。
6、设置开机启动vsftpd ftp服务
chkconfig vsftpd on
7、登录并取a.png文件
ftp://用户名:密码@IP/a.png (不推荐)
但是切换浏览器以后路径会更改。在IE中会访问到Linux的根目录,在谷歌访问到home下的ftpuser。
三、FTPClient
1、java技术,使用FTPClient,使用java代码上传到服务器
不依赖于容器jar项目都可以用。
1.1 连接IP和端口
1.2 用户名和密码登录
1.3 设置文件类型
1.4 上传文件
1.5 登出
工具类:
1 public static FTPClient connectFTPServer(String host , int port, String username ,String password){ 2 3 FTPClient ftpClient = new FTPClient(); 4 try { 5 ftpClient.connect(host, port); 6 int reply = ftpClient.getReplyCode(); 7 if (!FTPReply.isPositiveCompletion(reply)) { 8 ftpClient.disconnect(); 9 logger.error("FTP服务器 [" + host +":" + port+ "]拒绝连接"); 10 return null; 11 } 12 13 if (!ftpClient.login(username, password)) { 14 ftpClient.disconnect(); 15 logger.error("登陆[" + username +":" + port+ ","+ username +":" + username+ "]验证失败,请检查账号和密码是否正确"); 16 return null; 17 } 18 19 ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE); 20 } catch (SocketException e) { 21 logger.error("FTP服务器 [" + host +":" + port+ "]拒绝连接",e); 22 } catch (IOException e) { 23 logger.error("登陆[" + host +":" + port+ ","+ username +":" + password+ "]验证失败,请检查账号和密码是否正确",e); 24 } catch (Exception e){ 25 logger.error("登陆[" + host +":" + port+ ","+ username +":" + password+ "]验证失败,请检查账号和密码是否正确",e); 26 } 27 28 return ftpClient; 29 }
下载文件
1 public static File download(String fileFtpUrl,String targetFileName) 2 { 3 URI ftpUrl = null; 4 File targetFile; 5 //String name; 6 try { 7 ftpUrl = new URI(fileFtpUrl); 8 } catch (URISyntaxException e) { 9 logger.error("路径格式非法", e); 10 } 11 String userInfo = ftpUrl.getUserInfo(); 12 if(StringUtils.isEmpty(userInfo)) 13 { 14 userInfo = ":"; 15 } 16 String[] userApass = userInfo.split(":"); 17 FTPClient ftpClient = FtpUtil.connectFTPServer(ftpUrl.getHost(), ftpUrl.getPort()<0?21:ftpUrl.getPort(), 18 userApass[0], userApass[1]); 19 OutputStream os = null; 20 try { 21 if(StringUtils.isEmpty(targetFileName)){ 22 targetFileName = String.valueOf(System.currentTimeMillis()); 23 } 24 /*if(targetFileName.contains(File.separator)){ 25 name = targetFileName.substring(targetFileName.lastIndexOf(File.separator)+1); 26 }else{ 27 name = targetFileName; 28 }*/ 29 targetFile = new File(targetFileName); 30 targetFile.setWritable(true); 31 targetFile.setReadable(true); 32 ftpClient.enterLocalPassiveMode(); 33 try { 34 os = new FileOutputStream(targetFile); 35 } catch (Exception e) { 36 e.printStackTrace(); 37 }finally{ 38 if(os != null){ 39 os.close(); 40 } 41 } 42 43 Long startTime = System.currentTimeMillis(); 44 logger.info("下载开始时间为"+startTime); 45 boolean flag = ftpClient.retrieveFile(ftpUrl.getPath()+targetFileName, os); 46 if(flag){ 47 logger.info("下载成功"); 48 } 49 os.flush(); 50 Long endTime = System.currentTimeMillis(); 51 logger.info("下载结束时间为"+endTime); 52 Long time = endTime-startTime; 53 logger.info("本次下载共耗时"+time+"毫秒"); 54 return targetFile; 55 56 } 57 catch (FileNotFoundException e) 58 { 59 logger.error("ftp下载失败",e); 60 } 61 catch (IOException e) 62 { 63 logger.error("ftp下载失败",e); 64 } 65 finally 66 { 67 IOUtils.closeQuietly(os); 68 FtpUtil.closeConnect(ftpClient); 69 } 70 return null; 71 }
切换路径(创建)
1 public static boolean mkDir(FTPClient ftpClient, String dir){ 2 logger.info("待切换的FTP目录为:" + dir); 3 String pathChar = "/"; 4 String a = "\\"; 5 if(dir.contains(a)){ 6 dir = dir.replace("\\", pathChar); 7 } 8 9 try { 10 if(pathChar.equalsIgnoreCase(dir)){ 11 return true; 12 } 13 if(!ftpClient.changeWorkingDirectory(dir)){ 14 String[] dirArray = dir.split(pathChar); 15 for(String dirTmp : dirArray){ 16 //不存在 17 if(!StringUtils.isEmpty(dirTmp)&&!ftpClient.changeWorkingDirectory(dirTmp)){ 18 if(ftpClient.makeDirectory(dirTmp)){ 19 logger.info("从FTP服务器创建目录" + dirTmp + "成功"); 20 ftpClient.changeWorkingDirectory(dirTmp); 21 } 22 else{ 23 logger.info("从FTP服务器创建目录" + dirTmp + "失败"); 24 return false; 25 } 26 } 27 } 28 } 29 //切回根目录 30 ftpClient.changeWorkingDirectory("/"); 31 } catch (IOException e) { 32 logger.error("FTP切换目录失败",e); 33 return false; 34 } 35 return true; 36 }
2、web项目结合FTPClient完成
浏览器 -------> tomcat中的web项目,MultipartFile获取上传文件流,使用FtpClient -----> 上传到Linux中VSFTPD
<form id="dlg_form" method="post" enctype="multipart/form-data" action="upload"> <table class="input"> <tr id="iconInfo"> <th align="right">应用图标:</th> <td colspan="3"> <input type="file" name="icon" id="icon" class="input" style="width: 375px; height: 40px; float: left;" data-options='required:true'> <span style="font-size: 12px; -align: center;">支持.jpg;.png;.gif;<br>.tif;.psd;.ico格式的图片 </span> <div id="iconNameInfo"> </div> </td> </tr> <tr id="photoInfo"> <th align="right">应用图片:</th> <td colspan="3"> <input onchange="getPhotosName()" multiple="multiple" type="file" name="photos" id="photos" class="input"
style="width: 375px; height: 40px; float: left;" data-options='required:true'> <span style="font-size: 12px; -align: center;">支持.jpg;.png;.gif;<br>.tif;.psd;.ico格式的图片 </span> <div id="photosNameInfo"></div> </td> </tr> <tr id="fileMessageInfo"> <th align="right">升级包:</th> <td colspan="3"> <input type="file" name="file" id="file" class="input" style="width: 300px;" data-options='required:true'> <div id="fielNameInfo"> <a href="#" onclick="downfile();"> <font style="white-space: pre-line; word-break:break-all" id="fileInfo" title="单击可以进行升级包的下载"></font> </a> </div> </td> </tr> </table> </form>
@Controller public class UploadController{ @Resource private UploadService uploadService; @RequestMapping("/upload") public String Upload(MultipartFile file) throws IOException{ try{ boolean result = uploadService.upload(file); if(result){ return "/success.jsp"; } } catch(IOException e){ } return "/error.jsp"; } } @Service public class UploadService{ @Value("${ftpclient.host}") private String host; @Value("${ftpclient.port}") private int port; @Value("${ftmclient.userName}") private String userName; @Value("${ftpclient.password}") private String password; @Value("${ftpclient.basePath}") private String basePath; @Value("${ftpclient.filePath}") private String filePath; public boolean upload(MultipartFile file) throws IOException{ String fileName=UUID.randomUUID()+file.getOriginalFilename.substring(file.getOriginalFilename.lastIndexOf(".")); return FTPUtil.uploadFile(host,port,userName,password,basePath,filePath,fileName,file.getInputStream); } }
四、正向代理和反向代理
1、概念
1.1 正向代理服务器:客户端知道最终要访问的服务器地址。(FQ软件)
1.2 反向代理服务器:客户端只知道代理服务器地址,而不知道真实要访问的服务器地址。
Nginx反向代理服务,去访问图片服务器。
Nginx只能代理http,所以Nginx要跟图片服务器安装在同一个服务器上。
五、安装Nginx(俄罗斯C语言)
1、安装nginx之前(安装版,也可以解压tar.gz包)
1.1 如果没有gcc类库,安装gcc:yum install gcc-c++ -y -y需要确定的全yes
1.2 PCRE:yum install -y pcre pcre-devel pcre-devel是使用pcre开发的一个二次开发库。
PCRE是一个Perl库,包含perl兼容的正则表达式库。nginx的http模块使用pcre来解析正则表达式,所以要在linux上装pcre库。
1.3 zlib:yum install -y zlib zlib-devel
zlib库提供了很多压缩和解压缩的方式,nginx使用zlib对http包含的内容进行gzip,所以要在linux上装zlib库。
1.4 openssl:yum install -y openssl openssl-devel
openssl是一个强大的安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能以及SSL协议,并提供丰富的应用程序供测试或其他摸底使用。
nginx不仅支持http协议,还支持https(即在ssl协议上传输http),所以需要在linux安装openssl库。
2、编译和安装(所有用C语言的linux都需要编译安装)
2.1 解压nginx包,cd进nginx目录
2.2 configure 配置文件
--prefix=/usr/local/nginx 是安装目录
2.3 make 编译
2.4 makeinstall 安装
2.5 在nginx目录下的sbin中找到nginx可执行文件,./nginx 启动nginx,默认端口是80
2.6 快速停止nginx cd /usr/local/nginx/sbin ./nginx -s stop 此方式相当于先查出nginx进程id,再使用kill命令强制杀掉进程。
完全停止nginx cd /usr/local/nginx/sbin ./nginx -s quit 此方式停止步骤是待nginx进程处理任务完毕进行停止。(建议使用)
2.7 重启nginx 先停止再启动 ./nginx -s quit ./nginx(建议使用)
重新加载配置文件,当nginx的配置文件nginx.conf修改后,要想让配置文件生效,需要重启,使用 -s reload不用先停止nginx再启动nginx即可生效
cd /usr/local/nginx/sbin ./nginx -s reload
2.8 测试nginx安装成功,启动nginx,访问nginx出现welcome to nginx!表示成功
2.9 开机自启动nginx
编写shell脚本
vi /etc/init.d/nginx
设置文件权限
chmod a+x /etc/init.d/nginx (a+x : all user can execute 所有用户可以执行)
这样控制台就很容易操作nginxl
/etc/init.d/nginx status
/etc/init.d/nginx start
/etc/init.d/nginx stop
/etc/init.d/nginx restart
/etc/init.d/nginx reload
如果修改了nginx的配置文件nginx.conf,也可以使用上面的命令重新加载新的配置文件并运行,
可以将此命令加入到rc.local文件中,这样开机的时候nginx就默认启动了。
vi /etc/rc.local
加入一行 /etc/init.d/nginx start 保存并退出,下次重启会生效。
六、配置Nginx代理ftpuser目录
1、修改nginx配置文件
cd /usr/local/nginx/conf
vim nginx.conf
重启nginx。
再次访问,页面报403(没有权限)。
修改nginx.conf配置文件,赋予ftpuser权限。
重启nginx,再次访问nginx。(欢迎页也要配置)
2、在代码里访问文件
src定位到nginx中的文件地址就可以访问了。
<img src="http://IP:Port/文件.jpg">