FileZilla 源代码分析6

系统 Linux
FileZilla是一个免费开源的FTP客户端软件,分为客户端版本和服务器版本,具备所有的FTP软件功能。可控性、有条理的界面和管理多站点的简化方式使得Filezilla客户端版成为一个方便高效的FTP客户端工具,而FileZilla Server则是一个小巧并且可靠的支持FTP&SFTP的FTP服务器软件。

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

  CListenSocket是CAsyncSocketEx类的子类,在启动的时候用来监听21端口。

  pListenSocket->Create(nPort, SOCK_STREAM, FD_ACCEPT, NULL)

  可见,CListenSocket只处理FD_ACCEPT消息。

  看一下:

  void CListenSocket::OnAccept(int nErrorCode)

  {

  CAsyncSocketEx socket;

  if (!Accept(socket)) // 这里调用了win API: accept方法,建立了一个新连接,socket就这个新连接的SOCKET

  {

  int nError = WSAGetLastError();

  CStdString str;

  str.Format(_T("Failure in CListenSocket::OnAccept(%d) - call to CAsyncSocketEx::Accept failed, errorcode

  %d"), nErrorCode, nError);

  SendStatus(str, 1);

  SendStatus(_T("If you use a firewall, please check your firewall configuration"), 1);

  return;

  }

  // 权限检查,先不管

  if (!AccessAllowed(socket))

  {

  CStdStringA str = "550 No connections allowed from your IP\r\n";

  socket.Send(str, str.GetLength());

  return;

  }

  // 检查FileZilla Server是否处于锁定状态,即不允许建立新连接

  if (m_bLocked)

  {

  CStdStringA str = "421 Server is locked, please try again later.\r\n";

  socket.Send(str, str.GetLength());

  return;

  }

  // 下面从可用的线程中,找出目前负荷最小的线程,即线程中负责的connection最少的线程

  int minnum = 255*255*255;

  CServerThread *pBestThread=0;;

  for (std::list::iterator iter=m_pThreadList->begin(); iter!=m_pThreadList->end(); iter++)

  {

  int num=(*iter)->GetNumConnections();

  if (numIsReady()) // 找出connection最少的线程

  {

  minnum=num;

  pBestThread=*iter;

  if (!num)

  break;

  }

  }

  if (!pBestThread)

  {

  char str[] = "421 Server offline.";

  socket.Send(str, strlen(str)+1);

  socket.Close();

  return;

  }

  /* Disable Nagle algorithm. Most of the time single short strings get

  * transferred over the control connection. Waiting for additional data

  * where there will be most likely none affects performance.

  */

  BOOL value = TRUE;

  socket.SetSockOpt(TCP_NODELAY, &value, sizeof(value), IPPROTO_TCP); // 设置不使用Nagle算法,参见TCP协议Nagle算法部分

  SOCKET sockethandle = socket.Detach();

  pBestThread->AddSocket(sockethandle, m_ssl); // 转交服务线程来处理

  CAsyncSocketEx::OnAccept(nErrorCode); // 父类的缺省处理为空

  }

  可见,CListenSocket::OnAccept主要工作是

  1、创建一个socket来接收新的客户端连接

  2、进行一些检查设置,如权限检查,Nagle算法设置等

  3、找到一个负荷最小的后台服务线程,由交那个线程处理

  为了更清楚服务线程CServerThread的机制,先看回顾一下当时这个服务线程是如何被创建的。

  CServer类的Create()片断:

  for (int i = 0; i < num; i++) // 这里num是需要创建的服务线程的数量

  {

  int index = GetNextThreadNotificationID(); // 得到这个线程的一个标识,即在线程数组std::vector

  m_ThreadNotificationIDs中的index

  CServerThread *pThread = new CServerThread(WM_FILEZILLA_SERVERMSG + index);

  m_ThreadNotificationIDs[index] = pThread;

  // If the CREATE_SUSPENDED flag is specified, the thread is created in a suspended state,

  // and will not run until the ResumeThread function is called.

  // If this value is zero, the thread runs immediately after creation.

  if (pThread->Create(THREAD_PRIORITY_NORMAL, CREATE_SUSPENDED))

  {

  pThread->ResumeThread();

  m_ThreadArray.push_back(pThread);

  }

  }

  看一下pThread->Create(THREAD_PRIORITY_NORMAL, CREATE_SUSPENDED),由于CServerThread继承于CThread,因此调用了CThread的create:

  BOOL CThread::Create(int nPriority /*=THREAD_PRIORITY_NORMAL*/, DWORD dwCreateFlags /*=0*/)

  {

  m_hThread=CreateThread(0, 0, ThreadProc, this, dwCreateFlags, &m_dwThreadId); // 调用win api创建一个线程

  if (!m_hThread)

  {

  delete this;

  return FALSE;

  }

  ::SetThreadPriority(m_hThread, nPriority);

  return TRUE;

  }

  注意创建线程的时候,指定线程的初始状态为CREATE_SUSPENDED。

  创建成功后,调用pThread->ResumeThread():

  DWORD CThread::ResumeThread()

  {

  // 下面使用win API:ResumeThread启动这个线程,线程开动后, 会自动跑到ThreadProc函数(create时指定)

  DWORD res=::ResumeThread(m_hThread); // 这个函数过后,有两个线程在跑,一个是刚才的主线程,一个是刚启动的线程

  if (!m_started) // 主线程运行到这里,由于m_started还是0,所以通过下面的WaitForSingleObject,进行了等待状态

  {

  WaitForSingleObject(m_hEventStarted, INFINITE);

  }

  return res;

  }

  刚启动的线程进入了ThreadProc函数:

  DWORD WINAPI CThread::ThreadProc(LPVOID lpParameter)

  {

  // 在CreateThread时指定的参数LPVOID lpParameter为this,即CThread

  return ((CThread *)lpParameter)->Run();

  }

  即运行Run方法:

  DWORD CThread::Run()

  {

  InitInstance(); // 这里CServerThread类重写了这个方法,因此进入CServerThread::InitInstance(),进行了一些内存变量的初始

  化

  // The SetEvent function sets the specified event object to the signaled state.

  SetEvent(m_hEventStarted); // 设置event为active,使得刚才在等待的主线程复活,继续CServer的启动工作

  m_started = true;

  MSG msg;

  while (GetMessage(&msg, 0, 0, 0)) // 进入这个线程的消息循环

  {

  TranslateMessage(&msg);

  if (!msg.hwnd)

  OnThreadMessage(msg.message, msg.wParam, msg.lParam); // 调用OnThreadMessage处理消息

  DispatchMessage(&msg);

  }

  DWORD res=ExitInstance();

  delete this;

  return res;

  }

  可见,服务器启动后,刚开始没有消息时,CServerThread在GetMessage()时进入了block状态,一旦有消息到来,这个服务线程就苏醒,接着

  处理消息。

  下面回到最初的CListenSocket::OnAccept(),最后调用了pBestThread->AddSocket(sockethandle, m_ssl); // 转交服务线程来处理

  仔细看一下后台的服务线程是如何处理消息的。

  void CServerThread::AddSocket(SOCKET sockethandle, bool ssl)

  {

  // 调用了父类的方法

  PostThreadMessage(WM_FILEZILLA_THREADMSG, ssl ? FTM_NEWSOCKET_SSL : FTM_NEWSOCKET, (LPARAM)sockethandle);

  }

  接着:

  BOOL CThread::PostThreadMessage(UINT message, WPARAM wParam, LPARAM lParam)

  {

  // posts a message to the message queue of the specified thread.

  BOOL res=::PostThreadMessage(m_dwThreadId, message, wParam, lParam);;

  ASSERT(res);

  return res;

  }

  PostThreadMessage是windows API,作用是把消息message发送到线程m_dwThreadId,

  根据前面的代码,在这里就是把消息WM_FILEZILLA_THREADMSG,以及参数FTM_NEWSOCKET, sockethandle发送到那个负荷最小的后台服务线程,

  由于在启动时,那个后台线程处于GetMessage()的block中,因此收到这个消息到,那个后台线程苏醒,接着调用OnThreadMessage来处理这个WM_FILEZILLA_THREADMSG消息。

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

【编辑推荐】

  1. FileZilla简单介绍
  2. FileZilla 源代码分析1
  3. FileZilla 源代码分析2
  4. FileZilla 源代码分析3
  5. FileZilla 源代码分析4
  6. FileZilla 源代码分析5
  7. FileZilla:免费的服务器软件
  8. FileZilla 3.3.1.0新版升级 修复bug
责任编辑:赵鹏 来源: 网络转载
相关推荐

2011-02-23 14:46:21

FileZilla

2011-02-23 14:39:27

FileZilla

2011-02-23 14:16:43

FileZilla

2011-02-23 15:11:27

FileZilla

2011-02-23 15:33:42

FileZilla

2011-02-23 15:21:06

FileZilla

2011-02-23 15:26:01

FileZilla

2011-02-23 14:26:28

FileZilla

2011-02-23 13:47:33

FileZilla

2011-03-01 16:32:58

FileZilla

2011-03-01 16:01:08

FileZilla

2011-03-01 16:19:27

FileZilla

2011-03-01 16:25:37

FileZilla

2022-09-20 11:23:51

黑客GTA 6游戏

2015-08-28 09:38:51

Linux源代码分析工具

2018-05-25 14:16:55

NFS源代码线程

2015-08-26 17:38:47

Linux源代码

2009-07-02 13:59:35

JSP后台

2011-08-24 15:42:38

LUA源代码

2020-02-24 09:25:33

代码开发工具
点赞
收藏

51CTO技术栈公众号