1、 高级网络程序设计课程设计报告题 目 FTP 文件传输协议 学 号 11102410 姓 名 倪福柱 计算机网络工程教研室2015 年 01 月 12 日I目 录一、 实验目的 二、 实验内容和要求1、实验内容2、具体要求三、需要完成的的内容1.FTP 系统模型.2. 系统功能设计2.1 总体设计.2.2 系统实现四、具体实现步骤1. FTPClient 用户界面的实现.2. FTPClient 控制连接的实现.3. FTPClient 数据传输连接的实现.3.1 下载文件操作3.1 下载文件操作3.3 显示服务器的路径3.4 进入服务器更改路径4. FTPServer 控制连接的实现 5.
2、FTPServer 数据传输线程的实现 5.1 读取本地文件下载给客户端5.2 接收客户端的上传的文件5.3 获取服务器本地系统路径五、实验结果.六、实验心得.天津科技大学计算机学院 高级网络程序设计课程设计1一、课程设计内容1、实验内容 我们的计算机网络实验环境建立在 TCP/IP 网络体系结构之上。各计算机除了安装TCP/IP 软件外,还安装了 TCP/IP 开发系统。实验室各计算机具备 Windows 环境中套接字 socket 的编程接口功能,可为用户提供全网范围的进程通信功能。本实验要求学生利用这些功能,设计和实现一个简单的文件传送协议。二、设计目的文件传送是各种计算机网络都实现的基
3、本功能,文件传送协议是一种最基本的应用层协议按照客户/服务器的模式进行工作,提供交互式的访问,是 INTERNET 使用最广泛的协议之一。 本实验的目的是,学会利用已有网络环境设计并实现简单应用层协议,掌握TCP/IP 网络应用程序基本的设计方法和实现技巧。三、具体要求用 socket 编程接口编写两个程序,分别为客户程序(client.c)和服务器程序(server.c ) ,该程序应能实现下述命令功能:get:取远方的一个文件put:传给远方一个文件pwd:显示远主当前目录pwd:显示远主当前目录cd :改变远方当前目录? :显示你提供的命令quit :退出返回这此命令的具体工作方式(指给
4、出结果的形式)可以参照 FTP 的相应命令,有余力的同学可以多实现几个命令。 最后,写出实验报告。1. FTPSERVER 服务器界面的实现2自动获取服务器代码:TcpListener myTcpListener = null;private Thread listenThread;/ 保存用户名和密码Dictionary users;public FtpServerForm()InitializeComponent();/ 初始化用户名和密码 users = new Dictionary();users.Add(“admin“, “admin“);/ 设置默认的主目录tbxFtpRoot.T
5、ext = “D:/MyFtpServerRoot/“;IPAddress ips = Dns.GetHostAddresses(“);tbxFtpServerIp.Text = ips1.ToString();tbxFtpServerPort.Text = “21“;lstboxStatus.Enabled = false;服务器启动代码:/ 启动服务器private void btnFtpServerStartStop_Click(object sender, EventArgs e)if (myTcpListener = null)listenThread = new Thread(Li
6、stenClientConnect);3listenThread.IsBackground = true;listenThread.Start();lstboxStatus.Enabled = true;lstboxStatus.Items.Clear();lstboxStatus.Items.Add(“已经启动Ftp服务.“);btnFtpServerStartStop.Text = “停止“;elsemyTcpListener.Stop();myTcpListener = null;listenThread.Abort();lstboxStatus.Items.Add(“Ftp服务已停止!
7、“);lstboxStatus.TopIndex = lstboxStatus.Items.Count - 1;btnFtpServerStartStop.Text = “启动“;监听客户端代码:private void ListenClientConnect()myTcpListener = new TcpListener(IPAddress.Parse(tbxFtpServerIp.Text), int.Parse(tbxFtpServerPort.Text);/ 监听端口,处理客户端连接myTcpListener.Start();AddInfo(“启动FTP服务成功!“);AddInfo
8、(“Ftp服务器运行中.点击”停止“按钮停止FTP服务“);while (true)try/ 接收连接请求TcpClient tcpClient = myTcpListener.AcceptTcpClient();AddInfo(string.Format(“客户端(0)与本机(1)建立Ftp连接“, tcpClient.Client.RemoteEndPoint, myTcpListener.LocalEndpoint);User user = new User();mandSession = new UserSeesion(tcpClient);user.workDir = tbxFtpR
9、oot.Text;Thread t = new Thread(UserProcessing);t.IsBackground = true;t.Start(user);catch4break;处理客户端请求:private void UserProcessing(object obj)User user = (User)obj;string sendString = “220 FTP Server v1.0“;RepleyCommandToUser(user, sendString);while (true)string receiveString = null;try/ 读取客户端发来的请求信
10、息receiveString = mandSession.streamReader.ReadLine();catch(Exception ex)if (mandSession.tcpClient.Connected = false)AddInfo(string.Format(“客户端(0断开连接!)“ mandSession.tcpClient.Client.RemoteEndPoint);elseAddInfo(“接收命令失败!“ + ex.Message);break;if (receiveString = null)AddInfo(“接收字符串为null,结束线程!“);break;Ad
11、dInfo(string.Format(“来自0:1“, mandSession.tcpClient.Client.RemoteEndPoint, receiveString);5/ 分解客户端发来的控制信息中的命令和参数 string command = receiveString;string param = string.Empty;int index = receiveString.IndexOf( );if (index != -1)command = receiveString.Substring(0, index).ToUpper();param = receiveString.
12、Substring(command.Length).Trim();/ 处理不需登录即可响应的命令(这里只处理QUIT) if (command = “QUIT“)/ 关闭TCP连接并释放与其关联的所有资源mandSession.Close();return;elseswitch (user.loginOK)/ 等待用户输入用户名case 0:CommandUser(user, command, param);break;/ 等待用户输入密码case 1:CommandPassword(user, command, param);break;/ 用户名和密码验证正确后登陆case 2:switc
13、h (command)case “CWD“:CommandCWD(user, param);break;case “PWD“:CommandPWD(user);break;case “PASV“:CommandPASV(user);break;6case “PORT“:CommandPORT(user, param);break;case “LIST“:CommandLIST(user, param);break;case “NLIST“:CommandLIST(user, param);break;/ 处理下载文件命令case “RETR“:CommandRETR(user, param);
14、break;/ 处理上传文件命令case “STOR“:CommandSTOR(user, param);break;/ 处理删除命令case “DELE“:CommandDELE(user, param);break;/ 使用Type命令在ASCII和二进制模式进行变换 case “TYPE“:CommandTYPE(user, param);break;default:sendString = “502 command is not implemented.“;RepleyCommandToUser(user, sendString);break;break; 2. FTPClient 客
15、户端界面的实现7登陆功能实现代码:private void btnlogin_Click(object sender, EventArgs e)if (tbxServerIp.Text = string.Empty)MessageBox.Show(“请先填写服务器IP地址“, “提示“);return;ftpUristring = “ftp:/“ + tbxServerIp.Text;networkCredential = new NetworkCredential(tbxUsername.Text, tbxPassword.Text);if (ShowFtpFileAndDirectory(
16、) = true)btnlogin.Enabled = false;btnlogout.Enabled = true;lstbxFtpResources.Enabled = true;lstbxFtpState.Enabled = true;tbxServerIp.Enabled = false;if (chkbxAnonymous.Checked = false)tbxUsername.Enabled = false;tbxPassword.Enabled = false;chkbxAnonymous.Enabled = false;elsechkbxAnonymous.Enabled =
17、false;8tbxloginmessage.Text = “登录成功“;btnUpload.Enabled = true;btndownload.Enabled = true;btnDelete.Enabled = true;elselstbxFtpState.Enabled = true;tbxloginmessage.Text = “登录失败“;注销:private void btnlogout_Click(object sender, EventArgs e)btnlogin.Enabled = true;btnlogout.Enabled = false;tbxServerIp.En
18、abled = true;tbxServerIp.SelectAll();tbxServerIp.Focus();chkbxAnonymous.Enabled = true;if (chkbxAnonymous.Checked = false)tbxUsername.Enabled = true;tbxPassword.Enabled = true;tbxloginmessage.Text = “你已经退出了。“;lstbxFtpResources.Items.Clear();lstbxFtpResources.Enabled = false;lstbxFtpState.Items.Clear
19、();lstbxFtpState.Enabled = false;btnUpload.Enabled = false;btndownload.Enabled = false;btnDelete.Enabled = false;上传功能:private void btnUpload_Click(object sender, EventArgs e)/选择要上传的文件OpenFileDialog openFileDialog = new OpenFileDialog();openFileDialog.FileName = openFileDialog.FileNames.ToString();op
20、enFileDialog.Filter = “所有文件(*.*)|*.*“;9if (openFileDialog.ShowDialog() != DialogResult.OK)return;FileInfo fileinfo = new FileInfo(openFileDialog.FileName);trystring uri = GetUriString(fileinfo.Name);FtpWebRequest request = CreateFtpWebRequest(uri, WebRequestMethods.Ftp.UploadFile);request.ContentLen
21、gth = fileinfo.Length;int buflength = 8196;byte buffer = new bytebuflength;FileStream filestream = fileinfo.OpenRead();Stream responseStream = request.GetRequestStream();lstbxFtpState.Items.Add(“打开上传流,文件上传中.“);int contenlength = filestream.Read(buffer, 0, buflength);while (contenlength != 0)response
22、Stream.Write(buffer, 0, contenlength);contenlength = filestream.Read(buffer, 0, buflength);responseStream.Close();filestream.Close();FtpWebResponse response = GetFtpResponse(request);if (response = null)lstbxFtpState.Items.Add(“服务器未响应.“);lstbxFtpState.TopIndex = lstbxFtpState.Items.Count - 1;return;
23、lstbxFtpState.Items.Add(“上传完毕,服务器返回:“ + response.StatusCode + “ “ + response.StatusDescription);lstbxFtpState.TopIndex = lstbxFtpState.Items.Count - 1;MessageBox.Show(“上传成功!“);/ 上传成功后,立即刷新服务器目录列表ShowFtpFileAndDirectory();catch (WebException ex)10lstbxFtpState.Items.Add(“上传发生错误,返回信息为:“ + ex.Status);l
24、stbxFtpState.TopIndex = lstbxFtpState.Items.Count - 1;MessageBox.Show(ex.Message, “上传失败“);private string GetUriString(string filename)string uri = string.Empty;if (currentDir.EndsWith(“/“)uri = ftpUristring + currentDir + filename;elseuri = ftpUristring + currentDir + “/“ + filename;return uri;下载:pr
25、ivate void btndownload_Click(object sender, EventArgs e)string fileName = GetSelectedFile();if (fileName.Length = 0)MessageBox.Show(“请选择要下载的文件!“,“提示“);return;/ 选择保存文件的位置SaveFileDialog saveFileDialog = new SaveFileDialog();saveFileDialog.FileName = fileName;saveFileDialog.Filter = “所有文件(*.*)|(*.*)“;i
26、f (saveFileDialog.ShowDialog() != DialogResult.OK)return;string filePath = saveFileDialog.FileName;try11string uri = GetUriString(fileName);FtpWebRequest request = CreateFtpWebRequest(uri, WebRequestMethods.Ftp.DownloadFile);FtpWebResponse response = GetFtpResponse(request);if (response = null)lstbx
27、FtpState.Items.Add(“服务器未响应.“);lstbxFtpState.TopIndex = lstbxFtpState.Items.Count - 1;return;Stream responseStream = response.GetResponseStream();FileStream filestream = File.Create(filePath);int buflength = 8196;byte buffer = new bytebuflength;int bytesRead =1;lstbxFtpState.Items.Add(“打开下载通道,文件下载中.“
28、);while (bytesRead != 0)bytesRead = responseStream.Read(buffer, 0, buflength);filestream.Write(buffer, 0, bytesRead);responseStream.Close();filestream.Close();lstbxFtpState.Items.Add(“下载完毕,服务器返回:“ + response.StatusCode + “ “ + response.StatusDescription);lstbxFtpState.TopIndex = lstbxFtpState.Items.
29、Count - 1;MessageBox.Show(“下载完成!“);catch (WebException ex)lstbxFtpState.Items.Add(“发生错误,返回状态为:“ + ex.Status);lstbxFtpState.TopIndex = lstbxFtpState.Items.Count - 1;MessageBox.Show(ex.Message, “下载失败“);/ 获得选择的文件/ 如果选择的是目录或者是返回上层目录,则返回nullprivate string GetSelectedFile()string filename = string.Empty;i
30、f (!(lstbxFtpResources.SelectedIndex = -1 | 12lstbxFtpResources.SelectedItem.ToString().Substring(0, 4) = “目?录?“)string namefield = lstbxFtpResources.SelectedItem.ToString().Split( );filename = namefield0;return filename;删除:private void btnDelete_Click(object sender, EventArgs e)string filename = Ge
31、tSelectedFile();if (filename.Length = 0)MessageBox.Show(“请选择要删除的文件!“, “提示“);return;trystring uri = GetUriString(filename);if (MessageBox.Show(“确定要删除文件 “ + filename + “ 吗?“, “确认文件删除“, MessageBoxButtons.YesNo) = DialogResult.Yes)FtpWebRequest request = CreateFtpWebRequest(uri, WebRequestMethods.Ftp.De
32、leteFile);FtpWebResponse response = GetFtpResponse(request);if (response = null)lstbxFtpState.Items.Add(“服务器未响应.“);lstbxFtpState.TopIndex = lstbxFtpState.Items.Count - 1;return;lstbxFtpState.Items.Add(“文件删除成功,服务器返回:“ + response.StatusCode + “ “ + response.StatusDescription);ShowFtpFileAndDirectory()
33、;elsereturn;13catch (WebException ex)lstbxFtpState.Items.Add(“发生错误,返回状态为:“ + ex.Status);lstbxFtpState.TopIndex = lstbxFtpState.Items.Count - 1;MessageBox.Show(ex.Message, “删除失败“);#endregion四、实验结果1 启动服务器2 链接服务器143 上传下载:15五、实验心得经过两周的课程设计学习让我受益匪浅。在课程设计即将结束之时,我对这次的学习进行了总结,总结这次学习中的收获与不足。取长补短,这次可设在今后的学习和工
34、作中都会有所受用。在设计 FTP 客户端和服务器的时候,原本对 FTP 协议原理的理解不深入导致出现使用多层结构进行通信,而且每一层通信都是使用多个 ServerSocket 进行数据通信,那样子造成了架构的混乱而且通信的复杂度很大,一边写服务器一边写客户端,常常将客户端要实现的方法混淆在服务器项目上。在混乱之际,想起采用数据结构进行先写清楚相关的抽象数据类型,然后再进行编写代码。截然不同的作用,然后再老师的指点下,在文件的读取先采用 1k 的缓存再进行以 1k 为单位发生数据,大大改进了发送数据的速度。在这次课程设计中不仅熟悉了 FTP HTTP 等相关协议,还加深了对 TCP/UDP、Socket 的使用方法。以及文件流的读写,和网络编程的关键技术。