2023年6月22日发(作者:)
网络与信息安全实验
基于C++的FTP服务器程序设计
摘要: 本实验的目的是设计一个FTP服务器系统,实现FTP服务器的大多数功能,包括用户的登录,文件的上传、下载、删除、目录选择等,并给出相应的提示,能够解释一般的FTP命令,并且符合RFC959规范。本程序采用VC++ 6.0作为开发工具,设计采用自顶向下的方法。该系统有着良好的界面,简单易用。
本实验的设计,即从需求分析,软件设计到软件功能实现,都始终遵循软件工程的思想和方法。本实验中采用了大量的图表说明,使文章明确清晰,便与阅读和理解。
关键词: FTP服务器;上传、下载;自顶向下;
1 实验介绍
由于网络的带宽及各种服务的限制,单纯从页面上下载显得又慢又不可靠,所以就有许多FTP[1]工具被开发出来。FTP是一个客户机/服务器系统。用户连接到在远程主机上的FTP服务器程序,发出命令,服务器程序执行用户所发出的命令,并将执行的结果返回到客户机。
本次程序设计的是一个FTP服务器。通过TCP/IP 网络应用程序基本的设计方法和实现技巧,实现FTP服务器所应该具备的大多数功能,并给出相应的提示。设计采用流行的C++语言作为此次设计的开发语言,并采用C/S网络通信结构作为FTP的网络体系结构;采用Visual C++ 6.0开发平台,Socket网络编程原理,成功与相应的FTP客户端连接。
2 实验目的
理解并采用FTP协议制作一个简易的FTP服务器:
1. 具有用户授权功能(包括匿名模式);
2. 实现基本的命令(上传、下载、更改目录)操作;
3. 能够与目前已有FTP客户端连通。
FTP客户机可以给服务器发出命令来下载文件,上载文件,创建或改变服务器上的目录。
3 实验原理
FTP服务器的简单设计与实现建立在计算机网络实验环境TCP/IP 网络体系结构之上,使用Socket 编程接口编写。Socket 通讯机制是一种较原始的通讯机制,通过Socket的数据表现出来的形式是原始字节流信息,通讯双方只要在此基础上按照双方约定方式进行数据的格式化和解析处理工作,这样才能完成具体的应用,即实现某种协议的过程[2]。图3-1是Socket的工作原理图。
- 1 -
网络与信息安全实验
图3-1 Socket原理图
客户机程序发送请求给服务器程序,服务器进程对客户机的请求做出响应,并产生结果。客户机/服务器模式下,客户机为主动方,即请求方;而服务器为被动方,即接受请求方。FTP服务如下图所示。
图3-2 FTP服务示意图
在数据处理领域中,客户机/服务器体系结构受到极关注,C/S已经成为网络计算机的主要方式。其中基于TCP/IP的网络通信主要模式也是客户机/服务器方式。C/S结构是软件系统体系结构,通过它可以充分利用两端硬件环境的优势,将任务合理分配到Client端和Server端来实现,降低了系统的通讯开销。其最重要的特征是:是一个平等的环境,客户机和服务器的地位可以互换。所以客户机/服务器体系结构应是应用程序之间相互作用的一种模型[3]。
4 实验步骤
4.1图4-1所示系统流程图。
- 2 -
网络与信息安全实验
开始打开监听端口接受连接请求N连接成功?Y接受传输命令N命令正确?Y执行相应操作结束
图4-1 系统流程图
4.2 主要的功能与实现
用CSocket类编制的服务器端的程序,其过程如下,其过程主要是:
(1) 创建CSocket对象。
(2) 创建底层套接字Socket。
(3) 调用Listen,开始监听从客户端发来的访问请求。
(4) 如果收到请求,调用CAsyncSocket::Accept( )函数进行接收外理[4]。
(5) 建立CSocketFile对象,并且使该对象与CSocket对象具备一定的联系。建立Carchive对象,以便实现卸装(接收)数据和存储(发送)数据的目的地址。注意:该Carchive对象应该与前面的CSocketFile对象建立联系。
(6)使用Carchive对象在客户机和服务器Socket之间传递数据,从而实现服务- 3 -
网络与信息安全实验
器Socket和客户机Socket之间的通信。值得注意的是,一个给定的Carchive对象只能在单一的方向上传递数据:或者接收,或者发送。
4.3程序界面
程序界面主要包括服务器日志、在线用户、统计信息、安全管理、菜单栏、工具栏、状态栏。如图4-2所示。
图4-2 服务器用户界面
4.3.1菜单栏功能模块
菜单拦包括:服务器,查看。
服务器菜单包括:开始,停止,用户账户向导,用户账户等功能。
查看菜单包括:服务器日志,在线用户,配置,统计,安全等功能。
各项功能实现如下:
服务器功能:
1. 用户向导:当用户登录服务器时需要创建一个有效的账户,用户帐户向导将引导此用户通过必要的步骤,创造一个新的用户帐户。并将其添加到用户帐户对话框,创建用户名,如图4-3所示。
- 4 -
网络与信息安全实验
图4-3 用户帐户向导窗口
通过这个窗口可以创建用户的用户名以及用以登陆FTP服务器的相应密码,该部分功能实现代码如下:
CWizardPage1::CWizardPage1() : CPropertyPageEx(CWizardPage1::IDD, 0,
IDS_HEADERTITLE1, NULL)
{
m_strAccountName = _T(““);
m_s &= ~PSP_HASHELP;
}
CWizardPage1::~CWizardPage1()
{
}
void CWizardPage1::DoDataExchange(CDataExchange* pDX)
{
CPropertyPageEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CWizardPage1, CPropertyPageEx)
- 5 -
DDX_Text(pDX, IDC_ACCOUNTNAME, m_strAccountName); 网络与信息安全实验
END_MESSAGE_MAP()
2. 用户帐户功能:这一功能主要是服务器端添加,修改和删除用户帐户,设置目录权限(使用添加按钮以添加一个新目录,其中选定的用户帐户已具有访问权限,每小组目录可以设定不同的权限,例如你可以给所有权限到“C:下载”,但限制的权限为“C: 下载申请”时,没有权限指定的目录,在这个目录中它会自动阻止用户要求上传的任何子目录)。目录属性[5],当您添加的编辑目录的用户帐户,目录属性对话框将显示物理目录(物理目录是“真正”的路径文件夹的名称),虚拟目录。
设置服务端允许客户端的权限,例如允许客户端可以下载,上传,重命名哪些服务器端的文件内容。例如用户toldo将:“C:temp”设为许可目录,客户端就可以随时下载,上传“C:temp”盘里面的内容,如图4-4所示。
图4-4 用户帐户窗口
这一功能实现,代码如下
void CUserAccountsDlg::OnDblclkDirlist(NMHDR* pNMHDR, LRESULT* pResult)
{
}
OnEditDir();
*pResult = 0;
4.3.2查看功能模块
服务器日志模块的功能:在此屏幕中,我们可以看到FTP服务器所记录的- 6 -
网络与信息安全实验
客户端与服务器端的连接信息以及传输信息,当客户端登陆服务器时服务器日志会显示是否与服务器连接成功,当客户端要上传文件或是下载文件成功时会记录服务器和FTP客户端的详细资料,从而有助于用户追踪服务器与客户端之间所有的通讯讯息,数目之间的方括号[ ]是线程ID,如图4-5所示。
图4-5 服务器日志窗口
该部分功能实现代码如下:
friend CLogFile& setlevel(CLogFile& os, int level)
{
m_nCurrentLevel = level;
return os;
}
friend CLogFile& error_lvl(CLogFile& os)
{
os.m_nCurrentLevel = 1;
return os; }
- 7 -
网络与信息安全实验
在线用户模块的功能:通过服务器来查看在线客户端的用户名,用户IP地址,用户登陆时间等信息,如图4-6所示。
图4-6 在线用户窗口
该模块功能实现代码如下:
class COnlineUsersPage : public CDialog
{DECLARE_DYNCREATE(COnlineUsersPage)
public:
void RemoveUser(DWORD nThreadID);
void AddUser(DWORD nThreadID, LPCTSTR lpszName, LPCTSTR lpszAddress);
COnlineUsersPage();
~COnlineUsersPage();
enum { IDD = IDD_PROPPAGE_ONLINE };
CListCtrl m_OnlineUsers;
protected:
- 8 -
网络与信息安全实验
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
protected:
afx_msg void OnSize(UINT nType, int cx, int cy);
virtual BOOL OnInitDialog();
};
配置模块的功能:配置FTP服务器所有的设置。默认服务器端口为21,可以同时连接最多用户数,客户端与服务器端连接时间,欢迎信息,再见信息其他设置。FTP服务器在Windows下启动,启动最小化在系统盘,并在启动时自动激活服务器。用户还可以将用户各种信息都记录在服务器日志里,如图4-7所示。
图4-7 配置界面
5 结果分析
在编写程序时有时会遇到运行错误,这是由于代码编写错误造成的。只要根据相应的错误提示对代码做出相应的修改即可。
用客户端登录服务器,与服务器建立连接,实现文件的上传与下载等相应功能,并查看服务器端所做出的反应。客户端连接服务器时,需要输入用效的用户- 9 -
网络与信息安全实验
名、密码以及服务器IP,才可以与服务器建立连接。打开客户端,输入服务器地址,端口号,用户名以及密码即可成功连接服务器,显示登录成功。如图5-2
图5-2 客户端连接
用户登录成功后,客户端[6]将会显示与服务器连接成功的信息,表示用户可以上传和下载文件了。连接成功后,双击选择相应的文件弹出对话框,点击确定,即可完成上传、下载等相应功能。此时服务端作出反应,显示在线用户及服务日志。如图5-3所示
- 10 -
网络与信息安全实验
图5-3 服务器端显示连接成功
6 结论
本次程序设计的是一个FTP服务器。通过TCP/IP 网络应用程序基本的设计方法和实现技巧,实现了FTP服务器所应该具备的大多数功能,包括用户的登录,文件的上传[7]、下载、选择数据传输模式、目录选择等,并给出相应的提示。通过该程序的开发,基本上实现了一个FTP服务器所应该具有的功能,能够解释一般的FTP命令,并且符合RFC959规范。
设计采用流行的C++语言作为此次设计的开发语言,并采用C/S结构作为FTP的网络体系结构。采用Visual C++[8] [9] 6.0开发平台,C/S的网络通信模式及Socket网络编程原理。能成功与相应的FTP客户端连接,达到预期目的。
目前FTP服务器还需增强的部分为:加快FTP服务器与相应客户端的连接速度;增强服务器与客户端数据连接时传输的稳定性,使使用者获得更加快捷方便的用户体验[10]。
此次课程设计我搜索了很多的资料,学习到了很多新的内容;也让我懂得在以后的学习中要勤于思考,多多动手,更加认真耐心地解决学习中的问题。
- 11 -
网络与信息安全实验
参考文献
[1] t for Comments:959:File Transfer Protocol,October 1985:7-8.
[2] Allman M,Ostermann S,C Extensions for IPv6 and NA Ts[J].RFC, 1998(9):24-28.
[3] Robert E Gilligam,Svan Thowson,Jim Bownd,et socket in terface extansiows for
ZPV6[J].RFC,1999: 25-53.
[4] 任泰明.TCP/IP协议与网络编程[M].西安:西安电子科技大学出版社, 2004.
[5] Douglas ,David /IP网络互联技术(卷3)[M],北京:清华大学出版社,2004.
[6] 刘远生.计算机网络基础[M],北京:电子工业出版社,2001,9:203-204.
[7] 谢希仁.计算机网络(第4版)[M],北京:电子工业出版社,2003.
[8] 史斌.C语言贯通教程[M],北京:清华大学出版社,2001.
[9] 戴锋.Visual C++程序设计基础[M],北京:清华大学出版社,2001.
[10] 张力.Visual C++高级编程[M],北京:人民邮电出版社,2002
程序
部分实现代码:
#include "stdafx.h"
#include "FTPServerApp.h"
#include "FTPServer.h"
#include "ApplicationDlg.h"
#include "ListenSocket.h"
#include "ConnectThread.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CListenSocket::CListenSocket()
{
}
- 12 -
m_pWndServer = NULL; 网络与信息安全实验
CListenSocket::~CListenSocket()
{
}
// 不要编辑以下行,ClassWizard必需的
#if 0
BEGIN_MESSAGE_MAP(CListenSocket, CAsyncSocket)
//{{AFX_MSG_MAP(CListenSocket)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif // 0
/********************************************************************/
/*
*/
*/
/* Function name : OnAccept
/* Description : 调用框架来通知监听, */
/* 它可以通过调用接受成员函数接受等待连接请求.
/*
*/
*/
/********************************************************************/
void CListenSocket::OnAccept(int nErrorCode)
{
// 正在建立新连接
CSocket sockit;
// 接受连接使用一个临时CSocket对象
Accept(sockit);
// 创建一个线程来处理连接。线程被创建的停赛,所以我们可以在CConnectThread之前开始执行设置变量
CConnectThread* pThread =
(CConnectThread*)AfxBeginThread(RUNTIME_CLASS(CConnectThread),
THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
if (!pThread)
{
();
- 13 -
网络与信息安全实验
}
TRACE("Could not create threadn");
return;
CFTPServer *pWnd = (CFTPServer *)m_pWndServer;
// 因为一切都是成功的,添加线程
pWnd->m_();
pWnd->m_l(pThread);
}
#include "stdafx.h"
#include "FTPServer.h"
CFTPServer::CFTPServer()
{
m_nPort = 21;
m_nMaxUsers = 10;
m_strWelcomeMessage = "Welcome to my FTP Server";
m_strGoodbyeMessage = "Bye";
m_nTimeout = 5;
m_bRunning = FALSE;
m_hWnd = NULL;
m_nConnectionCount = 0;
// intialize statistics
m_dwTotalSentBytes = 0;
pWnd->m_();
// 保存指针
pThread->m_pWndServer = m_pWndServer;
// 通过套接字到线程通过套接字处理。你不能通过CSocket跨线程对象。
pThread->m_hSocket = ();
// 现在启动线程。
pThread->ResumeThread();
CAsyncSocket::OnAccept(nErrorCode);
- 14 -
网络与信息安全实验
m_dwTotalReceivedBytes = 0;
m_nTotalConnections = 0;
m_nFilesDownloaded = 0;
m_nFilesUploaded = 0;
m_nFailedDownloads = 0;
m_nFailedUploads = 0;
m_nSecurityMode = 0;
m_nStatisticsInterval = 0;
// load users
m_ize(FALSE);
// load security
m_ize(FALSE);
}
CFTPServer::~CFTPServer()
{
Stop();
}
BEGIN_MESSAGE_MAP(CFTPServer, CWnd)
//{{AFX_MSG_MAP(CFTPServer)
ON_WM_TIMER()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_THREADSTART, OnThreadStart)
ON_MESSAGE(WM_THREADCLOSE, OnThreadClose)
ON_MESSAGE(WM_THREADMSG, OnThreadMessage)
END_MESSAGE_MAP()
/********************************************************************/
/*
/* Function name : Start */
/* Description : 开始监听端口21并接受新的连接 */
/* */
- 15 -
*/ 网络与信息安全实验
/* */
/********************************************************************/
BOOL CFTPServer::Start()
{
//为消息路由创建虚拟窗口
if (m_bRunning)
return FALSE;
if (!CWnd::CreateEx(0, AfxRegisterWndClass(0), "FTP Server Notification Sink", WS_POPUP,
0,0,0,0, NULL, 0))
{
}
// 创建监听socket
if (m_(m_nPort))
{
}
AddTraceLine(0, "FTP Server failed to listen on port %d.", m_nPort);
// destroy notification window
if (IsWindow(m_hWnd))
- 16 -
AddTraceLine(0, "Failed to create notification window.");
return FALSE;
//开始监听
if (m_())
{
}
m_ListenSocket.m_pWndServer = this;
m_bRunning = TRUE;
SetTimer(1, m_nStatisticsInterval, NULL);
AddTraceLine(0, "FTP Server started on port %d.", m_nPort);
return TRUE;
网络与信息安全实验
}
DestroyWindow();
m_hWnd = NULL;
return FALSE;
/********************************************************************/
/*
/* Function name : Stop */
/* Description : 停止FTP服务器。 */
/*
/********************************************************************/
void CFTPServer::Stop()
{
if (!m_bRunning)
return;
// 停止统计定时器
KillTimer(1);
m_bRunning = FALSE;
m_();
CConnectThread* pThread = NULL;
// 关闭所有正在运行的线程
do
{
m_();
POSITION pos = m_dPosition();
if (pos != NULL)
{
pThread = (CConnectThread *)m_(pos);
m_();
// 保存线程成员
int nThreadID = pThread->m_nThreadID;
- 17 -
*/
*/ 网络与信息安全实验
}
}
else
{
}
HANDLE hThread = pThread->m_hThread;
AddTraceLine(0, "[%d] Shutting ", nThreadID);
// 通知线程停止
pThread->SetThreadPriority(THREAD_PRIORITY_HIGHEST);
pThread->PostThreadMessage(WM_QUIT,0,0);
// 等待线程结束,同时保持消息泵(最大5秒)
if (WaitWithMessageLoop(hThread, 5000) == FALSE)
{
}
else
{
}
AddTraceLine(0, "[%d] Thread successfully stopped.", nThreadID);
// 线程不想停止
AddTraceLine(0, "[%d] Problem while killing thread.", nThreadID);
// 不再试一次,所以删除
m_();
POSITION rmPos = m_(pThread);
if (rmPos != NULL)
m_At(rmPos);
m_();
m_();
pThread = NULL;
while (pThread != NULL);
AddTraceLine(0, "FTP Server stopped.");
- 18 -
网络与信息安全实验
}
if (IsWindow(m_hWnd))
DestroyWindow();
m_hWnd = NULL;
/********************************************************************/
/*
/* Function name : IsActive */
/* Description : FTP服务器是否启动? */
/*
/********************************************************************/
BOOL CFTPServer::IsActive()
{
return m_bRunning;
}
/********************************************************************/
/*
/* Function name : SetMaxUsers */
/* Description : 设置用户的最大数量 */
/*
/********************************************************************/
void CFTPServer::SetMaxUsers(int nValue)
{
m_nMaxUsers = nValue;
}
/********************************************************************/
/*
/* Function name : SetPort */
/* Description : 设置监听端口为新连接 */
/*
/********************************************************************/
- 19 -
*/
*/
*/
*/
*/
*/ 网络与信息安全实验
void CFTPServer::SetPort(int nValue)
{
}
/********************************************************************/
m_nPort = nValue;
/*
/* Function name : SetTimeout */
/* Description : 设置连接时限 */
/*
/********************************************************************/
void CFTPServer::SetTimeout(int nValue)
{
m_nTimeout = nValue;
}
/********************************************************************/
/*
/* Function name : SetTimeout */
/* Description : 设置连接时限 */
/*
/********************************************************************/
void CFTPServer::SetStatisticsInterval(int nValue)
{
m_nStatisticsInterval = nValue;
if (m_nStatisticsInterval != 0)
{
KillTimer(1);
SetTimer(1, nValue, NULL);
}
else
{
- 20 -
*/
*/
*/
*/ 网络与信息安全实验
}
}
KillTimer(1);
/********************************************************************/
/*
/* Function name : SetWelcomeMessage */
/* Description : 设置欢迎信息 */
/*
/********************************************************************/
void CFTPServer::SetWelcomeMessage(LPCTSTR lpszText)
{
m_strWelcomeMessage = lpszText;
}
/********************************************************************/
/*
/* Function name : SetGoodbyeMessage */
/* Description : 设置结束信息 */
/*
/********************************************************************/
void CFTPServer::SetGoodbyeMessage(LPCTSTR lpszText)
{
m_strGoodbyeMessage = lpszText;
}
/********************************************************************/
/*
/* Function name : Initialize */
/* Description : 初始化事件接收。 */
/*
- 21 -
*/
*/
*/
*/
*/
*/ 网络与信息安全实验
/********************************************************************/
void CFTPServer::Initialize(CFTPEventSink *pEventSink)
{
}
/********************************************************************/
m_pEventSink = pEventSink;
/*
/* Function name : AddTraceLine */
/* Description : FTP状态更改。 */
/*
/********************************************************************/
void CFTPServer::AddTraceLine(int nType, LPCTSTR pstrFormat, ...)
{
CString str;
// 得到了格式和写数据
va_list args;
va_start(args, pstrFormat);
V(pstrFormat, args);
m_pEventSink->OnFTPStatusChange(nType, str);
}
/********************************************************************/
/*
/* Function name : OnThreadStart */
/* Description : 一个新的线程已经开始时调用。 */
/*
/********************************************************************/
LRESULT CFTPServer::OnThreadStart(WPARAM wParam, LPARAM)
{
m_nConnectionCount++;
- 22 -
*/
*/
*/
*/ 网络与信息安全实验
m_nTotalConnections++;
CConnectThread *pThread = (CConnectThread *)wParam;
UINT port;
pThread->m_rName(pThread->m_strRemoteHost, port);
AddTraceLine(0, "[%d]
pThread->m_strRemoteHost);
return TRUE;
}
AboutDlg 消息处理程序
Client connected from %s.", pThread->m_nThreadID,
- 23 -
发布者:admin,转转请注明出处:http://www.yc00.com/web/1687429645a9384.html
评论列表(0条)