FileZilla 源代码分析8
创始人
2024-07-21 11:51:26
0

FileZilla是一种快速、可信赖的FTP客户端以及服务器端开放源代码程式,具有多种特色、直觉的接口。本文就给大家分析下FileZilla的源代码。

  FTP客户通过ftp localhost命令与FileZilla服务器建立socket连接后,FileZilla Server显示了welcome信息,这时屏幕上显示类似(我们以windows下的ftp命令作为sample):

  Connected to dell.

  220-FileZilla Server version 0.9.18 beta

  220-written by Tim Kosse (Tim.Kosse@gmx.de)

  220 Please visit http://sourceforge.net/projects/filezilla/

  User (dell:(none)):

  提示输入用户名,假设这时用户输入whg,回车,这时ftp客户端会将这用户输入的字符翻译成标准的FTP命令"USER whg"发送到服务器,因为这时是CControlSocket对这个socket进行监听,并且recv相关的事件通过前面提到的分发机制,最终分发到 CControlSocket的OnReceive方法,下面我看一下这个方法:

  m_antiHammeringWaitTime还不知是起什么作用,在对源代码进行跟踪的时候,其刚开始的值是0,因此先跳过这个。

  下段是获得传输速度限制SpeedLimit,如果没有限制,则为-1。

  再往下:

  int numread = Receive(buffer, len); // 调用recv来获得socket数据,取长度为len的数据放到buffer中

  读取成功后,将buffer中的接收到的数据一个字节一个字节放到m_RecvBuffer中:

  m_RecvBuffer[m_nRecvBufferPos++] = buffer[i];

  然后将将刚才收到的m_RecvBuffer放入m_RecvLineBuffer:

  m_RecvLineBuffer.push_back(m_RecvBuffer);

  m_RecvLineBuffer相当于一个命令池,里面存放着用户发送来,但还没有处理的命令。

  ***当这个recv处理完后,调用ParseCommand()来解释这个命令。

  首先通过GetCommand()取出m_RecvLineBuffer中最前面的命令,并解释成命令command,以及参数args,如刚才的命令USER whg就被解释成command=USER, args=whg

  下面的循环:

  for (int i = 0; i < (sizeof(commands)/sizeof(t_command)); i++)

  通过在预先定义的FTP Server所有命令commands中,查找是否包含command,从而校验刚才收到的命令的合法性,如果command不在commands中,显示command是非法命令,这时发送客户端

  Send(_T("500 Syntax error, command unrecognized."));

  即使命令是合法的,但如果参数不对(bHasargs指定这个命令是否需要参数),即有些命令必须带参数,而args没有,这时会发送:

  Send(_T("501 Syntax error"));

  下面:

  if (!m_RecvLineBuffer.empty())

  m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_COMMAND, m_userid);

  表示如果命令缓冲区中还有未处理的命令,则发送消息给CServerThread,CServerThread在方法OnThreadMessage中处理这个消息:

  else if (wParam==FTM_COMMAND)

  { //Process a command sent from a client

  CControlSocket *socket=GetControlSocket(lParam);

  if (socket)

  socket->ParseCommand();

  }

  在GetControlSocket()方法中:

  CControlSocket * CServerThread::GetControlSocket(int userid)

  {

  CControlSocket *ret=0;

  EnterCritSection(m_threadsync);

  // 下面这个map是user -> CControlSocket,即通过userid找到服务这个userid的CControlSocket

  std::map::iterator iter=m_LocalUserIDs.find(userid);

  if (iter!=m_LocalUserIDs.end())

  ret=iter->second;

  LeaveCritSection(m_threadsync);

  return ret;

  }

  可见,发送这个消息的作用是让CControlSocket继续调用ParseCommand()来处理下一个命令。

  回到最初的ParseCommand(),如果命令参数也没有问题,下面检查这个命令是否必须先登录再使用(由bValidBeforeLogon指定),比如:get命令是必须先登录的,而USER命令不用,如果必须先登录,发送:

  Send(_T("530 Please log in with USER and PASS first."));

  下面同样

  m_pOwner->PostThreadMessage(WM_FILEZILLA_THREADMSG, FTM_COMMAND, m_userid);

  命令都合格的话,下面:

  switch (nCommandID)

  来处理不同的命令,由于这时是COMMAND_USER命令,我们看一下处理过程:

  经过一些处理后,下面发送

  Send(_T("331 Password required for ") + args);

  要求用户输入密码,时客户端屏幕上会显示:

  331 Password required for whg

  Password:

  用户输入密码后,回车,这时ftp客户端会翻译成标准的FTP命令"PASS 123456"发送到服务器,我们看一下ParseCommand()对这的处理:

  case COMMAND_PASS:

  else if (DoUserLogin(args))

  Send(_T("230 Logged on"));

  在DoUserLogin()认定成功登录后,发送成功登录消息给客户端,否则会发送错误消息:

  Send(_T("530 Login or password incorrect!"));

  仔细看一下CPermissions::CheckUserLogin(),会发现密码是经过MD5加密的,并且在CServerThread创建时,跟权限相关的成员变量就初始化了:

  m_pPermissions = new CPermissions;

  在CPermissions::Init()中,调用ReadSettings(),从配置文件中,将所有的用户信息(包括密码)都读到内存了,因此刚才的密码校验只是内存中的字符串比对。

  用户成功登录后,FTP客户端显示:

  C:\Documents and Settings\Administrator>ftp localhost

  Connected to dell.

  220-FileZilla Server version 0.9.18 beta

  220-written by Tim Kosse (Tim.Kosse@gmx.de)

  220 Please visit http://sourceforge.net/projects/filezilla/

  User (dell:(none)): whg

  331 Password required for whg

  Password:

  230 Logged on

  ftp>

  下面FTP服务器等待新的FTP命令了。

通过文章完整的描述,大家应该知道了FileZilla 源代码,希望对大家有帮助!

【编辑推荐】

  • FileZilla简单介绍
  • FileZilla 源代码分析1
  • FileZilla 源代码分析2
  • FileZilla 源代码分析3
  • FileZilla 源代码分析4
  • FileZilla 源代码分析5
  • FileZilla 源代码分析6
  • FileZilla 源代码分析7

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
各种千兆交换机的数据接口类型详... 千兆交换机有很多值得学习的地方,这里我们主要介绍各种千兆交换机的数据接口类型,作为局域网的主要连接设...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
规避非法攻击 用好路由器远程管... 单位在市区不同位置设立了科技服务点,每一个服务点的员工都通过宽带路由器进行共享上网,和单位网络保持联...
范例解读VB.NET获取环境变... VB.NET编程语言的使用范围非常广泛,可以帮助开发人员处理各种程序中的需求,而且还能对移动设备进行...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...