VC FTP服务器程序分析(四)
2016-01-25 10:49
671 查看
下面是数据传输的重点-CDataSocket类,函数不多,都比较重要。
1、OnAccept 数据tcp服务器被连接的虚函数,由框架调用。
第7行 得到套接字描述符socket。第8行关闭监听的这个套接字,第11行关联socket与本对象,第12行,标记连接标志。这种处理方法少写一个类。因为tcp监听得一个socket,而连接上来的客户端也需要一个socket来与之通信。这样做适合只有一个客户端的情况。
2、OnReceive 数据接收处理函数
如果处于上传状态,那么将接收到的数据写入文件。
3、PreSendFile 与发送文件有关的函数
初始化文件描述符m_File,m_nTotalBytesSend,m_nTotalBytesTransfered。
4、 SendFile函数 调用PrepareSendFile,调用OnSend发送文件。
5、SendData 发送数据 是为了LIST命令而准备,发送文件目录列表。
6、OnSend 主要区分了list命令的情况和download的情况。
7、OnConnect函数 tcp连接成功时被框架调用的虚函数。
8、OnClose函数 当数据发送完成或者接收完成后被框架调用的虚函数。主要做清理工作。
9、
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 = 0; if (m_pControlSocket->m_nStatus == STATUS_UPLOAD) { if (m_File.m_hFile == NULL) return 0; byte data[PACKET_SIZE]; nRead = CAsyncSocket::Receive(data, PACKET_SIZE); switch(nRead) { case 0: { 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, 0, 0); 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, 0, 0); } 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, 0, 0); return 0; } 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 = 0; } 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, 0, 0); return; } OnSend(0); }
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(0); return; } else { TCHAR szError[256]; wsprintf(szError, "Server Socket failed to send: %d", GetLastError()); // close the data connection. Close(); m_nTotalBytesSend = 0; m_nTotalBytesTransfered = 0; // change status m_pControlSocket->m_nStatus = STATUS_IDLE; m_pControlSocket->SendResponse("426 Connection closed; transfer aborted."); // destroy this socket AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0); } } else { m_nTotalBytesTransfered += dwBytes; m_strData = m_strData.Mid(dwBytes); } } if (m_nTotalBytesTransfered == m_nTotalBytesSend) { // close the data connection. Close(); m_nTotalBytesSend = 0; m_nTotalBytesTransfered = 0; // 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, 0, 0); } 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(0); break; } else { TCHAR szError[256]; 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 = 0; m_nTotalBytesTransfered = 0; // change status m_pControlSocket->m_nStatus = STATUS_IDLE; m_pControlSocket->SendResponse("426 Connection closed; transfer aborted."); // destroy this socket AfxGetThread()->PostThreadMessage(WM_DESTROYDATACONNECTION, 0, 0); } } 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 = 0; m_nTotalBytesTransfered = 0; // 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, 0, 0); } break; } } }
7、OnConnect函数 tcp连接成功时被框架调用的虚函数。
8、OnClose函数 当数据发送完成或者接收完成后被框架调用的虚函数。主要做清理工作。
9、
相关文章推荐
- crontab无法执行php的解决方法
- win7安装php框架Yii的方法
- ThinkPHP3.2.3目录结构
- PHP扩展开发(4) - 多类扩展
- PHP扩展开发(3)-config.m4
- php结合md5实现的加密解密方法
- 如何解决PHP里大量数据循环时内存耗尽的问题
- PHP实现飞信接口来通过网页免费发短信
- PHP 文件操作类(创建文件并写入) 生成日志
- 如何解决PHP查询大量数据内存耗尽的问题
- PHP几个实用自定义函数小结
- PHP
- php empty()和isset()的区别
- PHP几个实用自定义函数小结
- php结合md5实现的加密解密方法
- win7安装php框架Yii的方法
- crontab无法执行php的解决方法
- 基于命令行执行带参数的php脚本并取得参数的方法
- PHP设置头信息及取得返回头信息的方法
- PHP+apc+ajax实现的ajax_upload上传进度条代码