VC FTP服务器程序分析(四)

  下面是数据传输的重点-CDataSocket类,函数不多,都比较重要。

  1、OnAccept  数据tcp服务器被连接的虚函数,由框架调用。

 1 void CDataSocket::OnAccept(int nErrorCode)
 2 {
 3     // Accept the connection using a temp CSocket object.
 4     CAsyncSocket tmpSocket;
 5     Accept(tmpSocket);
 6
 7     SOCKET socket = tmpSocket.Detach();
 8     Close();
 9
10     Attach(socket);
11
12     m_bConnected = TRUE;
13
14     CAsyncSocket::OnAccept(nErrorCode);
15 }

  第7行 得到套接字描述符socket。第8行关闭监听的这个套接字,第11行关联socket与本对象,第12行,标记连接标志。这种处理方法少写一个类。因为tcp监听得一个socket,而连接上来的客户端也需要一个socket来与之通信。这样做适合只有一个客户端的情况。

  2、OnReceive  数据接收处理函数

 1 int CDataSocket::Receive()
 2 {
 3     TRACE("OnReceive\n");
 4     int nRead = 0;
 5
 6     if (m_pControlSocket->m_nStatus == STATUS_UPLOAD)
 7     {
 8         if (m_File.m_hFile == NULL)
 9             return 0;
10
11         byte data[PACKET_SIZE];
12         nRead = CAsyncSocket::Receive(data, PACKET_SIZE);
13
14         switch(nRead)
15         {
16             case 0:
17             {
18                 m_File.Close();
19                 m_File.m_hFile = NULL;
20                 Close();
21                 // tell the client the transfer is complete.
22                 m_pControlSocket->SendResponse("226 Transfer complete");
23                 // destroy this socket
24                 AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
25                 break;
26             }
27             case SOCKET_ERROR:
28             {
29                 if (GetLastError() != WSAEWOULDBLOCK)
30                 {
31                     m_File.Close();
32                     m_File.m_hFile = NULL;
33                     Close();
34                     m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");
35                     // destroy this socket
36                     AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
37                 }
38                 break;
39             }
40             default:
41             {
42                 TRY
43                 {
44                     m_File.Write(data, nRead);
45                 }
46                 CATCH_ALL(e)
47                 {
48                     m_File.Close();
49                     m_File.m_hFile = NULL;
50                     Close();
51                     m_pControlSocket->SendResponse("450 Can‘t access file.");
52                     // destroy this socket
53                     AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
54                     return 0;
55                 }
56                 END_CATCH_ALL;
57                 break;
58             }
59         }
60     }
61     return nRead;
62 }

  如果处于上传状态,那么将接收到的数据写入文件。

  3、PreSendFile 与发送文件有关的函数

 1 BOOL CDataSocket::PrepareSendFile(LPCTSTR lpszFilename)
 2 {
 3     // close file if it‘s already open
 4     if (m_File.m_hFile != NULL)
 5     {
 6         m_File.Close();
 7     }
 8
 9     // open source file
10     if (!m_File.Open(lpszFilename, CFile::modeRead | CFile::typeBinary))
11     {
12         return FALSE;
13     }
14     m_nTotalBytesSend = m_File.GetLength();
15
16     if (m_pControlSocket->m_dwRestartOffset < m_nTotalBytesSend)
17     {
18         m_nTotalBytesTransfered = m_pControlSocket->m_dwRestartOffset;
19     }
20     else
21     {
22         m_nTotalBytesTransfered = 0;
23     }
24     return TRUE;
25 }

 初始化文件描述符m_File,m_nTotalBytesSend,m_nTotalBytesTransfered。

 4、 SendFile函数  调用PrepareSendFile,调用OnSend发送文件。

 1 void CDataSocket::SendFile(LPCTSTR lpszFilename)
 2 {
 3     if (!PrepareSendFile(lpszFilename))
 4     {
 5         // change status
 6         m_pControlSocket->m_nStatus = STATUS_IDLE;
 7
 8         m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");
 9
10         // destroy this socket
11         AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
12         return;
13     }
14     OnSend(0);
15 }

 5、SendData 发送数据 是为了LIST命令而准备,发送文件目录列表。

 6、OnSend 主要区分了list命令的情况和download的情况。

  1 void CDataSocket::OnSend(int nErrorCode)
  2 {
  3     CAsyncSocket::OnSend(nErrorCode);
  4     switch(m_pControlSocket->m_nStatus)
  5     {
  6         case STATUS_LIST:
  7         {
  8             while (m_nTotalBytesTransfered < m_nTotalBytesSend)
  9             {
 10                 DWORD dwRead;
 11                 int dwBytes;
 12
 13                 CString strDataBlock;
 14
 15                 dwRead = m_strData.GetLength();
 16
 17                 if (dwRead <= PACKET_SIZE)
 18                 {
 19                     strDataBlock = m_strData;
 20                 }
 21                 else
 22                 {
 23                     strDataBlock = m_strData.Left(PACKET_SIZE);
 24                     dwRead = strDataBlock.GetLength();
 25                 }
 26
 27                 if ((dwBytes = Send(strDataBlock, dwRead)) == SOCKET_ERROR)
 28                 {
 29                     if (GetLastError() == WSAEWOULDBLOCK)
 30                     {
 31                         Sleep(0);
 32                         return;
 33                     }
 34                     else
 35                     {
 36                         TCHAR szError[256];
 37                         wsprintf(szError, "Server Socket failed to send: %d", GetLastError());
 38
 39                         // close the data connection.
 40                         Close();
 41
 42                         m_nTotalBytesSend = 0;
 43                         m_nTotalBytesTransfered = 0;
 44
 45                         // change status
 46                         m_pControlSocket->m_nStatus = STATUS_IDLE;
 47
 48                         m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");
 49
 50                         // destroy this socket
 51                         AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
 52                     }
 53                 }
 54                 else
 55                 {
 56                     m_nTotalBytesTransfered += dwBytes;
 57                     m_strData = m_strData.Mid(dwBytes);
 58                 }
 59             }
 60             if (m_nTotalBytesTransfered == m_nTotalBytesSend)
 61             {
 62                 // close the data connection.
 63                 Close();
 64
 65                 m_nTotalBytesSend = 0;
 66                 m_nTotalBytesTransfered = 0;
 67
 68                 // change status
 69                 m_pControlSocket->m_nStatus = STATUS_IDLE;
 70
 71                 // tell the client the transfer is complete.
 72                 m_pControlSocket->SendResponse("226 Transfer complete");
 73                 // destroy this socket
 74                 AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
 75             }
 76             break;
 77         }
 78         case STATUS_DOWNLOAD:
 79         {
 80             while (m_nTotalBytesTransfered < m_nTotalBytesSend)
 81             {
 82                 // allocate space to store data
 83                 byte data[PACKET_SIZE];
 84
 85                 m_File.Seek(m_nTotalBytesTransfered, CFile::begin);
 86
 87                 DWORD dwRead = m_File.Read(data, PACKET_SIZE);
 88
 89                 int dwBytes;
 90
 91                 if ((dwBytes = Send(data, dwRead)) == SOCKET_ERROR)
 92                 {
 93                     if (GetLastError() == WSAEWOULDBLOCK)
 94                     {
 95                         Sleep(0);
 96                         break;
 97                     }
 98                     else
 99                     {
100                         TCHAR szError[256];
101                         wsprintf(szError, "Server Socket failed to send: %d", GetLastError());
102
103                         // close file.
104                         m_File.Close();
105                         m_File.m_hFile = NULL;
106
107                         // close the data connection.
108                         Close();
109
110                         m_nTotalBytesSend = 0;
111                         m_nTotalBytesTransfered = 0;
112
113                         // change status
114                         m_pControlSocket->m_nStatus = STATUS_IDLE;
115
116                         m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");
117
118                         // destroy this socket
119                         AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
120                     }
121                 }
122                 else
123                 {
124                     m_nTotalBytesTransfered += dwBytes;
125                 }
126             }
127             if (m_nTotalBytesTransfered == m_nTotalBytesSend)
128             {
129                 // close file.
130                 m_File.Close();
131                 m_File.m_hFile = NULL;
132
133                 // close the data connection.
134                 Close();
135
136                 m_nTotalBytesSend = 0;
137                 m_nTotalBytesTransfered = 0;
138
139                 // change status
140                 m_pControlSocket->m_nStatus = STATUS_IDLE;
141
142                 // tell the client the transfer is complete.
143                 m_pControlSocket->SendResponse("226 Transfer complete");
144                 // destroy this socket
145                 AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0);
146             }
147             break;
148         }
149     }
150 }

  7、OnConnect函数  tcp连接成功时被框架调用的虚函数。

  8、OnClose函数 当数据发送完成或者接收完成后被框架调用的虚函数。主要做清理工作。

  9、

 

时间: 2024-10-14 04:45:34

VC FTP服务器程序分析(四)的相关文章

VC FTP服务器程序分析(二)

上面讲到了CClientThread类,打开这个类的实现,这个类实现了4个函数.依次分析: 1.InitInstance   其说明如下:InitInstance必须被重载以初始化每个用户界面线程的新实例.统称,你重载InitInstance函数来执行当线程首次被创建时必须完成的任务.此成员函数仅在用户界面线程中使用. 1 BOOL CClientThread::InitInstance() 2 { 3 // Attach the socket handle to a CSocket objec

VC FTP服务器程序分析(三)

CControlSocket类的分析,CControlSocket类的内容比较多,为什么呢.因为通信控制命令的传输全部在这里,通信协议的多样也导致了协议解析的多样. 1.OnReceive  其大致说明:本函数由框架调用,通知套接字缓冲中有数据,可以调用Receive函数取出. 1 void CControlSocket::OnReceive(int nErrorCode) 2 { 3 try 4 { 5 TCHAR buff[BUFFER_SIZE+1]; 6 7 int nRead = Re

通过IIS设置架设FTP服务器程序步骤

FTP服务器在文件的传输上性能稳定,占用系统资源小,而且传输速度快,现在网上已经有很多的FTP服务器可供使用,而微软IIS强大的功能,除了提供WWW服务之外,还提供FTP的服务,利用它就可以很容易架设一个功能卓越的FTP服务器.下面介绍通过设置IIS来架设FTP服务器的几个步骤.    第一步:启动IIS及FTP服务.在默认情况下,FTP服务器已搭建好,并可立即登录,但FTP中是空的,没有文件.    第二步:通过IIS默认FTP站点-属性,调出对话框,选择“主目录”的标签,在“本地路径”填写共

使用事件驱动模型实现高效稳定的网络服务器程序

使用事件驱动模型实现高效稳定的网络服务器程序 几种网络服务器模型的介绍与比较 围绕如何构建一个高效稳定的网络服务器程序,本文从一个最简单的服务器模型开始,依次介绍了使用多线程的服务器模型.使用非阻塞接口的服务器模型.利用select()接口实现的基于事件驱动的服务器模型,和使用libev事件驱动库的服务器模型.通过比较各个模型,得出事件驱动模型更适合构建高效稳定的网络服务器程序的结论. 前言 事件驱动为广大的程序员所熟悉,其最为人津津乐道的是在图形化界面编程中的应用:事实上,在网络编程中事件驱动

linux下搭建ftp服务器(转载)

vsftpd是一款在Linux发行版中最受推崇的FTP服务器程序.特点是小巧轻快,安全易用.并且是一个完全免费开放源码的ftp软件 工具/原料 CentOS6.4 方法/步骤 1 用在线安装 yum install vsftpd pam* db4*-y 使用命令将vsftp配置为系统服务 chkconfig --level 35 vsftpd on 2 配置vsftpd服务的宿主 useradd vsftpdadmin -s /sbin/nologin -M 这个vsftpdadmin只是用来替

搭建ftp服务器实现文件共享

FTP服务器(File Transfer Protocol Server)是在互联网上提供文件存储和访问服务的计算机,它们依照FTP协议提供服务. FTP(File Transfer Protocol: 文件传输协议)作用: Internet 上用来传送文件的协议. 常见FTP服务器: windows:Serv-U FTP Server Linux:ProFTPD:(Professional FTP daemon)一个Unix平台上或是类Unix平台上(如Linux, FreeBSD等)的FTP

CentOS 7.3 FTP服务器的安装与配置

一.FTP服务简介 1. FTP服务和FTP协议 FTP服务是Internet上最早应用主机之间进行数据传输的基本服务之一.FTP服务的一个非常重要的特点就是可以独立于平台,也就是说在UNIX.MAC.Windows等操作系统中都可以实现FTP的客户端和服务器.尽管目前已经普遍采用HTTP方式传送文件,但FTP仍然是跨平台直接传送文件的主要方式. FTP文件传输协议(File Transfer Protocol,FTP).该协议定义了一个在远程计算机系统和本地计算机系统之间传输文件的一个标准.F

centos yum安装与配置vsFTPd FTP服务器(转)

vsftpd作为FTP服务器,在Linux系统中是非常常用的.下面我们介绍如何在centos系统上安装vsftp. 什么是vsftpd vsftpd是一款在Linux发行版中最受推崇的FTP服务器程序.特点是小巧轻快,安全易用. vsftpd 的名字代表"very secure FTP daemon", 安全是它的开发者 Chris Evans 考虑的首要问题之一.在这个 FTP 服务器设计开发的最开始的时候,高安全性就是一个目标. 安装vsftpd 1.以管理员(root)身份执行以

CentOS6.5搭建ftp服务器

FTP 是FileTransfer Protocol(文件传输协议)的英文简称,而中文简称为"文传协议".用于Internet上的控制文件的双向传输.同时,它也是一个应用程序(Application).基于不同的操作系统有不同的FTP应用程序,而所有这些应用程序都遵守同一种协议以传输文件.在FTP的使用当中,用户经常遇到两个概念:"下载"(Download)和"上传"(Upload)."下载"文件就是从远程主机拷贝文件至自己的