package com.ftp.client;
import java.net.*;
import java.io.*;
/**
* FTP客户端程序
* @author caiqq
*
*/
public class FtpClient
{
/**
* 初始化FTP客户端
* @param args args[0]:IP args[1]:端口
* @return clientSocket:客户端Socket
*/
public Socket init(String[] args)
{
Socket clientSocket=null;
if(args.length>0)
{
try
{
//接收参数,传递服务器ip和 port
InetAddress ip=InetAddress.getByName(args[0]);
int port = Integer.parseInt(args[1]);
clientSocket=new Socket(ip,port);
//初始化下载文件存放文件夹"Download"
File downDirctory=new File("Download");
if(!downDirctory.exists())
{
downDirctory.isDirectory();
downDirctory.mkdir();
}
}
catch(Exception ex)
{
System.out.println("error");
ex.printStackTrace();
}
}
else
{
System.out.println("Tip:the usage of the program is set the 'ip' and 'port';");
}
return clientSocket;
}
/**
* 功能:从FTP服务器上退出
* @param sentToServer 发送给FTP服务端的控制信息
*/
public void quit(PrintWriter sentToServer)
{
sentToServer.println("quit");//向FTP服务器端发送"quit"命令
}
/**
* 列表显示FTP服务器端的共享文件
* @param sentToServer 发送给FTP服务端的控制信息
*/
public void listFiles(PrintWriter sentToServer)
{
sentToServer.println("ls");//向FTP服务器端发送"ls"命令
}
/**
* 从FTP服务器端下载文件
* @param is FTP客户端套接字输入流
* @param recv 监听FTP服务器反馈信息的线程
* @param sentToServer 发送给FTP服务端的控制信息
* @param synObject 线程同步的对象标识
* @param keyBoardIn FTP客户端键盘的输入控制信息
* @param serverIn 接受FTP服务器端关于文件传输的控制信息
*/
public void downFromServer(InputStream is,Receive recv,PrintWriter sentToServer,String synObject,BufferedReader keyBoardIn,BufferedReader serverIn)
{
sentToServer.println("get");//向FTP服务器端发送"get"命令
recv.stopNow(true);//停止接收线程
sentToServer.println("ready");//发送第一轮握手标志“ready”
//下面的一个同步块就是用来将控制信息传输流转换成数据传输流
synchronized(synObject)
{
while(true)
{
try
{
// 双方达成协议 开始传发文件
if ((serverIn.readLine()).equalsIgnoreCase("accept"))
{
System.out.println("Protocol:" + "accept");
String fileName = null;
sentToServer.println(fileName = keyBoardIn.readLine());
String handShake = serverIn.readLine();
if (handShake == null|| handShake.equalsIgnoreCase("stop"))
{
System.out.println("**warnning**:This file can'n be download! ");
}
else
{
int fileLength = Integer.parseInt(handShake);
// System.out.println("待下载文件大小:"+fileLength);
FileOutputStream fileCopy = new FileOutputStream("."+File.separator+"Download"+File.separator + fileName);
TransferInfo transferInfo = new TransferInfo();// 文件传输时输出"."的线程
Thread transferThread = new Thread(transferInfo);
transferInfo.startNow(true);
transferThread.start();
// 通过文件大小实现文件的同步传输
for (int i = 0; i < fileLength; i++)
{
fileCopy.write(is.read()); // 将文件下载到本地
}
fileCopy.close();// 关闭文件
sentToServer.println("finished");// 发送文件下载完毕信号
transferInfo.stopNow(true);// 传输完毕,终止输出"."
}
synObject.notify();// 将数据流又切换到控制流
recv.startNow(true);// 打开接收线程
Thread.sleep(1000);
break;
}
} catch (Exception e)
{
e.printStackTrace();
}
}
}
}
/**
* 从FTP客户端上传文件
* @param os FTP客户端套接字输出流
* @param recv 监听FTP服务器反馈信息的线程
* @param sentToServer 发送给FTP服务端的控制信息
* @param synObject 线程同步的对象标识
* @param keyBoardIn FTP客户端键盘的输入控制信息
* @param serverIn 接受FTP服务器端关于文件传输的控制信息
*/
public void upToServer(OutputStream os,Receive recv,PrintWriter sentToServer,String synObject,BufferedReader keyBoardIn,BufferedReader serverIn)
{
sentToServer.println("put");//向FTP服务器端发送"get"命令
recv.stopNow(true);//停止接收线程
sentToServer.println("ready");//发送第一轮握手标志“ready”
//下面的一个同步块就是用来将控制信息传输流转换成数据传输流
synchronized(synObject)
{
while(true)
{
try
{
// 双方达成协议 开始传发文件
if ((serverIn.readLine()).equalsIgnoreCase("accept"))
{
System.out.println("Protocol:" + "accept");
int content;
String fileName = null;
sentToServer.println(fileName = keyBoardIn.readLine());
// String pathName=path+fileName;
File file = new File(fileName);
if (!file.exists())
{
sentToServer.println("stop");// 文件停止传送
System.out.println("The uploaded file 【" + fileName+ "】not exits!Please check.");
}
else
{
sentToServer.println("continue");// 文件继续传送
FileInputStream checkFile = new FileInputStream(fileName);
try
{
int fileLength = 0;
// 读写文件的大小
while ((content = checkFile.read()) != -1)
{
fileLength++;
}
sentToServer.println(fileLength);// 获取待上传文件的大小并发送到服务器端
checkFile.close();// 关闭文件
Thread.sleep(500);// 此处线程等待是为了保证读取同一个文件时不会出现重写错误
FileInputStream upFile = new FileInputStream(fileName);
TransferInfo transferInfo = new TransferInfo();// 文件传输时输出"."的线程
Thread transferThread = new Thread(transferInfo);
transferInfo.startNow(true);
transferThread.start();
// 按字节的形式将文件传送到服务端
while ((content = upFile.read()) != -1)
{
os.write(content);
}
upFile.close();// 关闭文件
transferInfo.stopNow(true);// 传输完毕,终止输出"."
} catch (Exception ex)
{
System.out.println("**warnning**:This file can'n be uploaded! ");
}
}
}
sentToServer.println("finished");// 发送文件下载完毕信号
synObject.notify();// 将数据流又切换到控制流
recv.startNow(true);// 打开接收线程
Thread.sleep(1000);
break;
} catch (Exception e)
{
e.printStackTrace();
}
}
}
}
/**
* FTP客户端运行主程序
* @param clientSocket FTP客户端套接字
* @throws Exception
*/
public void run(Socket clientSocket) throws Exception
{
String synObject=""; // 线程同步资源
BufferedReader keyBoardIn=new BufferedReader(new InputStreamReader(System.in));
String instruction=null; // 客户端的控制指令
OutputStream os=clientSocket.getOutputStream();// 套接字输出流
InputStream is=clientSocket.getInputStream();// 套接字输入流
PrintWriter sentToServer=new PrintWriter(os,true);//发送给服务端的控制流的封装
BufferedReader serverIn=new BufferedReader(new InputStreamReader(is));//接收服务器发来的信息
Receive recv=new Receive(is,os,synObject);//FTP服务器的监听线程
Thread recvThread=new Thread(recv); // 建立接收服务数据的线程
recvThread.setDaemon(true);//将线程设置成后台的以便于随主程序终止而终止
recvThread.start();
while(true)
{
instruction=keyBoardIn.readLine();
if(instruction.equalsIgnoreCase("quit"))
{
//退出FTP服务器端
quit(sentToServer);
break;
}
else if(instruction.equalsIgnoreCase("ls"))
{
//显示FTP服务器端的共享文件
listFiles(sentToServer);
}
else if(instruction.equalsIgnoreCase("get"))
{
//从FTP服务器端下载文件
downFromServer(is,recv,sentToServer,synObject,keyBoardIn,serverIn);
}
else if(instruction.equalsIgnoreCase("put"))
{
//从F
- 1
- 2
前往页