近期有个项目,要从ftp上下载txt文件下来,因为txt文件有我这边项目所需要的报告,但是我在本机上运行却能从客户的ftp上能拉取下来(我的电脑为WIN10),但是到了线上的环境却下了。
开始的时候,我是觉得路径的问题,然后把取的路径更改为 strFtpDirTmp += _T("\\*.txt");
也就是如下的代码,最后在本机(WIN10)上能拉到ftp服务器的txt文件,但是到了线上的环境却不行了。实现下载的代码如下(单独开了个线程来下载):
static THREAD_RETURN __STDCALL ThreadGetRptFromFtp(void *arglist)
{
CZzxFxImpl* pThis = (CZzxFxImpl*)arglist;
if (NULL == pThis)
{
return (THREAD_RETURN)0;
}
CAdapter::InterlockedIncrement(&pThis->m_getFtpRptThreadCnt);
pThis->m_getRptThreadExitFlag = false;
pThis->g_pInetSession = NULL; //会话对象
pThis->g_pFtpConnection = NULL; //连接对象
//新建对话
pThis->g_pInetSession = new CInternetSession(AfxGetAppName(), 1, PRE_CONFIG_INTERNET_ACCESS);
try
{
//新建连接对象
pThis->g_pFtpConnection = pThis->g_pInetSession->GetFtpConnection(pThis->m_FtpAddr.c_str(), pThis->m_FtpUid.c_str(), pThis->m_FtpPwd.c_str());
}
catch (CInternetException *pEx)
{
TCHAR szError[1024];
CString strError = "";
if (pEx->GetErrorMessage(szError, 1024))
{
string strLogInfo = cstr::format("连接FTP服务器失败,失败原因 %s", szError);
CSmsTools::GetInstance().WriteLogMsg(strLogInfo.c_str(), strLogInfo.length(), CSmsTools::LOG_LEVEL_ERROR);
}
else
{
string strLogInfo = cstr::format("连接FTP服务器失败,失败原因:未知异常");
CSmsTools::GetInstance().WriteLogMsg(strLogInfo.c_str(), strLogInfo.length(), CSmsTools::LOG_LEVEL_ERROR);
}
pEx->Delete();
pThis->g_pFtpConnection = NULL;
return 0;
}
try
{
memset(pThis->m_szLocalPath, 0x0, sizeof(pThis->m_szLocalPath));
CAdapter::GetCurrentPath(pThis->m_szLocalPath, MAX_PATH);
strcat(pThis->m_szLocalPath, "LocalRptFile");
if (!CAdapter::PathFileExists(pThis->m_szLocalPath))
{
CAdapter::CreateDirectory(pThis->m_szLocalPath, 0);
}
//创建会话成功
while (!pThis->m_getRptThreadExitFlag)
{
//设置远程服务端状态报告获取目录
BOOL bSetDir = pThis->g_pFtpConnection->SetCurrentDirectory(pThis->m_FtpRptDir.c_str());
CFtpFileFind RemoteFinder(pThis->g_pFtpConnection); //远程查找文件对象
// pRemoteFinder = new CFtpFileFind(g_pFtpConnection);
CString strFtpDirTmp = pThis->m_FtpRptDir.c_str();
//strFtpDirTmp += "*";
strFtpDirTmp += _T("\\*.txt");
BOOL bFindFile = RemoteFinder.FindFile(strFtpDirTmp); //获取目录下所有的文件
//BOOL bFindFile = RemoteFinder.FindFile(_T("*")); //获取目录下所有的文件
int nFileCnt = 0;
while (bFindFile)
{
bFindFile = RemoteFinder.FindNextFile();
nFileCnt++;
CString strFile = RemoteFinder.GetFileName();
CString strLoaclFilePath = "";
strLoaclFilePath.Format("%s\\%s", pThis->m_szLocalPath, strFile); //下载到本地文件夹的全路径
CString strErrMsgTmp = "";
BOOL bGetRlt = pThis->g_pFtpConnection->GetFile(strFile, strLoaclFilePath, FALSE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_BINARY); //下载
if (bGetRlt) //下载成功
{
BOOL bRemove = pThis->g_pFtpConnection->Remove(strFile); //删除
if (!bRemove) //删除失败
{
string strLogInfo = cstr::format("文件:%s 删除失败,失败代码:%d", strFile, GetLastError());
CSmsTools::GetInstance().WriteLogMsg(strLogInfo.c_str(), strLogInfo.length(), CSmsTools::LOG_LEVEL_ERROR);
break;
}
}
else //下载失败
{
string strLogInfo = cstr::format("文件:%s 下载失败,失败代码:%d", strFile, GetLastError());
CSmsTools::GetInstance().WriteLogMsg(strLogInfo.c_str(), strLogInfo.length(), CSmsTools::LOG_LEVEL_ERROR);
continue;
}
//解析本地文件夹中状态报告文件
pThis->ParseLocalDirectoryRptFile(strLoaclFilePath);
Sleep(100);
}
RemoteFinder.Close();
Sleep(1000 * 5);
}
}
catch (...) //GetErrorMessage
{
string strLogInfo = cstr::format("下载异常");
CSmsTools::GetInstance().WriteLogMsg(strLogInfo.c_str(), strLogInfo.length(), CSmsTools::LOG_LEVEL_ERROR);
}
CAdapter::InterlockedDecrement(&pThis->m_getFtpRptThreadCnt);
return 0;
}
最后到了线上再执行,还是从客户的FTP服务器上拉取不了txt文件下来,那就是把 strFtpDirTmp += "*"; 改成 strFtpDirTmp += _T("\\*.txt"); 是无效的了。
然后我想想了,这里没有几个函数 ,也都是成熟悉的东西(ftp这协议已经很久了)。最后把问题定在了线上环境的系统 上,因为线上的环境是Windows server 2012,最后找了资料,把GetFtpConnection 的后面再加上2个参数,这样就能正常运行了,路径也换为了 strFtpDirTmp += "*"; 代码更改后如下:
static THREAD_RETURN __STDCALL ThreadGetRptFromFtp(void *arglist)
{
CZzxFxImpl* pThis = (CZzxFxImpl*)arglist;
if (NULL == pThis)
{
return (THREAD_RETURN)0;
}
CAdapter::InterlockedIncrement(&pThis->m_getFtpRptThreadCnt);
pThis->m_getRptThreadExitFlag = false;
pThis->g_pInetSession = NULL; //会话对象
pThis->g_pFtpConnection = NULL; //连接对象
//新建对话
pThis->g_pInetSession = new CInternetSession(AfxGetAppName(), 1, PRE_CONFIG_INTERNET_ACCESS);
try
{
//新建连接对象
pThis->g_pFtpConnection = pThis->g_pInetSession->GetFtpConnection(pThis->m_FtpAddr.c_str(), pThis->m_FtpUid.c_str(), pThis->m_FtpPwd.c_str(),21,TRUE);
}
catch (CInternetException *pEx)
{
TCHAR szError[1024];
CString strError = "";
if (pEx->GetErrorMessage(szError, 1024))
{
string strLogInfo = cstr::format("连接FTP服务器失败,失败原因 %s", szError);
CSmsTools::GetInstance().WriteLogMsg(strLogInfo.c_str(), strLogInfo.length(), CSmsTools::LOG_LEVEL_ERROR);
}
else
{
string strLogInfo = cstr::format("连接FTP服务器失败,失败原因:未知异常");
CSmsTools::GetInstance().WriteLogMsg(strLogInfo.c_str(), strLogInfo.length(), CSmsTools::LOG_LEVEL_ERROR);
}
pEx->Delete();
pThis->g_pFtpConnection = NULL;
return 0;
}
try
{
memset(pThis->m_szLocalPath, 0x0, sizeof(pThis->m_szLocalPath));
CAdapter::GetCurrentPath(pThis->m_szLocalPath, MAX_PATH);
strcat(pThis->m_szLocalPath, "LocalRptFile");
if (!CAdapter::PathFileExists(pThis->m_szLocalPath))
{
CAdapter::CreateDirectory(pThis->m_szLocalPath, 0);
}
//创建会话成功
while (!pThis->m_getRptThreadExitFlag)
{
//设置远程服务端状态报告获取目录
BOOL bSetDir = pThis->g_pFtpConnection->SetCurrentDirectory(pThis->m_FtpRptDir.c_str());
CFtpFileFind RemoteFinder(pThis->g_pFtpConnection); //远程查找文件对象
// pRemoteFinder = new CFtpFileFind(g_pFtpConnection);
CString strFtpDirTmp = pThis->m_FtpRptDir.c_str();
strFtpDirTmp += "*";
BOOL bFindFile = RemoteFinder.FindFile(strFtpDirTmp); //获取目录下所有的文件
//BOOL bFindFile = RemoteFinder.FindFile(_T("*")); //获取目录下所有的文件
int nFileCnt = 0;
while (bFindFile)
{
bFindFile = RemoteFinder.FindNextFile();
nFileCnt++;
CString strFile = RemoteFinder.GetFileName();
CString strLoaclFilePath = "";
strLoaclFilePath.Format("%s\\%s", pThis->m_szLocalPath, strFile); //下载到本地文件夹的全路径
CString strErrMsgTmp = "";
BOOL bGetRlt = pThis->g_pFtpConnection->GetFile(strFile, strLoaclFilePath, FALSE, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_BINARY); //下载
if (bGetRlt) //下载成功
{
BOOL bRemove = pThis->g_pFtpConnection->Remove(strFile); //删除
if (!bRemove) //删除失败
{
string strLogInfo = cstr::format("文件:%s 删除失败,失败代码:%d", strFile, GetLastError());
CSmsTools::GetInstance().WriteLogMsg(strLogInfo.c_str(), strLogInfo.length(), CSmsTools::LOG_LEVEL_ERROR);
break;
}
}
else //下载失败
{
string strLogInfo = cstr::format("文件:%s 下载失败,失败代码:%d", strFile, GetLastError());
CSmsTools::GetInstance().WriteLogMsg(strLogInfo.c_str(), strLogInfo.length(), CSmsTools::LOG_LEVEL_ERROR);
continue;
}
//解析本地文件夹中状态报告文件
pThis->ParseLocalDirectoryRptFile(strLoaclFilePath);
Sleep(100);
}
RemoteFinder.Close();
Sleep(1000 * 5);
}
}
catch (...) //GetErrorMessage
{
string strLogInfo = cstr::format("下载异常");
CSmsTools::GetInstance().WriteLogMsg(strLogInfo.c_str(), strLogInfo.length(), CSmsTools::LOG_LEVEL_ERROR);
}
CAdapter::InterlockedDecrement(&pThis->m_getFtpRptThreadCnt);
return 0;
}
也就是这句后面的2个参数起了重要作用
pThis->g_pFtpConnection = pThis->g_pInetSession->GetFtpConnection(pThis->m_FtpAddr.c_str(), pThis->m_FtpUid.c_str(), pThis->m_FtpPwd.c_str(),21,TRUE);
具体的可看下FTP的被动连接和主动连接。
接着再把程序拿到线上跑,就能从客户的FTP服务器上拉取txt文件的了。
注:最后一个问题,就是本机上我从ftp下载很快,但是到了线上生产环境很慢的话,那就是线上的网线的问题的了,这时候就要和客户的ftp所在的IP(也就是接入的运营商,移动,电信搞清楚)。因为线上的环境数据 出去有几个运营商(移动,联通,电信),要能从客户这里快速下载文件的话,就必须把这跑的程序所在的线上机子出去的IP单独为运营商移动的(因为客户的IP对应也是移动这块的)。。。