该demo主要是封装了MS的Wininet.dll,方便FTP文件上传,
解决了在XP系统下面InternetConnect()接口在FTP服务器不可用,连接超时严重,且不可控的问题。
该demo在WIN7 64 和XP 32 自测通过。
完整工程源码下载地址:
ftp.cpp
解决了在XP系统下面InternetConnect()接口在FTP服务器不可用,连接超时严重,且不可控的问题。
该demo在WIN7 64 和XP 32 自测通过。
完整工程源码下载地址:
http://download.csdn.net/detail/friendan/8068905
------------------------------------------------------------------------------------------
主要代码如下:
ftp.h
#pragma once
#pragma warning(disable:4995)
#include <strsafe.h>
#include <process.h>
#include <Wininet.h>
#pragma comment(lib, "Wininet.lib")
#include <vector>
#include <string>
using std::vector;
using std::string;
using std::wstring;
#ifdef _UNICODE
#define tstring wstring
#else
#define tstring string
#endif
// FTP配置参数
typedef struct tagFtpParam
{
int iFtpEnable; // 1开启FTP上传,0是关闭FTP上传
TCHAR szFtpServerIp[32]; // FTP服务器IP
TCHAR szFtpUser[20]; // FTP登陆账号
TCHAR szFtpPass[30]; // FTP登陆密码
int iFtpPort; // FTP服务端口, 默认为21
int iFtpIsPassive; // 1表示FTP为被动模式,0表示FTP为主动模式
TCHAR szFtpUploadDir[30]; // FTP上传目录,如 /test
tagFtpParam()
{
iFtpEnable = 0;
ZeroMemory(szFtpServerIp, sizeof(szFtpServerIp));
ZeroMemory(szFtpUser, sizeof(szFtpUser));
ZeroMemory(szFtpPass, sizeof(szFtpPass));
iFtpPort = 21;
iFtpIsPassive = 1;
ZeroMemory(szFtpUploadDir, sizeof(szFtpUploadDir));
StringCbCopy(szFtpUploadDir, sizeof(szFtpUploadDir), _T("/test"));
}
}FtpParam;
class CFtp
{
public:
CFtp(void);
~CFtp(void);
/**
@name UploadDiskFile
@brief 往FTP上传磁盘文件
@param[in] LPCTSTR pszFilePath, 磁盘文件路径
@param[in] LPCTSTR pszUploadDir, 上传到的FTP目录,以斜杠/开头,如 /test
@return 成功true,失败false
*/
bool UploadDiskFile(LPCTSTR pszFilePath, LPCTSTR pszUploadDir);
/**
@name UploadMemoryFile
@brief 往FTP上传内存文件
@param[in] PBYTE pbFile, 内存文件缓冲区指针
@param[in] int iFileLen, 内存文件长度
@param[in] LPCTSTR pszFileName, 保存文件名称
@param[in] LPCTSTR pszUploadDir, 上传到的FTP目录,以斜杠开头,如/test
@return bool
*/
bool UploadMemoryFile(PBYTE pbFile, int iFileLen, LPCTSTR pszFileName, LPCTSTR pszUploadDir);
/**
@name IsFileExists
@brief 判断文件是否存在
@param[in]: LPCTSTR pszFilePath 文件路径
@return 文件存在返回true, 否则返回false
*/
bool IsFileExists(LPCTSTR pszFilePath);
public:
FtpParam m_ftpParam; // ftp配置参数
private:
/**
@name ConnFtpServer
@brief 连接FTP服务器
@param[in] void
@return 成功true,失败false
*/
bool ConnFtpServer(void);
// 连接FTP线程代理
static unsigned int _stdcall ThreadConnFtpProxy(PVOID pParam)
{
CFtp *pThis = (CFtp*)pParam;
if (pThis != NULL)
{
pThis->ThreadConnFtp();
}
return 0;
}
/**
@name ThreadConnFtp
@brief 连接FTP线程
@param[in] void
@return bool
*/
bool ThreadConnFtp(void);
private:
HINTERNET m_hInetOpen; // 网络打开句柄
HINTERNET m_hInetConn; // 网络连接句柄
HANDLE m_hConnThread; // 连接线程句柄
};
ftp.cpp
#include "StdAfx.h"
#include "Ftp.h"
CFtp::CFtp(void)
{
m_hInetOpen = NULL;
m_hInetConn = NULL;
m_hConnThread = NULL;
}
CFtp::~CFtp(void)
{
if (m_hInetOpen != NULL)
{
InternetCloseHandle(m_hInetOpen);
m_hInetOpen = NULL;
}
if (m_hInetConn != NULL)
{
InternetCloseHandle(m_hInetConn);
m_hInetConn = NULL;
}
if (m_hConnThread != NULL)
{
WaitForSingleObject (m_hConnThread, 1000*30);
CloseHandle(m_hConnThread);
m_hConnThread = NULL;
}
}
/**
@name ConnFtpServer
@brief 连接FTP服务器
@param[in] void
@return 成功true,失败false
*/
bool CFtp::ConnFtpServer(void)
{
WaitForSingleObject(m_hConnThread, 1000*60);
m_hConnThread = (HANDLE)_beginthreadex(NULL, 0, ThreadConnFtpProxy, this, 0, NULL);
DWORD dwTimeout = 1000*3; // 连接FTP超时时间
if (WaitForSingleObject (m_hConnThread, dwTimeout ) == WAIT_TIMEOUT)
{
TerminateThread(m_hConnThread, -1);
if (m_hConnThread != NULL)
{
CloseHandle(m_hConnThread);
m_hConnThread = NULL;
}
return false;
}
if (m_hConnThread != NULL)
{
CloseHandle(m_hConnThread);
m_hConnThread = NULL;
}
return true;
}
/**
@name UploadDiskFile
@brief 往FTP上传磁盘文件
@param[in] LPCTSTR pszFilePath, 磁盘文件路径
@param[in] LPCTSTR pszUploadDir, 上传到的FTP目录,以斜杠/开头,如 /test
@return 成功true,失败false
*/
bool CFtp::UploadDiskFile(LPCTSTR pszFilePath, LPCTSTR pszUploadDir)
{
if (pszFilePath == NULL || m_ftpParam.iFtpEnable == 0)
{
return false;
}
if (!IsFileExists(pszFilePath))
{
return false;
}
if (!ConnFtpServer())
{
return false;
}
// 解析上传目录
tstring strUploadDir;
if (_tcslen(pszUploadDir) > 0)
{
strUploadDir = pszUploadDir;
}
else
{
strUploadDir = m_ftpParam.szFtpUploadDir; // 默认上传目录
}
if (strUploadDir.size() <= 0)
{
strUploadDir = _T("/result/");
}
strUploadDir[0] = _T('/'); // 确保以斜杠/开头
if (strUploadDir[strUploadDir.size() - 1] != _T('/'))
{
strUploadDir += _T('/'); // 确保以斜杠/结尾
}
// 确保上传目录存在 strUploadDir = /test
tstring strCurDir = _T("/");
FtpSetCurrentDirectory(m_hInetConn, strCurDir.c_str());
tstring strTmpDir = strUploadDir;
bool bRet = true;
while(strTmpDir.find(_T('/')) != tstring::npos && bRet)
{
size_t iStart = strTmpDir.find(_T('/'));
strTmpDir.erase(iStart, 1);
size_t iEnd = strTmpDir.find(_T('/'));
tstring strDir = strTmpDir.substr(iStart, iEnd - iStart);
bRet = FtpCreateDirectory(m_hInetConn, strDir.c_str()) > 0 ? true : false;
strCurDir += strDir;
strCurDir += _T('/');
FtpSetCurrentDirectory(m_hInetConn, strCurDir.c_str());
if (iEnd == strTmpDir.size() - 1)
{
break;
}
}
FtpSetCurrentDirectory(m_hInetConn, strUploadDir.c_str());
// 解析上传磁盘文件名称,如 D:\test.txt
tstring strDiskFilePath = pszFilePath;
tstring strDiskFileName;
size_t iIndex = strDiskFilePath.rfind('\\');
if (iIndex != tstring::npos && iIndex >= 0)
{
strDiskFileName = strDiskFilePath.substr(iIndex+1, strDiskFilePath.size() - 1);
}
// 上传磁盘文件
tstring strTmpFile = strUploadDir;
strTmpFile += strDiskFileName;
bRet = FtpPutFile(m_hInetConn, pszFilePath, strTmpFile.c_str(), FTP_TRANSFER_TYPE_BINARY, NULL) > 0 ? true : false;
// 获取错误信息
if (!bRet)
{
DWORD iErrorCode = GetLastError();
TCHAR szErr[1024] = {0};
DWORD dwLen = 1024;
InternetGetLastResponseInfo(&iErrorCode, szErr, &dwLen);
OutputDebugString(szErr);
}
return bRet;
}
/**
@name UploadMemoryFile
@brief 往FTP上传内存文件
@param[in] PBYTE pbFile, 内存文件缓冲区指针
@param[in] int iFileLen, 内存文件长度
@param[in] LPCTSTR pszFileName, 保存文件名称
@param[in] LPCTSTR pszUploadDir, 上传到的FTP目录,以斜杠开头,如/test
@return bool
*/
bool CFtp::UploadMemoryFile(PBYTE pbFile, int iFileLen, LPCTSTR pszFileName, LPCTSTR pszUploadDir)
{
if (pbFile == NULL || iFileLen < 1 || m_ftpParam.iFtpEnable == 0)
{
return false;
}
if (pszFileName == NULL)
{
return false;
}
if (!ConnFtpServer())
{
return false;
}
// 解析上传目录
tstring strUploadDir;
if (_tcslen(pszUploadDir) > 0)
{
strUploadDir = pszUploadDir;
}
else
{
strUploadDir = m_ftpParam.szFtpUploadDir; // 默认上传目录
}
if (strUploadDir.size() <= 0)
{
strUploadDir = _T("/result/");
}
strUploadDir[0] = _T('/'); // 确保以斜杠/开头
if (strUploadDir[strUploadDir.size() - 1] != _T('/'))
{
strUploadDir += _T('/'); // 确保以斜杠/结尾
}
// 确保上传目录存在 strUploadDir = /test
tstring strCurDir = _T("/");
FtpSetCurrentDirectory(m_hInetConn, strCurDir.c_str());
tstring strTmpDir = strUploadDir;
bool bRet = true;
while(strTmpDir.find(_T('/')) != tstring::npos && bRet)
{
size_t iStart = strTmpDir.find(_T('/'));
strTmpDir.erase(iStart, 1);
size_t iEnd = strTmpDir.find(_T('/'));
tstring strDir = strTmpDir.substr(iStart, iEnd - iStart);
bRet = FtpCreateDirectory(m_hInetConn, strDir.c_str()) > 0 ? true : false;
strCurDir += strDir;
strCurDir += _T('/');
FtpSetCurrentDirectory(m_hInetConn, strCurDir.c_str());
if (iEnd == strTmpDir.size() - 1)
{
break;
}
}
FtpSetCurrentDirectory(m_hInetConn, strUploadDir.c_str());
// 解析上传内存文件名称
tstring strMemoryFileName = pszFileName;
// 上传内存文件
HINTERNET hFtpFile = NULL;
tstring strTmpFile = strUploadDir;
strTmpFile += strMemoryFileName;
hFtpFile = FtpOpenFile(m_hInetConn, strTmpFile.c_str(), GENERIC_WRITE, INTERNET_FLAG_TRANSFER_BINARY, NULL);
if (hFtpFile != NULL)
{
DWORD dwWrite = 0;
bRet = InternetWriteFile(hFtpFile, pbFile, iFileLen, &dwWrite) > 0 ? true : false;
}
// 获取错误信息
if (!bRet)
{
DWORD iErrorCode = GetLastError();
TCHAR szErr[1024] = {0};
DWORD dwLen = 1024;
InternetGetLastResponseInfo(&iErrorCode, szErr, &dwLen);
OutputDebugString(szErr);
}
// 释放内存
if (hFtpFile != NULL)
{
InternetCloseHandle(hFtpFile);
hFtpFile = NULL;
}
return bRet;
}
/**
@name IsFileExists
@brief 判断文件是否存在
@param[in]: LPCTSTR pszFilePath 文件路径
@return 文件存在返回true, 否则返回false
*/
bool CFtp::IsFileExists(LPCTSTR pszFilePath)
{
if (pszFilePath == NULL)
{
return false;
}
HANDLE hRet = CreateFile(pszFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
bool bRet = false;
if (hRet != INVALID_HANDLE_VALUE ) // 文件存在
{
bRet = true;
}
CloseHandle(hRet);
return bRet;
}
/**
@name ThreadConnFtp
@brief 连接FTP线程
@param[in] void
@return bool
*/
bool CFtp::ThreadConnFtp(void)
{
if (m_hInetOpen != NULL)
{
InternetCloseHandle(m_hInetOpen);
m_hInetOpen = NULL;
}
if (m_hInetConn != NULL)
{
InternetCloseHandle(m_hInetConn);
m_hInetConn = NULL;
}
// 连接FTP 服务器
//HINTERNET hInetOpen = InternetOpen(_T("CN"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, INTERNET_FLAG_ASYNC); // 异步
m_hInetOpen = InternetOpen(_T("CN"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); // 同步
if (m_hInetOpen == NULL)
{
return false;
}
DWORD dwFlags = 0;
if(m_ftpParam.iFtpIsPassive == 1)
{
dwFlags = INTERNET_FLAG_PASSIVE;
}
//DWORD dwTimeOut = 1000*3; // 超时值,经测试在WIN7有效,在XP无效,现已改成由线程控制
//InternetSetOption(m_hInetOpen, INTERNET_OPTION_CONNECT_TIMEOUT, &dwTimeOut, sizeof(dwTimeOut));
m_hInetConn = InternetConnect(m_hInetOpen,
m_ftpParam.szFtpServerIp,
m_ftpParam.iFtpPort,
m_ftpParam.szFtpUser,
m_ftpParam.szFtpPass,
INTERNET_SERVICE_FTP,
dwFlags,
NULL);
if (m_hInetConn == NULL)
{
return false;
}
return true;
}