VC FTP服务器程序分析(四)
下面是数据传输的重点-CDataSocket类,函数不多,都比较重要。
1、OnAccept 数据tcp服务器被连接的虚函数,由框架调用。
void CDataSocket::OnAccept(int nErrorCode)
{
// Accept the connection using a temp CSocket object.
CAsyncSocket tmpSocket;
Accept(tmpSocket); SOCKET socket = tmpSocket.Detach();
Close(); Attach(socket); m_bConnected = TRUE; CAsyncSocket::OnAccept(nErrorCode);
}
第7行 得到套接字描述符socket。第8行关闭监听的这个套接字,第11行关联socket与本对象,第12行,标记连接标志。这种处理方法少写一个类。因为tcp监听得一个socket,而连接上来的客户端也需要一个socket来与之通信。这样做适合只有一个客户端的情况。
2、OnReceive 数据接收处理函数
int CDataSocket::Receive()
{
TRACE("OnReceive\n");
int nRead = ; if (m_pControlSocket->m_nStatus == STATUS_UPLOAD)
{
if (m_File.m_hFile == NULL)
return ; byte data[PACKET_SIZE];
nRead = CAsyncSocket::Receive(data, PACKET_SIZE); switch(nRead)
{
case :
{
m_File.Close();
m_File.m_hFile = NULL;
Close();
// tell the client the transfer is complete.
m_pControlSocket->SendResponse("226 Transfer complete");
// destroy this socket
AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, , );
break;
}
case SOCKET_ERROR:
{
if (GetLastError() != WSAEWOULDBLOCK)
{
m_File.Close();
m_File.m_hFile = NULL;
Close();
m_pControlSocket->SendResponse("426 Connection closed; transfer aborted.");
// destroy this socket
AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, , );
}
break;
}
default:
{
TRY
{
m_File.Write(data, nRead);
}
CATCH_ALL(e)
{
m_File.Close();
m_File.m_hFile = NULL;
Close();
m_pControlSocket->SendResponse("450 Can't access file.");
// destroy this socket
AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, , );
return ;
}
END_CATCH_ALL;
break;
}
}
}
return nRead;
}
如果处于上传状态,那么将接收到的数据写入文件。
3、PreSendFile 与发送文件有关的函数
BOOL CDataSocket::PrepareSendFile(LPCTSTR lpszFilename)
{
// close file if it's already open
if (m_File.m_hFile != NULL)
{
m_File.Close();
} // open source file
if (!m_File.Open(lpszFilename, CFile::modeRead | CFile::typeBinary))
{
return FALSE;
}
m_nTotalBytesSend = m_File.GetLength(); if (m_pControlSocket->m_dwRestartOffset < m_nTotalBytesSend)
{
m_nTotalBytesTransfered = m_pControlSocket->m_dwRestartOffset;
}
else
{
m_nTotalBytesTransfered = ;
}
return TRUE;
}
初始化文件描述符m_File,m_nTotalBytesSend,m_nTotalBytesTransfered。
4、 SendFile函数 调用PrepareSendFile,调用OnSend发送文件。
void CDataSocket::SendFile(LPCTSTR lpszFilename)
{
if (!PrepareSendFile(lpszFilename))
{
// change status
m_pControlSocket->m_nStatus = STATUS_IDLE; m_pControlSocket->SendResponse("426 Connection closed; transfer aborted."); // destroy this socket
AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, , );
return;
}
OnSend();
}
5、SendData 发送数据 是为了LIST命令而准备,发送文件目录列表。
6、OnSend 主要区分了list命令的情况和download的情况。
void CDataSocket::OnSend(int nErrorCode)
{
CAsyncSocket::OnSend(nErrorCode);
switch(m_pControlSocket->m_nStatus)
{
case STATUS_LIST:
{
while (m_nTotalBytesTransfered < m_nTotalBytesSend)
{
DWORD dwRead;
int dwBytes; CString strDataBlock; dwRead = m_strData.GetLength(); if (dwRead <= PACKET_SIZE)
{
strDataBlock = m_strData;
}
else
{
strDataBlock = m_strData.Left(PACKET_SIZE);
dwRead = strDataBlock.GetLength();
} if ((dwBytes = Send(strDataBlock, dwRead)) == SOCKET_ERROR)
{
if (GetLastError() == WSAEWOULDBLOCK)
{
Sleep();
return;
}
else
{
TCHAR szError[];
wsprintf(szError, "Server Socket failed to send: %d", GetLastError()); // close the data connection.
Close(); m_nTotalBytesSend = ;
m_nTotalBytesTransfered = ; // change status
m_pControlSocket->m_nStatus = STATUS_IDLE; m_pControlSocket->SendResponse("426 Connection closed; transfer aborted."); // destroy this socket
AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, , );
}
}
else
{
m_nTotalBytesTransfered += dwBytes;
m_strData = m_strData.Mid(dwBytes);
}
}
if (m_nTotalBytesTransfered == m_nTotalBytesSend)
{
// close the data connection.
Close(); m_nTotalBytesSend = ;
m_nTotalBytesTransfered = ; // change status
m_pControlSocket->m_nStatus = STATUS_IDLE; // tell the client the transfer is complete.
m_pControlSocket->SendResponse("226 Transfer complete");
// destroy this socket
AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, , );
}
break;
}
case STATUS_DOWNLOAD:
{
while (m_nTotalBytesTransfered < m_nTotalBytesSend)
{
// allocate space to store data
byte data[PACKET_SIZE]; m_File.Seek(m_nTotalBytesTransfered, CFile::begin); DWORD dwRead = m_File.Read(data, PACKET_SIZE); int dwBytes; if ((dwBytes = Send(data, dwRead)) == SOCKET_ERROR)
{
if (GetLastError() == WSAEWOULDBLOCK)
{
Sleep();
break;
}
else
{
TCHAR szError[];
wsprintf(szError, "Server Socket failed to send: %d", GetLastError()); // close file.
m_File.Close();
m_File.m_hFile = NULL; // close the data connection.
Close(); m_nTotalBytesSend = ;
m_nTotalBytesTransfered = ; // change status
m_pControlSocket->m_nStatus = STATUS_IDLE; m_pControlSocket->SendResponse("426 Connection closed; transfer aborted."); // destroy this socket
AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, , );
}
}
else
{
m_nTotalBytesTransfered += dwBytes;
}
}
if (m_nTotalBytesTransfered == m_nTotalBytesSend)
{
// close file.
m_File.Close();
m_File.m_hFile = NULL; // close the data connection.
Close(); m_nTotalBytesSend = ;
m_nTotalBytesTransfered = ; // change status
m_pControlSocket->m_nStatus = STATUS_IDLE; // tell the client the transfer is complete.
m_pControlSocket->SendResponse("226 Transfer complete");
// destroy this socket
AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, , );
}
break;
}
}
}
7、OnConnect函数 tcp连接成功时被框架调用的虚函数。
8、OnClose函数 当数据发送完成或者接收完成后被框架调用的虚函数。主要做清理工作。
9、
VC FTP服务器程序分析(四)的更多相关文章
- VC FTP服务器程序分析(一)
想在QT上移植一个FTP服务器程序,先学习windows下的FTP服务器例子,然后随便动手写点东西. 在pudn上搜索 "FTP服务器端和客户端实现 VC“这几个关键字,就可以搜到下面要分析 ...
- VC FTP服务器程序分析(二)
上面讲到了CClientThread类,打开这个类的实现,这个类实现了4个函数.依次分析: 1.InitInstance 其说明如下:InitInstance必须被重载以初始化每个用户界面线程的新 ...
- VC FTP服务器程序分析(三)
CControlSocket类的分析,CControlSocket类的内容比较多,为什么呢.因为通信控制命令的传输全部在这里,通信协议的多样也导致了协议解析的多样. 1.OnReceive 其大致说 ...
- 搭建ftp服务器实现文件共享
FTP服务器(File Transfer Protocol Server)是在互联网上提供文件存储和访问服务的计算机,它们依照FTP协议提供服务. FTP(File Transfer Protocol ...
- 转:【专题十二】实现一个简单的FTP服务器
引言: 休息一个国庆节后好久没有更新文章了,主要是刚开始休息完心态还没有调整过来的, 现在差不多进入状态了, 所以继续和大家分享下网络编程的知识,在本专题中将和大家分享如何自己实现一个简单的FTP服务 ...
- Linux中搭建FTP服务器
FTP工作原理 (1)FTP使用端口 [root@localhost ~]# cat /etc/services | grep ftp ftp-data 20/tcp #数据链路:端口20 ftp 2 ...
- 专题十二:实现一个简单的FTP服务器
引言: 在本专题中将和大家分享如何自己实现一个简单的FTP服务器.在我们平时的上网过程中,一般都是使用FTP的客户端来对商家提供的服务器进行访问(上传.下载文件),例如我们经常用到微软的SkyDriv ...
- centos yum安装与配置vsFTPd FTP服务器(转)
vsftpd作为FTP服务器,在Linux系统中是非常常用的.下面我们介绍如何在centos系统上安装vsftp. 什么是vsftpd vsftpd是一款在Linux发行版中最受推崇的FTP服务器程序 ...
- [CentOs7]搭建ftp服务器
摘要 vsftpd 是“very secure FTP daemon”的缩写,安全性是它的一个最大的特点.vsftpd 是一个 UNIX 类操作系统上运行的服务器的名字,它可以运行在诸如 Linux. ...
随机推荐
- Java中的自动类型转换
Java里所有的数值型变量可以进行类型转换,这个大家都知道,应该不需要详细解释为什么. 2 在说明自动类型转换之前必须理解这样一个原则“表数范围小的可以向表数范围大的进行自动类型转换” 3 关于jav ...
- PHP文件上传类(页面和调用部分)
<!--upform.html内容--> <form action="upload.php" method="post" enctype=&q ...
- Hubtown
Hubtown 时间限制: 10 Sec 内存限制: 256 MB 题目描述 Hubtown is a large Nordic city which is home to n citizens. ...
- uva 11995 判别数据类型
Problem I I Can Guess the Data Structure! There is a bag-like data structure, supporting two operati ...
- Count on a tree(bzoj 2588)
Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始 ...
- ElasticSearch API 之 GET
GET API是Elasticsearch中常用的操作,一般用于验证文档是否存在:或者执行CURD中的文档查询.与检索不同的是,GET查询是实时查询,可以实时查询到索引结果.而检索则是需要经过处理才能 ...
- 自定义header参数时的命名要求
HTTP头是可以包含英文字母([A-Za-z]).数字([0-9]).连接号(-)hyphens, 也可义是下划线(_).在使用nginx的时候应该避免使用包含下划线的HTTP头.主要的原因有以下2点 ...
- 在 VirtualBox 5.0 系列中让虚拟机支持 USB 3.0 必须开启 APIC
VirtualBox 5.0 系列正式支持 USB 3.0,能够在宿主机支持 USB 3.0 的情况下,让虚拟机也选择具备 USB 3.0 的功能.但是经过多方试验,发现必须在 VirtualBox ...
- LeetCode OJ--Partition List
http://oj.leetcode.com/problems/partition-list/ 链表的处理 #include <iostream> using namespace std; ...
- android EditText禁止复制粘贴完整代码
<!-- 定义基础布局LinearLayout --> <LinearLayout xmlns:android="http://schemas.android.com/ap ...