网络与信息安全实验报告
- 格式:doc
- 大小:418.00 KB
- 文档页数:16
计算机科学与技术学院网络与信息安全课程设计学号:专业:计算机科学与技术学生姓名:任课教师:***2017年3月FTP服务器的设计与实现***计算机科学与技术学院,哈尔滨工程大学摘要:FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”。
用于Internet上的控制文件的双向传输。
同时,它也是一个应用程序(Application)。
基于不同的操作系统有不同的FTP应用程序,而所有这些应用程序都遵守同一种协议以传输文件。
在FTP的使用当中,用户经常遇到两个概念:"下载" (Download)和"上传"(Upload)。
"下载"文件就是从远程主机拷贝文件至自己的计算机上;"上传"文件就是将文件从自己的计算机中拷贝至远程主机上。
用Internet语言来说,用户可通过客户机程序向(从)远程主机上传(下载)文件。
本文基于FTP协议搭建了一个FTP服务器,实现简单的上传下载功能。
关键字:FTP,网络协议,服务器一、FTP协议的工作原理1. 简介FTP是因特网网络上历史最悠久的网络协议,凭借其独特的优势一直都是因特网中最重要、最广泛的服务之一。
FTP是TCP/IP提供的标准机制,实现从一台主机向另一台主机传送文件的任务。
目前FTP客户端软件很多,大致我们可以把它们分为三类:第一类是传统的FTP客户机;第二类是图形化用户界面的FTP软件;第三类是Web浏览器。
从根本上说,FTP就是在网络中各种不同的计算机之间按照TCP/IP协议来传输文件。
FTP 采用的是现在流行的Client/Server模式,由FTP客户端和FTP服务器端程序组成。
通常服务器端是远程端点,用户可以通过Internet网络连接到远程的FTP服务器站点。
服务器的功能是主要的。
只有当FTP服务器支持各种协议和指令时,才能够开发相应的客户端程序。
开发任何基于FTP的客户端软件都必须遵循FTP的工作原理,FTP的独特的优势同时也是与其它客户服务器程序最大的不同点就在于它在两台通信的主机之间使用了两条TCP连接,一条是数据连接,用于数据传送;另一条是控制连接,用于传送控制信息(命令和响应),这种将命令和数据分开传送的思想大大提高了FTP的效率,而其它客户服务器应用程序一般只有一条TCP 连接。
图1给出了FTP的基本模型。
客户有三个构件:用户接口、客户控制进程和客户数据传送进程。
服务器有两个构件:服务器控制进程和服务器数据传送进程。
在整个交互的FTP会话中,控制连接始终是处于连接状态的,数据连接则在每一次文件传送时先打开后关闭。
用户接口控制进程数据传送进程控制进程数据传送进程控制连接命令与应答数据连接文件传输图1 FTP 的基本模型 FTP 是TCP/IP 的一种具体应用,它工作在OSI 模型的第七层,TCP 模型的第四层上,即应用层,使用TCP 传输而不是UDP ,这样FTP 客户在和服务器建立连接前就要经过一个被广为熟知的“三次握手”的过程,它带来的意义在于客户与服务器之间的连接是可靠的,而且是面向连接,为数据的传输提供了可靠的保证。
采用FTP 协议可使 Internet 用户高效地从网上的FTP 服务器下载大信息量的数据文件,将远程主机上的文件拷贝到自己的计算机上。
以达到资源共享和传递信息的目的。
由于FTP 的使用使得Internet 上出现大量为用户提供的下载服务器。
Internet 成为了一个巨型的软件仓库。
FTP 在文件传输中还支持断点续传功能,可以大幅度地减小CPU 和网络带宽的开销。
FTP 需要2个端口,一个端口是控制连接端口,也即21端口,用于发送指令给服务器并等待服务器响应;另一个端口是数据传输端口,端口号为20(仅PORT 模式),用于建立数据传输通道。
FTP 的连接模式有2种:PORT 和PASV 。
PORT 模式是一个主动模式,PASV 是被动模式,二者都是相对于服务器而言的。
2. FTP 运行原理FTP 的工作原理与其他许多网络实用程序一样,也是基于客户/服务器模式。
互联网文件传输协议(File Transfer Protocol) 标准是在FTC959说明的。
该协议定义了一个在远程计算机系统和本地计算机系统之间传输文件的标准。
一般来说,要传输文件的用户需先经过认证以后才能登录ftp 服务器,访问在远程服务器的文件。
大多数的FTP 服务器往往提供一个guest 的公共帐户来允许没有FTP 服务器帐户的用户可以访问该FTP 服务器。
一个FTP 会话通常包括五个软件元素的交互。
就模型而言,从1973年以来并没有什么变化。
如图2所示。
文件系统SDTP UDTP文件系统SPI USERPI用户接口用户图2 FTP 协议模型 在一个FTP 会话中,会存在两个独立的网络连接,一个是由两端的PI 使用的,另一个是由两端的DTP 使用的。
PI 之间的连接一般被称作控制连接(control connection),DTP 之间的连接被称作数据连接(data connection)。
通常情况下,ftp 服务器监听端口号21来等待控制连接建立请求,当客户连接请求到达,会在客户和ftp 服务器之间建立一个控制连接。
而数据连接端口号的选择依赖于控制连接上的命令,通常是客户发送一个控制消息来指定客户需要建立一个数据连接来传输ftp 数据(如下载/上载一个文件,显示当前目录的内容等等,都需要建立数据连接来传输数据),在该消息中,指定了客户监听并等待连接的端口号,而服务器从控制连接收到该命令,向客户端发起一个连接请求到消息中指定的端口号,客户端收到该请求以后就会建立一个数据连接。
连接建立以后,服务器或客户就会主动通过该连接发送数据(可能是要传输的文件,也可能是用户在命令行上发出的IS 命令的输出)。
二、 系统设计与实现1 功能要求本系统是一个在局域网内实现的小型FTP 文件传输服务器。
主要实现的是FTP 服务器端功能,包括:FTP 服务日志,在线用户的管理,统计客户端信息还有客户端上传、下载、选择数据传输模式、改变目录等,并给出相应的提示。
2 主界面程序界面主要包括服务器日志、在线用户、统计信息、安全管理、菜单栏、工具栏、状态栏。
如图5所示。
图5 服务器用户界面3 主要功能与实现用CSocket类编制的服务器端的程序,其过程如下,其过程主要是:创建CSocket对象。
创建底层套接字Socket。
调用Listen,开始监听从客户端发来的访问请求。
如果收到请求,调用CAsyncSocket::Accept( )函数进行接收外理。
建立CSocketFile对象,并且使该对象与CSocket对象具备一定的联系。
建立Carchive对象,以便实现卸装(接收)数据和存储(发送)数据的目的地址。
当然,该Carchive对象应该与前面的CSocketFile对象建立联系。
使用Carchive对象在客户和服务器Socket之间传递数据,从而实现服务器Socket和客户机Socket之间的通信。
值得注意的是,一个给定的Carchive对象只能在单一的方向上传递数据:或者接收,或者发送。
一般情况下,可能需要两个Carchive对象来实现数据的双向传递。
3.1菜单栏功能模块菜单拦包括:服务器,查看。
服务器菜单包括:开始,停止,用户账户向导,用户账户等功能。
查看菜单包括:服务器日志,在线用户,配置,统计,安全等功能。
各项功能实现如下:服务器功能:(1) 帐户向导:当你登录服务器时你需要一个有效的账户,用户帐户向导将引导您通过必要的步骤,创造一个新的用户帐户。
并将其添加到用户帐户对话框,创建用户名,如图6所示。
图6 用户帐户向导窗口通过这个窗口你可以创建自己的用户名以及密码用以登陆FTP服务器,该部分功能实现代码如下:(2) 用户帐户功能:这一功能主要是服务器端添加,修改和删除用户帐户,设置目录权限(使用添加按钮以添加一个新目录,其中选定的用户帐户已具有访问权限,每小组目录您可以设定不同的权限,例如你可以给所有权限到C:\下载,但限制的权限为C :\下载\申请时,没有权限指定的目录,在这个目录中它会自动阻止用户要求上传任何子目录)。
目录属性,当您添加的编辑目录的用户帐户,目录属性对话框将显示物理目录(物理目录是'真正'的路径文件夹的名称)。
虚拟目录(虚拟目录是一个物理文件夹的别名,当用户连接到您的FTP服务器,它将看到这个目录名而不是真正的物理名称)。
设制服务端允许客户端的权限,例如允许客户端可以下载,上传,重命名哪些服务器端的文件内容。
例如用户123将:E:\盘设为许可目录,客户端就可以随时下载,上传E:\盘里面的内容,如图7所示。
图7 用户帐户窗口3.2 查看功能模块(1) 服务器日志模块的功能:在此屏幕,记录客户端与服务器端的连接信息以及传输信息,当客户端登陆服务器时服务器日志会显示是否与服务器连接成功,当客户端要上传文件或是下载文件成功时会记录服务器和FTP客户端的详细资料,从而有助于您追踪服务器与客户端之间所有的通讯讯息,数目之间的方括号[ ]是线程ID,如图8所示。
图8 服务器日志窗口(2) 在线用户模块的功能:通过服务器来查看在线客户端的用户名,用户IP地址,用户登陆时间等信息,如图9所示。
图9 在线用户窗口(3) 配置模块的功能:配置FTP服务器所有的设置。
默认服务器端口为21,可以同时连接最多用户数,客户端与服务器端连接时间(当客户端已闲置的具体时间,它会自动断开),欢迎信息(当客户端连接到服务器时将会显示该文本),再见讯息(文本将显示当一个客户端从服务器断开时)其他设置,FTP服务器在Windows下启动,启动最小化在系统盘,并在启动时自动激活服务器。
用户还可以将用户各种信息都记录在服务器日志里,如图10所示。
图10 配置界面三、实验结论本次实验实现了一个基于FTP协议的服务器系统,基本完成了FTP服务器所需的大多数功能。
用户能够选择相应的数据传输模式,对指定的文件进行上传下载。
通过该程序的开发,涵盖了一个FTP服务器所应该具有的功能,能够解释一般的FTP命令,符合相应的规范。
四、参考文献[1]蔡勇. FTP服务器技术研究及实现[D].电子科技大学,2005.[2]王占军,王伟,赵志刚. 基于FTP协议的文件传输组件设计与实现[J]. 沈阳师范大学学报(自然科学版),2012,03:375-377.[3]吴珂,卢秉亮,张磊. 基于FTP协议客户端软件的实现[J]. 沈阳航空工业学院学报,2006,04:39-42.五、源代码// stdafx.cpp : source file that includes just the standard includes// FTPServer.pch will be the pre-compiled header// stdafx.obj will contain the pre-compiled type information#include "stdafx.h"CString BrowseForFolder(HWND hWnd, LPCSTR lpszTitle, UINT nFlags) {// We're going to use the shell to display a// "Choose Directory" dialog box for the user.CString strResult = "";LPMALLOC lpMalloc;if (::SHGetMalloc(&lpMalloc) != NOERROR){// failed to get allocatorreturn strResult;}char szBuffer[_MAX_PATH];char szDisplayName[_MAX_PA TH];BROWSEINFO browseInfo;browseInfo.hwndOwner = hWnd;// set root at DesktopbrowseInfo.pidlRoot = NULL;browseInfo.pszDisplayName = szDisplayName;browseInfo.lpszTitle = lpszTitle;browseInfo.ulFlags = nFlags;browseInfo.lpfn = NULL;browseInfo.lParam = 0;LPITEMIDLIST lpItemIDList;if ((lpItemIDList = ::SHBrowseForFolder(&browseInfo)) != NULL){// Get the path of the selected folder from the item ID list.if (::SHGetPathFromIDList(lpItemIDList, szBuffer)){// At this point, szBuffer contains the path the user chose.if (szBuffer[0] == '\0'){// SHGetPathFromIDList failed, or SHBrowseForFolder failed.AfxMessageBox("Failed to get directory", MB_ICONSTOP|MB_OK);return strResult;}// We have a path in szBuffer!strResult = szBuffer;return strResult;}else{// The thing referred to by lpItemIDList// might not have been a file system object.// For whatever reason, SHGetPathFromIDList didn't work!AfxMessageBox("Failed to get directory", MB_ICONSTOP|MB_OK);return strResult; // strResult is empty}lpMalloc->Free(lpItemIDList);lpMalloc->Release();}return strResult;}void DoEvents(){MSG msg;// window messagewhile (PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE)){TranslateMessage(&msg);DispatchMessage(&msg);}}void GetAppDir(CString& strAppDir){TCHAR szFullPath[MAX_PATH];TCHAR szDir[_MAX_DIR];TCHAR szDrive[_MAX_DRIVE];// Get application's full path.::GetModuleFileName(NULL, szFullPath, MAX_PA TH);// Break full path into seperate components._splitpath(szFullPath, szDrive, szDir, NULL, NULL);// Store application's drive and pathstrAppDir.Format(_T("%s%s"), szDrive, szDir);}PFNSHGETFOLDERPA THA GetFuncPtr_SHGetFolderPathA(){static HMODULE hMod = NULL;PFNSHGETFOLDERPATHA pSHGetFolderPath = NULL;// Load SHFolder.dll only onceif (!hMod)hMod = LoadLibrary("SHFolder.dll");// Obtain a pointer to the SHGetFolderPathA functionif (hMod)pSHGetFolderPath = (PFNSHGETFOLDERPATHA)GetProcAddress(hMod, "SHGetFolderPathA");return pSHGetFolderPath;}HRESULT CreateStartMenuShortcut(LPSTR lpszShortcutFile, LPSTR lpszDescription, LPTSTR lpszRelativeFolder){HRESULT hr;PFNSHGETFOLDERPATHA pSHGetFolderPath = NULL;TCHAR lpszLink[MAX_PA TH];BOOL bFound = FALSE;pSHGetFolderPath = GetFuncPtr_SHGetFolderPathA();// Find the current user's Start Menu Programs folderif (pSHGetFolderPath)bFound = SUCCEEDED(pSHGetFolderPath(NULL, CSIDL_PROGRAMS, NULL, 0, lpszLink));if (bFound){// Proceed to create the shortcutIShellLink *pIShellLink = NULL;IPersistFile *ppf = NULL;WCHAR pLinkUnicode[MAX_PATH];CoInitialize(NULL);// Get a pointer to the IShellLink interface.hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,IID_IShellLink, (void **)&pIShellLink);if (SUCCEEDED(hr)){// Get a pointer to IPersistFile interface for saving shortcuthr = pIShellLink->QueryInterface(IID_IPersistFile, (void **)&ppf);if (SUCCEEDED(hr)){hr = pIShellLink->SetPath(lpszShortcutFile);hr = pIShellLink->SetDescription(lpszDescription);if (SUCCEEDED(hr)){// Add the target folder to the Start Menu Programs pathlstrcat(lpszLink, "\\");lstrcat(lpszLink, lpszRelativeFolder);lstrcat(lpszLink, "\\");// Create the directory if it does not existCreateDirectory(lpszLink,NULL);// Add the file name for the shortcutlstrcat(lpszLink, lpszDescription);lstrcat(lpszLink, ".lnk");// Convert string to Unicode, and call IPersistFile::Save()MultiByteToWideChar(CP_ACP, 0, lpszLink, -1, pLinkUnicode, MAX_PATH);hr = ppf->Save(pLinkUnicode, TRUE);}ppf->Release();}pIShellLink->Release();}CoUninitialize();}return hr;}void RemoveStartMenuShortcut(LPSTR lpszDescription, LPTSTR lpszRelativeFolder){PFNSHGETFOLDERPATHA pSHGetFolderPath = NULL;TCHAR lpszLink[MAX_PA TH];BOOL bFound = FALSE;pSHGetFolderPath = GetFuncPtr_SHGetFolderPathA();// Find the current user's Start Menu Programs folderif (pSHGetFolderPath)bFound = SUCCEEDED(pSHGetFolderPath(NULL, CSIDL_PROGRAMS, NULL, 0, lpszLink));if (bFound){// Add the target folder to the Start Menu Programs pathlstrcat(lpszLink, "\\");lstrcat(lpszLink, lpszRelativeFolder);lstrcat(lpszLink, "\\");// Add the file name for the shortcutlstrcat(lpszLink, lpszDescription);lstrcat(lpszLink, ".lnk");DeleteFile(lpszLink);}}CString GetShortcutTarget(LPCTSTR lpszFilename){CoInitialize(0);CString strResult;HRESULT hResult;IShellLink *psl;char szPath[MAX_PATH];WIN32_FIND_DA TA findData;// Get a pointer to the IShellLink interface.hResult = CoCreateInstance (CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,IID_IShellLink, (void **)&psl);if (SUCCEEDED(hResult)){IPersistFile *ppf;// Get a pointer to the IPersistFile interface.hResult = psl->QueryInterface (IID_IPersistFile, (void **)&ppf);if (SUCCEEDED(hResult)){WORD wsz [MAX_PATH]; // buffer for Unicode string// Ensure that the string consists of Unicode characters.MultiByteToWideChar (CP_ACP, 0, lpszFilename, -1, wsz, MAX_PATH);// Load the shortcut.hResult = ppf->Load (wsz, STGM_READ);if (SUCCEEDED (hResult)){// Resolve the shortcut.hResult = psl->Resolve (0, SLR_ANY_MATCH|SLR_NO_UI);if (SUCCEEDED (hResult)){lstrcpy (szPath, lpszFilename);// Get the path to the shortcut target.hResult = psl->GetPath(szPath, MAX_PATH, (WIN32_FIND_DATA *)&findData, 0);strResult = szPath;}}// Release the pointer to IPersistFile.ppf->Release ();}// Release the pointer to IShellLink.psl->Release ();}CoUninitialize();if (SUCCEEDED(hResult))return strResult;elsereturn "";}// Pump messages while waiting for eventBOOL WaitWithMessageLoop(HANDLE hEvent, int nTimeout){DWORD dwRet;while (1){// wait for event or message, if it's a message, process it and return to waiting statedwRet = MsgWaitForMultipleObjects(1, &hEvent, FALSE, nTimeout, QS_ALLINPUT);if (dwRet == W AIT_OBJECT_0){TRACE0("WaitWithMessageLoop() event triggered.\n");return TRUE;}elseif (dwRet == W AIT_OBJECT_0 + 1){// process window messagesAfxGetApp()->PumpMessage();}elseif (dwRet == W AIT_TIMEOUT){// timed out !return FALSE;}else{// WAIT_ABANDONED_0 ...return TRUE;}}}void AutoSizeColumns(CListCtrl *pListCtrl){// Call this after your the control is filledpListCtrl->SetRedraw(FALSE);int mincol = 0;int maxcol = pListCtrl->GetHeaderCtrl()->GetItemCount()-1;for (int col = mincol; col <= maxcol; col++){pListCtrl->SetColumnWidth(col, LVSCW_AUTOSIZE);int wc1 = pListCtrl->GetColumnWidth(col);pListCtrl->SetColumnWidth(col, LVSCW_AUTOSIZE_USEHEADER);int wc2 = pListCtrl->GetColumnWidth(col);// 10 is minumim column widthint wc = max(10, max(wc1,wc2));pListCtrl->SetColumnWidth(col,wc);}pListCtrl->SetRedraw(TRUE);}。