SocketAPI 实现FTPServer文件下载
来源:互联网 发布:女孩晒巨臀照走红网络 编辑:程序博客网 时间:2024/06/07 03:42
//.h file
#ifndef __FTPCLIENT_H__
#define __FTPCLIENT_H__
class FTPClient
{
public:
FTPClient();
virtual ~FTPClient();
public:
//@Function create control connection, connect to ftp server, log on to ftp server,
// open data connection, start thread to download data.
//@Param
//@Return TRUE if successful to complete operations above, else return FALSE.
BOOL Active(char* pAddress, // ftp server address.
int nPort, // ftp server port.
char* pUserName, // user name to log on to server.
char* pPassword, // password to log on.
char* pRemoteFile); // remote file name located on ftp server.
//@Function stop thread, close data connection, log off from ftp server, close control connection.
//@Param
//@Return
void Inactive();
//@Function get bytes currently received from ftp server.
//@Param
//@Return the bytes currently received.
LONGLONG GetBytesNumber();
public:
//@Function virtual function that will be implemented by child class to do data process.
// when data is receive from ftp server, this function will be called automaticly.
//@Param char* pBuffer: data buffer that received from ftp server.
//@Param int nBufLen: data buffer length.
virtual BOOL OnReceive(char* pBuffer, int nBufLen);
//@Function virtual function that should be implemented by child class to implement error process.
// when error occurs while downloading from ftp server, this function is called.
//@Param DWORD dwError: error code.
//@Param char* strError:error description.
virtual void OnError(DWORD dwError, char* strError);
//@Function virtual function that should be implemented by child class to implement error
// log when error occurs.
//@Param DWORD dwError: error code.
//@Param char* strError:error description.
virtual void OnLogError(DWORD dwError, char* strError);
//@Function virtual function that should be implemented by child class to process some operations
// when data is end of stream such as pop a dialog to notify user that downloading is
// successfully finished or notify down stream that upstream is end of stream.
virtual void OnEndOfStream();
protected:
BOOL EstablishCtrlConnection(char* pAddress, int nPort);
BOOL LogOnToServer(char* pUser, char* pPassword);
BOOL EstablishDataConnection(char* strRemoteFile);
void CloseDataConnection();
void LogOffServer();
void CloseCtrlConnection();
DWORD FunThread();
static DWORD WINAPI EntryThread(LPVOID lParam);
private:
//@Function read command line until command line is read successfully, user cancel, or error occurs.
//@Param char* pBuffer: buffer to retrieve data.
//@Param int nLen: buffer length.
//@Param int* nCode: pointer to retrieve command response code such as 220, 150.
//@Param int* nLenRead: data length that is read, include '/n';
//@Param DWORD *dwError: pointer to retrieve the error code.
//Return 0 successful to receive one complete command line.
// 1 user cancels this operation.
// -1 error occurs while receiving data from ftp server.
int ReadCmdLine(char* pBuffer, int nLen, int* nCode, int* nLenRead, DWORD* dwError);
//@Function read one complete cmd response command until it is successful to read, user cancel, or error occurs.
//@Param DWORD *dwError: pointer to retrieve the error code.
//Return 0 successful to receive one complete response.
// 1 user cancels this operation.
// -1 error occurs while receiving data from ftp server.
int ReadCmdResponse(DWORD* dwError);
//@Function send complete data until all the data is sent, user cancels, or error occurs.
//@Param char* pBuffer: data to send. it must end with '/r/n'.
//@Param int nLen: data length, including '/r/n';
//@Param DWORD* dwError: pointer to retrieve error code.
//@Return 0 successful to send all the data to ftp server.
// 1 user cancel this operation.
// -1 error occurs while sending data.
int SendCmdLine(char* pBuffer, int nLen, DWORD* dwError);
protected:
char m_strAddress[MAX_PATH]; // ftp server address.
int m_nPort; // ftp server port.
char m_strUser[MAX_PATH]; // user name to log on.
char m_strPassword[MAX_PATH]; // user password to log on.
char m_strRemoteFile[MAX_PATH]; // file located on ftp server to download.
DWORD m_dwError; // error code.
LONGLONG m_llBytes; // bytes current received.
protected:
SOCKET m_hSktCtrl; // control connection to ftp server.
SOCKET m_hSktSvr; // server socket handle to wait for ftp server to connect.
SOCKET m_hSktData; // data connection.
protected:
HANDLE m_hThread; // thread handle to receive data.
HANDLE m_hEvent; // event to quit from thread.
int m_fc; // return code.
DWORD m_dwID; // instance id.
char* m_pBuffer;
};
#endif
//cpp file
#include "stdafx.h"
#include <winsock2.h>
#include "SocketApi.h"
#include "FTPClient.h"
DWORD gdwFTPClientID = 0;
FTPClient::FTPClient():
m_nPort(21)
,m_dwError(0)
,m_llBytes(0)
,m_hSktCtrl(INVALID_SOCKET)
,m_hSktSvr(INVALID_SOCKET)
,m_hSktData(INVALID_SOCKET)
,m_hThread(NULL)
,m_hEvent(NULL)
,m_fc(0)
,m_dwID(-1)
{
gdwFTPClientID++;
m_dwID = gdwFTPClientID;
m_pBuffer = new char[1025];
}
FTPClient::~FTPClient()
{
delete[] m_pBuffer;
}
//@Function create control connection, connect to ftp server, log on to ftp server,
// open data connection, start thread to download data.
//@Param
//@Return TRUE if successful to complete operations above, else return FALSE.
BOOL FTPClient::Active(char* pAddress, // ftp server address
int nPort, // ftp server port
char* pUserName, // user name to log on to server
char* pPassword, // password to log on
char* pRemoteFile) // remote file name located on ftp server
{
char sMsg[1000];
m_hEvent = CreateEvent( NULL, TRUE, FALSE, NULL);
if( m_hEvent==NULL )
{
m_dwError = GetLastError();
OnLogError(m_dwError, "Error:: FTPClient Active:Failed to create event.");
return FALSE;
}
BOOL bRet = EstablishCtrlConnection(pAddress, nPort);
if( !bRet )
{
m_dwError = GetLastError();
sprintf(sMsg,"Error::FTPClient Active:EstablishCtrlConnection %s %d %x",pAddress,nPort,m_dwError);
OnLogError(m_dwError, sMsg);
CloseHandle( m_hEvent);
m_hEvent = 0;
return FALSE;
}
bRet = LogOnToServer(pUserName, pPassword);
if( !bRet )
{
m_dwError = GetLastError();
sprintf(sMsg,"Error::FTPClient Active:LogOnToServer %s %s %x",pUserName,pPassword,m_dwError);
OnLogError(m_dwError, sMsg);
CloseCtrlConnection();
CloseHandle( m_hEvent);
m_hEvent = 0;
return FALSE;
}
bRet = EstablishDataConnection(pRemoteFile);
if( !bRet )
{
m_dwError = GetLastError();
sprintf(sMsg,"Error::FTPClient Active:EstablishDataConnection %s %x",pRemoteFile,m_dwError);
OnLogError(m_dwError, sMsg);
LogOffServer();
CloseCtrlConnection();
CloseHandle( m_hEvent);
m_hEvent = 0;
return FALSE;
}
DWORD dwThreadID = 0;
m_hThread = CreateThread(NULL, 0, EntryThread, (LPVOID)this, 0, &dwThreadID);
if( m_hThread==0 )
{
m_dwError = GetLastError();
sprintf(sMsg,"Error::FTPClient Active:EntryThread %x",m_dwError);
OnLogError(m_dwError, sMsg);
CloseDataConnection();
LogOffServer();
CloseCtrlConnection();
CloseHandle( m_hEvent);
m_hEvent = 0;
return FALSE;
}
m_dwError = 0;
return TRUE;
}
//@Function stop thread, close data connection, log off from ftp server, close control connection.
//@Param
//@Return
void FTPClient::Inactive()
{
if( m_hEvent )
{
SetEvent( m_hEvent );
}
if( m_hThread )
{
WaitForSingleObject( m_hThread, INFINITE);
CloseHandle( m_hThread);
m_hThread = 0;
}
CloseDataConnection();
LogOffServer();
CloseCtrlConnection();
if( m_hEvent )
{
CloseHandle( m_hEvent);
m_hEvent = 0;
}
}
//@Function get bytes currently received from ftp server.
//@Param
//@Return the bytes currently received.
LONGLONG FTPClient::GetBytesNumber()
{
return m_llBytes;
}
//@Function virtual function that will be implemented by child class to do data process.
// when data is receive from ftp server, this function will be called automaticly.
//@Param char* pBuffer: data buffer that received from ftp server.
//@Param int nBufLen: data buffer length.
BOOL FTPClient::OnReceive(char* pBuffer, int nBufLen)
{
return TRUE;
}
//@Function virtual function that should be implemented by child class to implement error process.
// when error occurs while downloading from ftp server, this function is called.
//@Param DWORD dwError: error code.
//@Param char* strError:error description.
void FTPClient::OnError(DWORD dwError, char* strError)
{
}
//@Function virtual function that should be implemented by child class to implement error
// log when error occurs.
//@Param DWORD dwError: error code.
//@Param char* strError:error description.
void FTPClient::OnLogError(DWORD dwError, char* strError)
{
}
//@Function virtual function that should be implemented by child class to process some operations
// when data is end of stream such as pop a dialog to notify user that downloading is
// successfully finished or notify down stream that upstream is end of stream.
void FTPClient::OnEndOfStream()
{
}
BOOL FTPClient::EstablishCtrlConnection(char* pAddress, int nPort)
{
char sMsg[2000];
strcpy( m_strAddress, pAddress);
m_nPort = nPort;
m_hSktCtrl = CSocketInterface::CreateClientSocket(&m_dwError);
if( m_hSktCtrl==INVALID_SOCKET )
{
sprintf(sMsg,"Error::FTPClient EstablishCtrlConnection:Failed to create client socket. %x",m_dwError);
OnLogError(m_dwError,sMsg);
return FALSE;
}
if( !CSocketInterface::Connect(m_hSktCtrl, pAddress, nPort, &m_dwError) )
{
sprintf(sMsg,"Error::FTPClient EstablishCtrlConnection:Failed to connect to ftp server. %s %d %x",pAddress,nPort,m_dwError);
OnLogError(m_dwError, sMsg);
closesocket( m_hSktCtrl );
m_hSktCtrl = INVALID_SOCKET;
return FALSE;
}
int nRet = ReadCmdResponse(&m_dwError);
if( nRet!=0 )
{
sprintf(sMsg,"Error::FTPClient EstablishCtrlConnection:Failed to ReadCmdResponse %x",m_dwError);
OnLogError(m_dwError, sMsg);
closesocket( m_hSktCtrl );
m_hSktCtrl = INVALID_SOCKET;
return FALSE;
}
m_dwError = 0;
return TRUE;
}
BOOL FTPClient::LogOnToServer(char* pUser, char* pPassword)
{
strcpy(m_strUser, pUser);
strcpy(m_strPassword, pPassword);
int nRet = 0;
char strBuffer[MAX_PATH];
//send "USER pUser /r/n"
sprintf( strBuffer, "USER %s/r/n", pUser);
nRet = SendCmdLine(strBuffer, strlen(strBuffer), &m_dwError);
if( nRet!=0 )
{
return FALSE;
}
nRet = ReadCmdResponse(&m_dwError);
if( nRet!=0 )
{
return FALSE;
}
if( m_fc!=3 )//331
{
return FALSE;
}
//send "PASS pPassword/r/n"
sprintf( strBuffer, "PASS %s/r/n", pPassword);
nRet = SendCmdLine(strBuffer, strlen(strBuffer), &m_dwError);
if( nRet!=0 )
{
return FALSE;
}
nRet = ReadCmdResponse(&m_dwError);
if( nRet!=0 )
{
return FALSE;
}
if( m_fc!=2 )//230
{
return FALSE;
}
m_dwError = 0;
return TRUE;
}
BOOL FTPClient::EstablishDataConnection(char* strRemoteFile)
{
strcpy( m_strRemoteFile, strRemoteFile);
char strBuffer[1025];
int nRet = 0;
int nCode = 0;
int nRead = 0;
//send "TYPE I/r/n".
strcpy( strBuffer, "TYPE I/r/n" );
nRet = SendCmdLine( strBuffer, strlen(strBuffer), &m_dwError );
if( nRet!=0 )
{
return FALSE;
}
nRet = ReadCmdResponse(&m_dwError);
if( nRet!=0 )
{
return FALSE;
}
if( m_fc!=2 )//200
{
return FALSE;
}
//create server socket and start to listen.
m_hSktSvr = CSocketInterface::CreateListenSocket(0, &m_dwError);
if( m_hSktSvr==INVALID_SOCKET )
{
return FALSE;
}
if( !CSocketInterface::Listen( m_hSktSvr, 5, &m_dwError) )
{
closesocket( m_hSktSvr );
m_hSktSvr = INVALID_SOCKET;
return FALSE;
}
//get server ip address and ip port, then send "PORT 192,168,80,68,0,21/r/n".
char strAddress[32];
int nPort = 0;
BYTE a,b,c,d;
if( !CSocketInterface::GetSocketName(m_hSktCtrl, strAddress, &nPort, &m_dwError) ) //m_hSktSvr
{
closesocket( m_hSktSvr );
m_hSktSvr = INVALID_SOCKET;
return FALSE;
}
//if( !CSocketInterface::GetSocketName(m_hSktSvr, strAddress, &nPort, &m_dwError) ) //m_hSktSvr
//{
// closesocket( m_hSktSvr );
// m_hSktSvr = INVALID_SOCKET;
// return FALSE;
//}
//{
// char sMsg[1024];
// sprintf(sMsg, "FTPClient Ftp server will connect to %s.", strAddress);
// OnLogError(0, sMsg);
//}
if( !CSocketInterface::IP2B4(strAddress, &a, &b, &c, &d) )
{
closesocket( m_hSktSvr );
m_hSktSvr = INVALID_SOCKET;
return FALSE;
}
if( !CSocketInterface::GetSocketName(m_hSktSvr, strAddress, &nPort, &m_dwError) ) //m_hSktSvr
{
closesocket( m_hSktSvr );
m_hSktSvr = INVALID_SOCKET;
return FALSE;
}
sprintf(strBuffer, "PORT %d,%d,%d,%d,%d,%d/r/n", a, b, c, d, nPort/256, nPort%256 );
nRet = SendCmdLine( strBuffer, strlen(strBuffer), &m_dwError);
if( nRet!=0 )
{
closesocket( m_hSktSvr );
m_hSktSvr = INVALID_SOCKET;
return FALSE;
}
nRet = ReadCmdResponse( &m_dwError );
if( nRet!=0 )
{
closesocket( m_hSktSvr );
m_hSktSvr = INVALID_SOCKET;
return FALSE;
}
if( m_fc!=2 )
{
closesocket( m_hSktSvr );
m_hSktSvr = INVALID_SOCKET;
return FALSE;
}
//send "RETR filename/r/n"
sprintf( strBuffer, "RETR %s/r/n", strRemoteFile);
nRet = SendCmdLine( strBuffer, strlen(strBuffer), &m_dwError );
if( nRet!=0 )
{
closesocket( m_hSktSvr );
m_hSktSvr = INVALID_SOCKET;
return FALSE;
}
nRet = ReadCmdResponse(&m_dwError);
if( nRet!=0 )
{
closesocket( m_hSktSvr );
m_hSktSvr = INVALID_SOCKET;
return FALSE;
}
if( m_fc!=1 )//150
{
closesocket( m_hSktSvr );
m_hSktSvr = INVALID_SOCKET;
return FALSE;
}
//accept connection from ftp server.
nRet = CSocketInterface::CheckRead(m_hSktSvr, 10000, &m_dwError);
if( nRet==SOCKET_ERROR || nRet==0 )
{
closesocket( m_hSktSvr );
m_hSktSvr = INVALID_SOCKET;
return FALSE;
}
else
{
m_hSktData = CSocketInterface::AcceptSocket( m_hSktSvr, &m_dwError);
if( m_hSktData==INVALID_SOCKET )
{
closesocket( m_hSktSvr );
m_hSktSvr = INVALID_SOCKET;
return FALSE;
}
}
return TRUE;
}
void FTPClient::CloseDataConnection()
{
if( m_hSktData!=INVALID_SOCKET )
{
closesocket( m_hSktData);
m_hSktData = INVALID_SOCKET;
}
if( m_hSktSvr!=INVALID_SOCKET )
{
closesocket( m_hSktSvr );
m_hSktSvr = INVALID_SOCKET;
}
}
void FTPClient::LogOffServer()
{
if( m_hSktCtrl!=INVALID_SOCKET )
{
SendCmdLine("QUIT/r/n", strlen("QUIT/r/n"), &m_dwError);
}
}
void FTPClient::CloseCtrlConnection()
{
if( m_hSktCtrl!=INVALID_SOCKET )
{
closesocket( m_hSktCtrl );
m_hSktCtrl = INVALID_SOCKET;
}
}
DWORD FTPClient::FunThread()
{
const DWORD BUFFERSIZE = 4096*20;
char* pBuffer = new char[BUFFERSIZE];
int nRet = 0;
DWORD dwError = 0;
m_llBytes = 0;
while( 1 )
{
//check if user want to cancel this operation.
if( WaitForSingleObject(m_hEvent, 0)==WAIT_OBJECT_0 )
{
break;
}
//check if there are some data to read.
nRet = CSocketInterface::CheckRead(m_hSktData, 500, &dwError);
//if error occurs.
if( nRet==SOCKET_ERROR )
{
char* pMsg = 0;
BOOL bRet = CSocketInterface::GetLastErrorDes(&pMsg, dwError);
if( bRet )
{
OnError(dwError, pMsg);
CSocketInterface::ReleaseMessage(pMsg);
}
else
{
OnError(dwError, "unknown error.");
}
break;
}
//if there are some data to read,just read them.
else if( nRet==1 )
{
int nRead = recv(m_hSktData, pBuffer, BUFFERSIZE, 0);
//if end of stream, we notify this to external system.
if( nRead==0 )
{
OnEndOfStream();
break;
}
//if data is successful to read, update bytes downloaded.
else if( nRead!=SOCKET_ERROR )
{
OnReceive(pBuffer, nRead);
m_llBytes += nRead;
}
//if error to read.
else
{
dwError = WSAGetLastError();
char* pMsg;
BOOL bRet = CSocketInterface::GetLastErrorDes(&pMsg, dwError);
if( bRet )
{
OnError(dwError, pMsg);
CSocketInterface::ReleaseMessage(pMsg);
}
else
{
OnError(dwError, "unknown error");
}
break;
}
}
//if time out to check. just continue
else
{
continue;
}
}
delete[] pBuffer;
ReadCmdResponse( &dwError );
return 0;
}
DWORD WINAPI FTPClient::EntryThread(LPVOID lParam)
{
FTPClient* pThis = (FTPClient *)lParam;
DWORD dwRet = pThis->FunThread();
return dwRet;
}
//@Function read command line until command line is read successfully, user cancel, or error occurs.
//@Param char* pBuffer: buffer to retrieve data.
//@Param int nLen: buffer length.
//@Param int* nCode: pointer to retrieve command response code such as 220, 150.
//@Param int* nLenRead: data length that is read, include '/r/n';
//@Param DWORD *dwError: pointer to retrieve the error code.
//Return 0 successful to receive one complete command line.
// 1 user cancels this operation.
// -1 error occurs while receiving data from ftp server.
int FTPClient::ReadCmdLine(char* pBuffer, int nLen, int* nCode, int* nLenRead, DWORD* dwError)
{
int nRetCheck = 0;
int nRetRead = 0;
int nPos = 0;
*nCode = 0;
*nLenRead = 0;
*dwError = 0;
while( 1 )
{
if( WaitForSingleObject( m_hEvent, 0)==WAIT_OBJECT_0 )
{
return 1;
}
nRetCheck = CSocketInterface::CheckRead(m_hSktCtrl, 500, dwError);
//if there are some data to read.
if( nRetCheck==1 )
{
nRetRead = recv(m_hSktCtrl, pBuffer+nPos, 1, 0);//return value are:SOCKET_ERROR, 0, 1
if(nRetRead!=1)
{
*dwError = WSAGetLastError();
return -1;
}
else
{
nPos++;
*nLenRead = *nLenRead + 1;
if( *(pBuffer+nPos-1)=='/n' )
{
*(pBuffer+nPos) = '/0';
*nCode = *pBuffer - 48;
//TRACE(pBuffer);
return 0;
}
}
}
//if timeout.
else if( nRetCheck==0 )
{
continue;
}
//we regard it is error.
else
{
return -1;
}
}
return 0;
}
//@Function read one complete cmd response command until it is successful to read, user cancel, or error occurs.
//@Param DWORD *dwError: pointer to retrieve the error code.
//Return 0 successful to receive one complete response.
// 1 user cancels this operation.
// -1 error occurs while receiving data from ftp server.
int FTPClient::ReadCmdResponse(DWORD* dwError)
{
int nRet = 0;
int nCode = 0;
int nLenRead = 0;
nRet = ReadCmdLine(m_pBuffer, 1024, &nCode, &nLenRead, dwError);
if( nRet!=0 )
{
return nRet;
}
//if it is single reply.
m_fc = nCode;
if( strlen(m_pBuffer)<6 || *(m_pBuffer+3)!='-' )
{
return 0;
}
int nMsg = atoi( m_pBuffer );
//if it is multiple replies.
while(1)
{
nRet = ReadCmdLine(m_pBuffer, 1024, &nCode, &nLenRead, dwError);
if( nRet!=0 )
{
return nRet;
}
if( strlen(m_pBuffer)>=6 && *(m_pBuffer+3)==' ' && atoi(m_pBuffer)==nMsg )
{
return 0;
}
}
return 0;
}
//@Function send complete data until all the data is sent, user cancels, or error occurs.
//@Param char* pBuffer: data to send. it must end with '/r/n'.
//@Param int nLen: data length, including '/r/n';
//@Param DWORD* dwError: pointer to retrieve error code.
//@Return 0 successful to send all the data to ftp server.
// 1 user cancel this operation.
// -1 error occurs while sending data.
int FTPClient::SendCmdLine(char* pBuffer, int nLen, DWORD* dwError)
{
int nPos = 0;
int nRet = 0;
*dwError = 0;
while( nPos<nLen )
{
if( WaitForSingleObject( m_hEvent, 0 )==WAIT_OBJECT_0 )
{
return 1;
}
nRet = send( m_hSktCtrl, pBuffer + nPos, nLen - nPos, 0);
if( nRet==SOCKET_ERROR )
{
*dwError = WSAGetLastError();
return -1;
}
nPos += nRet;
}
return 0;
}
- SocketAPI 实现FTPServer文件下载
- socketAPI
- python 实现 FTPServer 服务
- 利用Apache提供的ftp下载工具类下载ftpServer数据
- PHP实现文件下载
- [Servlet] 实现文件下载
- JSP实现文件下载
- jsp实现文件下载
- struts实现文件下载
- JSP实现文件下载
- Servlet实现文件下载
- servlet实现文件下载
- struts2实现文件下载
- PHP实现文件下载
- 如何实现文件下载
- PHP实现文件下载
- 实现文件下载功能
- java实现文件下载
- Asp.Net细节性问题技巧精萃
- Robbin关于App class loader的总结(zt)
- ADO.NET 2.0 功能一览
- 细说多态
- SetUp A Mysql Datasource
- SocketAPI 实现FTPServer文件下载
- 汽车配件管理系统分析报告
- Inside The C++ Object Model---构造函数语义学
- C语言学习系统的数据库设计(原创)
- 优秀程序员的两大要素:懒 + 笨
- 在Oracle运行操作系统命令
- 大道至简 Java 23种模式一点就通
- 男人25岁以前应该知道的
- Thinking in AJAX(二) —— 基于AJAX的WEB设计