资源描述
课 程 设 计
课程名称_计算机网络
题目名称_文件传输协议的简单设计与实现
学生学院_自动化学院
专业班级_13级物联网工程1班
学 号_3113001554
学生姓名 梁建斌
指导教师 刘洪涛
2015年12月25日
摘要
文件传送是各种计算机网络都实现的基本功能,文件传送协议是一种最基本的应用层协议按照客户/服务器的模式进行工作,提供交互式的访问。本设计是基于Eclipse平台下使用Java实现的FTP文件传输。实现基本的文件传输操作。建立客户端和服务器、客户端基于TCP Socket进行数据传输,采用多线程进行数据传输,套接字来实现。在实现过程中采用类与对象的思想进行规划,体验了一个软件开发过程的具体实现步骤。
关键字:Java网络编程 FTP文件传输 文件上传下载 文件操作
目录
一、 实验目的 3
二、 实验内容和要求 3
1、实验内容 3
2、具体要求 3
三、 实验主要仪器设备和材料 3
四、 基本原理 3
1.FTP系统模型 3
2. 系统功能设计 4
2.1总体设计 4
基本功能 4
2.2系统实现 4
五、 实现结构流程图 5
六、 整体实现的逻辑、数据结构
6
1.客户端的抽象数据类型 6
1.1FTPClient用户界面 6
1.2FTPClient控制连接线程 7
1.3FTPClient数据连接线程 7
2. 服务器的抽象数据类型 8
2.1 FTPServer的控制连接线程 8
2.2FTPServer的数据连接线程 9
七、 具体的一些方法实现
9
1. FTPClient用户界面 10
2. FTPClient控制连接 10
3. FTPClient数据传输 12
4. FTPServer控制连接 14
5. FTPServer数据传输 14
八、测试结果
客户端结果...............................................................................................................................................................16
服务端结果 16
九、 课程设计心得 17
十、 参考文献 18
一、 实验目的
文件传送是各种计算机网络都实现的基本功能,文件传送协议是一种最基本的应用层协议按照客户/服务器的模式进行工作,提供交互式的访问,是INTERNET使用最广泛的协议之一。
本实验的目的是,学会利用已有网络环境设计并实现简单应用层协议,掌握TCP/IP 网络应用程序基本的设计方法和实现技巧。
二、 实验内容和要求
1、实验内容
我们的计算机网络实验环境建立在TCP/IP 网络体系结构之上。各计算机除了安装TCP/IP 软件外,还安装了TCP/IP 开发系统。实验室各计算机具备Windows环境中套接字socket 的编程接口功能,可为用户提供全网范围的进程通信功能。本实验要求学生利用这些功能,设计和实现一个简单的文件传送协议。
2、具体要求
用socket 编程接口编写两个程序,分别为客户程序(client.c)和服务器程序(server.c),该程序应能实现下述命令功能:
get:取远方的一个文件
put:传给远方一个文件
pwd:显示远主当前目录
dir:列出远方当前目录
cd :改变远方当前目录
? :显示你提供的命令
quit :退出返回
这此命令的具体工作方式(指给出结果的形式)可以参照FTP 的相应命令,有余力的同学可以多实现几个命令。
最后,写出实验报告。
三、 实验主要仪器设备和材料
联网计算机 Eclipse JDK1.7帮助文档
四、 基本原理
1.FTP系统模型
FTP是Internet上传文件的应用层协议。FTP规定数据包的格式、数据包头部结构和命令结构等等。FTP应用TCP传输而不用UDP。由FTP提供的文件传输将一个完整的文件从一个系统复杂然后通过TCP套接字发送传输个另一个系统中。一方为服务器。一方为客户端。FTP建立两个TCP连接,一个用于数据传输,一个用于传输命令。每一个FTP主机都有一个“协议解析器”模块。FTP以纯文本形式发送,其响应同样也是纯文本形式。在进行文件传输时,FTP的客户端和服务器之间要建立两个并行的TCP连接:“控制连接”和“数据连接”。控制连接在整个连接回话的期间一直保持打开状态。当FTP客户端通过控制连接发送请求,并告诉服务器自己的数据连接的动态端口号(randomPort),服务器通过控制连接(2554)接收到请求信息,然后,创建数据连接(randomPort)进程进行连接客户端的数据传输端口。由于FTP采用两个不同的端口,所以数据连接和控制连接不会混乱。原理图看图1
输入的操作信息和数据传输进程的动态端口、
断点字节流
具体的数据字节流
控制进程
客户端
服务器
数据传输进程
控制进程
用户界面
数据传输进程
FTP采用两个TCP进行连接
图1
2. 系统功能设计
2.1总体设计
基本功能:Client Server界面设计 ;输入要连的远程主机服务器IP,上传任意格式的文件;下载任意格式文件(能实现断点续传);查看服务器的根目录;列出服务器当前文件夹目录,更改服务器当前文件夹目录再列出,
支持多客户同时数据访问服务器(通过控制层给传输层分配动态端口实现)。
2.2系统实现
系统功能实现:FTPServer启动控制连接线程ServerControlPro创建一个ServerSocket端口号为2554进行实况监听访问。FTPClient开启,启动用户界面菜单,输入IP后,弹出选择提示菜单,用户输入想实现的操作operating(get,put,dir,pwd,-cd)和相应其它信息(文件路径),然后FTPClient开启控制连接的线程ClientControlPro访问FTPServer的2554端口进行控制连接,并启动了数据连接线程ClientTransPro。服务器接收到FTPClient的请求和相关信息,进行启动数据连接ServerTransPro,监听客户端的数据连接。完成相应请求后。服务器关闭套接字,关闭数据连接线程。进入监听状态。
五、 实现结构流程图
六、整体实现的逻辑、数据结构
1.客户端的抽象数据类型
ADT Client
{
数据对象:控制线程 数据传输线程
数据关系:控制线程 控制 数据传输线程
三个类:
Class UserInterface;//用户界面
Class ClientControlPro;//控制进程
Class ClientDataTransPro;//数据传输进程
}
1.1FTPClient用户界面
ADT Client -UserInterface()
{
public static void main(String[] args)
{
System.out.println("请输入服务器ip地址");
serverIP =input.next();
optionmenu();
}
static void optionmenu()
{
System.out.println(" 欢迎来到FTP文件管理客户端 ");
System.out.println("-------------------------------");
System.out.println("请输入具体操作( h get put dir pwd -cd quit)");
String operating = input.next();
try
{
switch (operating)
{
case "h":
System.out.println("使用说明书!\n");
showUsingBook();
break;
case "get":
// 获取要下载的文件名
String getFileNmae = getFileName();
String[] a=getFileNmae.split("\\.",2);
houzui=a[1];
System.out.println("下载中---------");
new ClientControlPro(operating, getFileNmae,serverIP,houzui).start();// 控制连接
break;
case "put":
String putFileNmae = putFileName();
System.out.println("发送中----------");
new ClientControlPro(operating, putFileNmae,serverIP,houzui).start();
break;
case "dir":
System.out.println("开始操作列出远方当前目录功能!");
new ClientControlPro(operating, "",serverIP,houzui).start();
break;
case "pwd":
System.out.println("开始操作显示远主当前路径功能!");
new ClientControlPro(operating, "",serverIP,houzui).start();
break;
case "-cd":
System.out.println("开始操作改变远方当前目录文件功能!");
// 获取要更改文件的新路径
String cdFileDirName = getChangeDir();
new ClientControlPro(operating, cdFileDirName,serverIP,houzui).start();
break;
case "quit":
System.out.println("正在退出程序!");
System.exit(0);
break;
default:
break;
}
} optionmenu();
catch (Exception e1)
{
e1.printStackTrace();
System.out.println("客户端启动失败!");
}
}
1.2FTPClient控制连接线程
public class ClientControlPro extends Thread
{
String userCode = "";//传输给服务器的一窜控制信息
String operating;
String getFilename;
String serverIP;
String houzui;
long position;
int randomPort;
public ClientControlPro(String operating, String getFilename,String serverIP,String houzui){...}
public void run()
{
randomPort=new Random().nextInt(65535);//生成随机端口
userCode = operating + ":"+randomPort+":" + ":"+position+":" +getFilename;// 利用":"通过正则表达式拆分3个字符窜
sendMessage();//发送控制信息并启动传输端线程
}
sendMessage(){...}
}
1.3FTPClient数据连接线程
ClientTransPro extended Thread{
...
public ClientTransPro(String operating, String getFilename,String serverIP,
String houzui,int randomPort,long position)
{...}
public void run()
{
switch (operating)
{
case "get":
download();
break;
case "put":
upload(getFilename);
break;
case "pwd":
show();
break;
case "dir":
dir();
break;
case "-cd":
dir();
break;
default:
break;
}
}
}
2. 服务器的抽象数据类型
ADT Server{
数据对象:控制线程Socket (2554) 数据传输线程Socket(randomPort)
数据关系:控制线程 控制 数据传输线程
三个类:
ServerInterface//服务器入口
ServerControlPro//控制进程
ServerDataTransPro//数据传输进程
}
2.1 FTPServer的控制连接
public class ServerControlPro extends Thread {
... ...
public void run()
{
ServerSocket serverSocket;
serverSocket = new ServerSocket(2554);// 学号后三位加+2000
while (true)
{
System.out.println("监听到客户端请求第" + i + "个!\n");
// 控制线程
Socket s = serverSocket.accept();// 创建一个监听客户请求的套接字
i++;
getClientMessage(s);//接收客户端传来的控制信息并启动传输端线程
}
getClientMessage(s){...};
}
2.2FTPServer的数据连接
public class ServerDataTransPro extends Thread
{
String operating = "";
String getFilename = "";
String randomPort="";
Socket socket;
int serverRandomPort;
public ServerDataTransPro(String operating, String randomPort, String getFilename)
{
this.operating = operating;
this.getFilename = getFilename;
this.randomPort=randomPort;
}
public void run()
{
ServerSocket serverSocket = null;
try
{
serverRandomPort= new Integer(randomPort);
serverSocket = new ServerSocket(serverRandomPort);
boolean isflag = true;
while (isflag)
{
socket = serverSocket.accept();
System.out.println("有客户端" + socket.toString() + "连接本服务数据传输端");
if (socket != null)
{
switch (operating)
{
case "get":
System.out.println("控制端的操作是get");
download();
isflag = false;
break;
case "put":
System.out.println("控制端的操作是put");
put(socket);
isflag = false;
break;
case "pwd":
System.out.println("控制端的操作是pwd");
pwd();
isflag = false;
break;
case "dir":
System.out.println("控制端的操作是dir");
dir();
isflag = false;
break;
case "-cd":
System.out.println("控制端的操作是-cd");
cd();
isflag = false;
break;
default:
break;
}
}
isflag = false;
}
serverSocket.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
七、具体的一些方法实现
1. FTPClient控制连接的sendMessage()方法,访问服务器的2554端口,发送控制指令和指令信息给服务器的控制连接线程,并启动了自己的传输线程。
private void sendMessage()// 发送信息给服务器控制端
{
ClientTransPro ctp = new ClientTransPro(operating, getFilename,serverIP,houzui,randomPort,position);
Socket socket;
try
{
socket = new Socket(serverIP, 2554);
OutputStream osToSer = socket.getOutputStream();
InputStream isFromSer = socket.getInputStream();
osToSer.write(userCode.getBytes());
osToSer.close();
isFromSer.close();
socket.close();
ctp.start();
} catch (UnknownHostException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
2. FTPClient数据传输各操作方法实现
private void dir() //列出文件夹目录
{
try
{
Socket socket = new Socket(serverIP, randomPort);//动态端口randomPort
InputStream inputStream = socket.getInputStream();
// 缓存接收数据,然后进行显示服务器的路径:
byte[] recvbuf = new byte[1024];
int len;
while ((len = inputStream.read(recvbuf)) != -1)
{
len = inputStream.read(recvbuf);
}
String str = new String(recvbuf);
String[] dir = str.split(",");
for (int i = 0; i < dir.length; i++)
{
System.out.println(dir[i]);
}
inputStream.close();
socket.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
public void download()
{
// 下载文件操作
// 先进套接字访问服务器数据传输线程:
Socket socket;
try
{
socket = new Socket(serverIP, randomPort);
// 建立输入输出流进行数据通信:
InputStream inputStream = socket.getInputStream();
RandomAccessFile file_out = new RandomAccessFile("downloadfile."+houzui,"rw");//创建从中读取和向其中写入(可选)的随机访问文件流
int pos=(int)position;
file_out.seek(pos);//即定位到要开始下载的字节位置
byte[] bytes = new byte[10240];
while ((c = inputStream.read(bytes)) != -1)
{
file_out.write(bytes, 0, c);
}
// 关闭流和套接字
file_out.close();
inputStream.close();
} catch (UnknownHostException e1)
{
e1.printStackTrace();
} catch (IOException e1)
{
e1.printStackTrace();
}
}
public void upload(String filename)
{
try
{
/*
* 上传文件操作 先进套接字访问服务器数据传输线程和输入输出流的实现:
*/
Socket socket = new Socket(serverIP, randomPort);
InputStream inputStream = socket.getInputStream();
// 根据用户选择的文件路径进行读取本地文件到缓存中然后发送给服务器的数据传输线程。具体如下:
File file_in = new File(filename);
FileInputStream fis = new FileInputStream(file_in);
byte[] bytes = new byte[1024];
while ((c = fis.read(bytes)) != -1)
{
outputStream.write(bytes, 0, c);
}
fis.close();
inputStream.close();
socket.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
// 显示服务器的路径
public void show()
{
try
{
Socket socket = new Socket(serverIP, randomPort);
InputStream inputStream = socket.getInputStream();
// 缓存接收数据,然后进行显示服务器的路径:
byte[] recvbuf = new byte[1024];
int len;
while ((len = inputStream.read(recvbuf)) != -1)
{
len = inputStream.read(recvbuf);
}
System.out.println(new String(recvbuf));
inputStream.close();
socket.close();
} catch (IOException e)
{
e.printStackTrace();
}
}
3.FTPServer控制连接类各方法的实现
private void getClientMessage(Socket s)//接收客户端控制线程发来的控制信息
{
InputStream is = s.getInputStream();
byte[] b = new byte[1024];
int c;
StringBuffer sb = null;
String str = null;
while ((c = is.read(b)) != -1)
{
str = new String(b);
sb = new StringBuffer(str);
}
String[] a = sb.toString().split(":", 4);// 根据给定正则表达式的匹配拆分成四个字符串
String operating = a[0];
String randomPort=a[1];
String position=a[2];
String file = a[3].trim();
s.close();
new ServerDataTransPro(operating,randomPort, file,position).start();//传参给传输端,启动传输端线程。
}
4. FTPServer数据传输类各方法的实现
private void cd() //发送指定路径的目录
{
try
{
String sendDir = "";
StringBuffer sb = new StringBuffer();
String str;
File[] fs = new File(getFilename).listFiles();
if ((fs == null) || (fs.length <= 0))
{
sendDir = "空文件夹";
} else
{
for (int i = 0; i < fs.length; i++)
if (fs[i].isDirectory())
{
str = "目录:" + fs[i].getName() + ",";
sb = new StringBuffer(sb + str);
}
sendDir = sb.toString();
}
OutputStream os = socket.getOutputStream();
byte[] bytes = new byte[1024];
bytes = sendDir.getBytes();
os.write(bytes);
os.close();
socket.close();
} catch (FileNotFoundException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
private void dir()//发送服务器当前文件夹目录名称
{
try
{
String sendDir = "";
StringBuffer sb = new StringBuffer();
String str = "";
String string = System.getProperty("user.dir");//得到当前文件夹路径
System.out.println(string);
File[] fs = new File(string).listFiles();
if ((fs == null) || (fs.length <= 0))
{
sendDir = "空文件夹";
} else
{
for (int i = 0; i < fs.length; i++)
if (fs[i].isDirectory())
{
str = "目录:" + fs[i].getName() + ",";
sb = new StringBuffer(sb + str);
}
sendDir = sb.toString();//"目录:.settings,目录:bin,目录:src,"
}
OutputStream os = socket.getOutputStream();
byte[] bytes = new byte[1024];
bytes = sendDir.getBytes();
os.write(bytes);
os.close();
socket.close();
} catch (FileNotFoundException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
private void pwd()//发送当前文件夹绝对路径
{
String workingDir = System.getProperty("user.dir");
OutputStream os;
try
{
System.out.println(getFilename);
os = socket.getOutputStream();
byte[] bytes = new byte[1024];
bytes = workingDir.getBytes();
os.write(bytes);
os.close();
socket.close();
} catch (FileNotFoundException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
private void put(Socket socket)//接收客户端发来的文件
{
try
{
InputStream inputStream = socket.getInputStream();
String []str=getFilename.split("\\.",2);//得到发来的文件的后缀,能收到任意格式的文件
String houzui=str[1];
File file_out = new File("receivefile."+houzui);
FileOutputStream os = new FileOutputStream(file_out);
byte[] bytes = new byte[1024];
int c;
while ((c = inputStream.read(bytes)) != -1)
{
os.write(bytes, 0, c);
}
// 关闭流和套接字
os.close();
inputStream.close();
socket.close();
} catch (Exception e)
{
e.printStackTrace();
}
}
private void download()//发送客户端要下载的文件
{
// 建立输入输出流进行数据通信:
File file_in = new File(getFilename);
OutputStream os;
int c;
try
{
String str = file_in.toString();
System.out.println("file_in " + str);
RandomAccessFile randomAccessFile=new RandomAccessFi
展开阅读全文