15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


FTP Сервер.

Компилятор: Visual C++

Автор: Pablo van der Meer

Описание

В этой статье представлен многопотоковый полнофункциональный FTP сервер. Сервер понимает все основные команды FTP, поддерживает авторизацию пользователей и виртуальные директории.

Ниже представлены основные классы приложения:

CFTPServer

Этот класс фактически является самим FTP сервером и управляет остальными классами, необходимыми для работы сервера. CFTPServer является частью диалогового приложения и не имеет пользовательского интерфейса, поэтому может быть легко использован как сервис или консольное приложение.

Методы:

Метод Описание
BOOL Start() Активирует FTP сервер. Он открывает "слушающий" сокет (порт 21) для ожидания соединений.
void Stop() Останавливает сервер и разрывает все соединения клиентов путём прекращения всех запущенных потоков.
BOOL IsActive() Активен ли FTP сервер?
void SetMaxUsers(int nValue) Устанавливает максимальное количество пользователей.
void SetPort(int nValue) Устанавливает слушающий порт для нового соединения.
void SetTimeout(int nValue) Устанавливает тайм-аут для соединения (в мс).
Если клиент не пришлёт никакой команды через nValue мс, то сервер закроет соединение.
void SetWelcomeMessage(LPCTSTR lpszText) Устанавливает текст, который будет показан, когда пользователь залогинится.
void SetSecurityMode(BOOL bBlockSpecific) Устанавливает режим доступа (security).
Их всего два:
Первый проверяет список заблокированных IP адресов, а второй разрешает соединения только с IP адресами которые присутствуют в списке только разрешённых адресов.
void Initialize(CFTPEventSink *pEventSink) Устанавливает приёмник событий.
Приёмник событий, это окно (или класс) который принимает события сгенерированные FTP сервером.
Более детальную информацию см. в CFTPEventSink.

CFTPEventSink

Этот класс используется для того, чтобы сделать возможным "посылку" событий из класса CFTPServer в главное приложение. CFTPEventSink это всего лишь вспомогательный класс, который не содержит ничего кроме виртуальных функций. CFTPServer ссылается на этот класс и вызывает эти виртуальные функции, когда ему необходимо уведомить приложение.

Доступны следующие события:

Событие Описание
void OnFTPUserConnected(DWORD nThreadID, LPCTSTR lpszUser, LPCSTR lpszAddress); Клиент успешно соединился.
void OnFTPUserDisconnected(DWORD nThreadID, LPCTSTR lpszUser); Клиент завершил соединение.
void OnFTPStatusChange(int nType, LPCTSTR lpszText); Состояние FTP сервера изменилось (файл скачан/закачан).
void OnFTPReceivedBytesChange(int nBytes); Изменилось количество принятых байт.
void OnFTPSentBytesChange(int nBytes); Изменилось количество переданных байт.
void OnFTPStatisticChange(int nType, int nValue); Статистика изменилась, например количество принятых или переданных файлов.
Другие вспомогательные классы:
CUserManager Класс CUserManager обрабатывает всё, что связано с пользователями и файлами. Он проверяет подключённых пользователей на права доступа и преобразует удалённый и локальный пути. CUserManager использует Сериализацию для хранения и загрузки пользовательских настроек.
CSecurityManager FTP сервер может хранить список IP адресов, которым запрещено соединение с сервером. Так же сервер может блокировать все адреса, заисключением тех, которые разрешены. CSecurityManager управляет этими двумя списками и следит за хранением и загрузкой их с диска.
CListenSocket Этот сокет является частью CFTPServer и аксептит входящие соединения. Когда клиент коннектится к серверу, то CListenSocket аксептит соединение и создаёт новый поток (CConnectThread), который полностью заботится о соединение между клиентом и сервером. После того, как поток создан, CListenSocket вернётся в ожидающее состояние.
CConnectThread Этот поток обрабатывает соединение между сервером и клиентом используя CConnectSocket.
CConnectSocket Этот класс сокета обрабатывает все входящие команды FTP и отправляет обратно клиенту ответы.
CDataSocket Когда необходимо отправить или принять данные, то в CConnectSocket создаётся CDataSocket. Класс CDataSocket передаёт эти данные (такие как список директорий и файлов) на отдельном порту.

Все остальные классы, это всего лишь настройки для пользовательского интерфейса.

Использование класса CFTPServer

Для использования класса в своём приложение, необходимо проделать следующее:

  1. Добавить класс в приложение
  2. Наследовать свой главный класс от CFTPEventSink
  3. Переопределить виртуальные функции в CFTPEventSink; это события, которые будут поступать от сервера.
  4. Инициализировать приёмник событий
  5. Запустить сервер.
class CMyDlg : public CDialog, CFTPEventSink
{
  ...

  CFTPServer m_FTPSERVER;

  virtual void OnFTPUserConnected(DWORD nThreadID,
                                  LPCTSTR lpszUser,
                                  LPCSTR lpszAddress);
  virtual void OnFTPUserDisconnected(DWORD nThreadID,
                                     LPCTSTR lpszUser);
  virtual void OnFTPStatusChange(int nType,
                                 LPCTSTR lpszText);
  virtual void OnFTPReceivedBytesChange(int nBytes);
  virtual void OnFTPSentBytesChange(int nBytes);
  virtual void OnFTPStatisticChange(int nType,
                                    int nValue);

  ...
}


BOOL CMyDlg::OnInitDialog()
{
  CDialog::OnInitDialog();

  ...

  // инициализирует приёмник событий
  m_FTPSERVER.Initialize(this);
  // устанавливаем максимальное количество пользователей в 10
  m_FTPSERVER.SetMaxUsers(10);
  // разрешаем новые соединения на 21-ом порту
  m_FTPSERVER.SetPort(21);
  // активируем сервер
  m_FTPSERVER.Start();

  return TRUE;
}

Downloads

Скачать демонстрационный пример - 80 Kb
Скачать исходник - 121 Kb