|
|
Affter connect successfully to a FtpServer:
FtpSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); // FtpSocket is a Global Variable.
connect (FtpSocket, ...);
I tried to put a file to FtpServer by call the following put function:
int CFtp::put(char* szLocalFilename, char* szRemoteFilename)
{
// only if connected
if(!isConnected)
return FTP_ERROR_NOTCONNECTED;
// make sure local file exists
std::ifstream ifsLocalFile;
ifsLocalFile.open(szLocalFilename, std::ios_base::in | std::ios_base::binary);
if(!ifsLocalFile)
return FTP_ERROR_LOCALFILENOTFOUND;
// make sure remote path exists
std::string sPath = szRemoteFilename;
std::string sFilename; // we will do this later
std::basic_string <char>::size_type pos_first = sPath.find('/');
std::basic_string <char>::size_type pos_last = sPath.find_last_of('/');
std::string recvstring;
char recvbuffer[RECEIVE_BUFFER_SIZE];
char buffer[200];
int recvbytes;
if(pos_first==-1) // remote file contains path information
{
// no path information, so assume that this is the pure filename
sFilename = sPath;
} else {
// isolate the filename and path substring
sFilename = sPath.substr(pos_last+1,sPath.length());
if(pos_first==pos_last) // tricky part, this is a relativ path so watch out!
sPath = sPath.substr(0, pos_last+1);
else
sPath = sPath.substr(pos_first, pos_last+1);
// now try to change into this directory
sprintf(buffer, "CWD %s\n", sPath.c_str());
send(ftpSocket,buffer,static_cast<int>(strlen(buffer)),0);
if(recvStatus(ftpSocket,"250")==FTP_ERROR_FAILED)
return FTP_ERROR_REMOTEPATHNOTFOUND;
}
// paths are ok. lets switch to binary mode to be on the safe side
sprintf(buffer, "%s", "TYPE I\n");
send(ftpSocket,buffer,static_cast<int>(strlen(buffer)),0);
if(recvStatus(ftpSocket,"200")==FTP_ERROR_FAILED)
return FTP_ERROR_FAILEDTYPEI;
// now lets switch to PASV mode
sprintf(buffer, "%s", "PASV\n");
send(ftpSocket,buffer,static_cast<int>(strlen(buffer)),0);
recvbytes=recv(ftpSocket,recvbuffer,RECEIVE_BUFFER_SIZE,0);
recvstring.assign(recvbuffer,recvbytes);
if(recvstring.substr(0,3)!="227") // PASV failed
return FTP_ERROR_REMOTEPASVFAILED;
// status code 227: Entering passive mode.
// this needs to be parsed for the ip/port data channel data
// lets make a seperate scope for this task
SOCKADDR_IN server_pasv;
{
server_pasv.sin_family = AF_INET;
// lets strip the the important things from the string
std::basic_string <char>::size_type pos_find = recvstring.find('(');
recvstring = recvstring.substr(pos_find+1,recvstring.find(')')-pos_find-1);
// parse the ip into SockAddr... well this is a dirty pointer hell isnt it?
for(int i=0;i<4;i++)
{
pos_find = recvstring.find(',');
sscanf(recvstring.substr(0,pos_find).c_str(), "%d", &server_pasv.sin_addr.S_un.S_un_b.s_b1+i);
recvstring.erase(0,pos_find+1);
}
// parse the port into SockAddr
int portbyte1, portbyte2;
pos_find = recvstring.find(',');
sscanf(recvstring.substr(0,pos_find).c_str(), "%d", &portbyte1);
recvstring.erase(0,pos_find+1);
portbyte1 = portbyte1 * 256;
pos_find = recvstring.find(',');
sscanf(recvstring.substr(0,pos_find).c_str(), "%d", &portbyte2);
server_pasv.sin_port = htons(portbyte1+portbyte2);
}
// create pasvSocket
pasvSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if(pasvSocket==INVALID_SOCKET)
return FTP_ERROR_PASVSOCKET;
// sync the information with the PASV socket and open the PASV data connection
if(::connect(pasvSocket,reinterpret_cast<struct sockaddr*="">(&server_pasv),sizeof(server_pasv))==SOCKET_ERROR)
{
closesocket(pasvSocket);
return FTP_ERROR_LOCALPASVFAILED;
}
// this is put, not get... so we dont need to check if data is send through this
// instead we need to announce on the ftpSocket that we want to store a file
// all commands on ftpSocket will only work after you established the pasvSocket
// otherwise your commands will be buffered till sunrise. but we took care of it already.
// remember? we already CWD'ed to the directory, so we only need the filename
/*********************************************************/
/* My question is here */
/*********************************************************/
sprintf(buffer, "STOR %s\n", sFilename.c_str());
send(ftpSocket,buffer,static_cast<int>(strlen(buffer)),0);
if(recvStatus(ftpSocket,"150")==FTP_ERROR_FAILED)
return FTP_ERROR_STORFAILED;
char sendbuffer[SEND_BUFFER_SIZE];
while(!ifsLocalFile.eof())
{
ifsLocalFile.read(sendbuffer,SEND_BUFFER_SIZE);
send(pasvSocket,sendbuffer,ifsLocalFile.gcount(),0);
}
/*************************************************************/
/* Affter "STOR" command was sent, replly code is */
/* 125 Data connection already open; tranfer starting */
/* but my file was not STORE on Server */
/*Does "while loop" not work ? I don't know what is the reason*/
/*************************************************************/
// be sure to close the pasv port! otherwise the transfer will not be finished
closesocket(pasvSocket);
if(recvStatus(ftpSocket,"226")==FTP_ERROR_FAILED)
return FTP_ERROR_TRANSFERFAILED;
// and finaly close the file
ifsLocalFile.close();
return FTP_OK;
}
Sincerely
Thangnvhl
|
|
|
|
|
I had solved above error but when i exit my program, the temp file which i save on server was lost, too. So i can't resume upload that broken file. How can i solve this problem? Could u show me?
Sincerely
Thangnvhl
|
|
|
|
|
I had solved above error but when i exit my program, the temp file which i save on server was lost, too. So i can't resume upload that broken file. How can i solve this problem? Could u show me?
Sincerely
Thangnvhl
|
|
|
|
|
I use a freeware FTPServer based on Cool FTP.
For upload resume, the REST command does nothing for me.
I use the APPE command and this work very well. With the REST command, the file was resumed but corrupted. With APPE, the file is resumed and readable.
I test this solution with a FTP server daemon on my SUN server and it works perfect.
Hope that helps.
|
|
|
|
|
Hey thanks a lot for this article also the comments here, i was able to get resume upload for serv-u work using the example given above in the comments section however for the "ABOR" and "PASV" calls was unneccessary because wininet actually drops the ftp connection and gives the error 12030, so this is what i used: std::string command="REST "+ (string)pszOffset+"\r\nSTOR "+remote_filename+ "\r\n";
I simply use the handle this call returns from ftpcommand and continue uploading the file using InternetWriteFile call. I hope this helps someone out there just wanted to share
Oh i dunno why but in some cases i did notice a Sleep(250) helped write after the FTPCommand call try this if you are getting 12111 during InternetWriteFile
|
|
|
|
|
I use rest command,but use "rest 100" or "rest 0",get same
result.I rework your program,but i get same result regardless with "rest 100" or "rest 0".
my program :
bool CPauseResumeDemoDlg::StartDownloadingHardCodedFile()
{
GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);
DWORD dwPacketSize =5;
DWORD dwSize, dwToRead = dwPacketSize * 1024;
PBYTE pBuffer = new BYTE[dwPacketSize * 1024];
double dFileSize = 352256;
double dOffsetToSeek =0;
HINTERNET hConnect = NULL;
HINTERNET hOpen = NULL;
HINTERNET hOpenFile = NULL;
BOOL bRet = FALSE;
BOOL bInComplete = FALSE;
INTERNET_PORT nServerPort =21;
FILE * pFile = NULL;
string strTmpFileName = "Temp_find-ls.txt.gz";
string strFileNameAtLocalMachine= "find-ls.txt.gz";
string strFileNameAtServer= "/s.txt";
CString strStaus;
double nTripsToServerCnt;
int nTotalSpan = 100;
DWORD dwBytesWrrittenToFile =0;
nTripsToServerCnt = ceil(dFileSize / ((NKBYTE * 1024)*1.0));
if(nTripsToServerCnt ==0)
nTripsToServerCnt =1;
while(nTripsToServerCnt > nTotalSpan)
{
nTotalSpan *= 10;
}
DeleteFile(strFileNameAtLocalMachine.c_str());
m_ProgressCtl.SetRange(0,nTotalSpan);
//m_ProgressCtl.SetPos(1);
strStaus.Format("Initializing WinInet..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
hOpen = InternetOpen("PauseResumeDemo",INTERNET_OPEN_TYPE_PRECONFIG ,NULL, NULL, NULL);
if(!hOpen)
{
return false;
}
DWORD dwContext = 123;
strStaus.Format("Connecting to server..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
if ( !(hConnect = InternetConnect( hOpen, "localhost" , nServerPort, NULL, NULL, INTERNET_SERVICE_FTP, 0 , 0) ) )
{
CString strMsg;
string strReposeFromServer;
GetLastResponse(strReposeFromServer);
strMsg.Format("Error:%d\nDescription:%s", GetLastError(), strReposeFromServer.c_str());
AfxMessageBox(strMsg, MB_OK);
return false;
}
strStaus.Format("Finding out if this server supoprts Pause & Resume..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
if(FindPauseResumeSupported(hConnect))
{
strStaus.Format("Pause & Resume Supported..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
}
else
{
strStaus.Format("Pause & Resume not Supported..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
}
double dCurrentFileSize;
if(IfLocalFileExist(strTmpFileName.c_str(), &dCurrentFileSize))
{
dOffsetToSeek = dCurrentFileSize;
}
dOffsetToSeek=40;
if(dOffsetToSeek >0)
{
strStaus.Format("Sending REST...");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
//Seek to the file first
char pszOffset[30];
HINTERNET hResponse;
ltoa(dOffsetToSeek, pszOffset, 10);
//sprintf(pszOffset,"%ld", dOffsetToSeek);
string strSeekOffsetCMD = "REST " + (string)pszOffset;
bRet =FtpCommand(hConnect, // WinInet Connection handle
FALSE, // No, I don't expect a response
FTP_TRANSFER_TYPE_BINARY, // I'm receiving ASCII
"REST 6000",//strSeekOffsetCMD.c_str(), // This is the FTP command I am passing
0, // No context needed
&hResponse); // The handle to read the response
if (!bRet)
{
CString strMsg;
strMsg.Format("Error:%d", GetLastError());
AfxMessageBox(strMsg, MB_OK);
}
}
hOpenFile = ::FtpOpenFile(hConnect,strFileNameAtServer.c_str(), GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 1);
// DWORD dd=InternetSetFilePointer(hOpenFile,100,NULL,FILE_BEGIN,0);
if(hOpenFile == NULL)
{
CString strMsg;
string strReposeFromServer;
GetLastResponse(strReposeFromServer);
strMsg.Format("Error:%d\nDescription:%s", GetLastError(), strReposeFromServer.c_str());
AfxMessageBox(strMsg, MB_OK);
return false;
}
if ( !(pFile = fopen (strTmpFileName.c_str(), "ab" ) ) )
{
CString strMsg;
strMsg.Format("Error:%d", GetLastError());
AfxMessageBox(strMsg, MB_OK);
return false;
}
if(dOffsetToSeek >=0)
{
strStaus.Format("Seeking to local file...");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
int n = fseek(pFile, dOffsetToSeek, SEEK_SET);
}
dwBytesWrrittenToFile = dOffsetToSeek;
GetDlgItem(IDC_BUTTON2)->EnableWindow(TRUE);
do
{
PUMPMESSAGE();
//Intentional delay so that user get chance to hit stop button
Sleep(100);
strStaus.Format("Sending RETRIVE..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
if(m_bStopped)
{
strStaus.Format("Stopped..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
AfxMessageBox("Download aborted\nThere is an incomplete temp file 'Temp_find-ls.txt.gz' at current directory. Don't delete it just check it out. It has useful data downloaded so far...\nOnce you are done click Start again, now download will start from exact location where it left off");
m_bStopped = FALSE;
bInComplete = TRUE;
GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);
break;
}
if (!InternetReadFile (hOpenFile, (LPVOID)pBuffer, dwToRead, &dwSize) )
{
fclose (pFile);
CString strMsg;
string strReposeFromServer;
GetLastResponse(strReposeFromServer);
strMsg.Format("Error:%d\nDescription:%s", GetLastError(), strReposeFromServer.c_str());
AfxMessageBox(strMsg, MB_OK);
return false;
}
if (!dwSize)
{
m_ProgressCtl.SetPos(100);
CString strTmpPercentage;
strTmpPercentage.Format("Percentage Completed:%d%%", 100);
GetDlgItem(IDC_STATIC_PERCENTAGE)->SetWindowText(strTmpPercentage);
break; // Condition of dwSize=0 indicate EOF. Stop.
}
else
{
fwrite(pBuffer, sizeof (char), dwSize , pFile);
Sleep(2000);
dwBytesWrrittenToFile = dwBytesWrrittenToFile + dwSize;
int nPercentageComplete = (int)floor(((dwBytesWrrittenToFile) * 100)/dFileSize);
CString strTmpPercentage;
strTmpPercentage.Format("Percentage Completed:%d%%", nPercentageComplete);
GetDlgItem(IDC_STATIC_PERCENTAGE)->SetWindowText(strTmpPercentage);
//m_pMainFrame->m_ProgressCtl.SetBkColor(RGB(0, 255, 0));
int nLower, nUpper;
m_ProgressCtl.GetRange(nLower, nUpper );
m_ProgressCtl.SetPos(((nUpper-nLower)/100) * nPercentageComplete);
}
} // do
while (TRUE);
fflush (pFile);
fclose (pFile);
delete [] pBuffer;
if(!bInComplete)
{
strStaus.Format("Renaming file at local machine..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
if(!MoveFile(strTmpFileName.c_str(), strFileNameAtLocalMachine.c_str() ))
{
CString strMsg;
strMsg.Format("Error:%d", GetLastError());
AfxMessageBox(strMsg, MB_OK);
}
strStaus.Format("Done..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
}
if(!bInComplete)
{
AfxMessageBox("File has downloaded..");
GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);
}
if(hConnect)
InternetCloseHandle(hConnect);
if(hOpen)
InternetCloseHandle(hOpen);
if(hOpenFile)
InternetCloseHandle(hOpenFile);
return TRUE;
}
thank you
|
|
|
|
|
I use rest command,but use "rest 100" or "rest 0",get same
result.I rework your program,but i get same result regardless with "rest 100" or "rest 0".
my program :
bool CPauseResumeDemoDlg::StartDownloadingHardCodedFile()
{
GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);
DWORD dwPacketSize =5;
DWORD dwSize, dwToRead = dwPacketSize * 1024;
PBYTE pBuffer = new BYTE[dwPacketSize * 1024];
double dFileSize = 352256;
double dOffsetToSeek =0;
HINTERNET hConnect = NULL;
HINTERNET hOpen = NULL;
HINTERNET hOpenFile = NULL;
BOOL bRet = FALSE;
BOOL bInComplete = FALSE;
INTERNET_PORT nServerPort =21;
FILE * pFile = NULL;
string strTmpFileName = "Temp_find-ls.txt.gz";
string strFileNameAtLocalMachine= "find-ls.txt.gz";
string strFileNameAtServer= "/s.txt";
CString strStaus;
double nTripsToServerCnt;
int nTotalSpan = 100;
DWORD dwBytesWrrittenToFile =0;
nTripsToServerCnt = ceil(dFileSize / ((NKBYTE * 1024)*1.0));
if(nTripsToServerCnt ==0)
nTripsToServerCnt =1;
while(nTripsToServerCnt > nTotalSpan)
{
nTotalSpan *= 10;
}
DeleteFile(strFileNameAtLocalMachine.c_str());
m_ProgressCtl.SetRange(0,nTotalSpan);
//m_ProgressCtl.SetPos(1);
strStaus.Format("Initializing WinInet..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
hOpen = InternetOpen("PauseResumeDemo",INTERNET_OPEN_TYPE_PRECONFIG ,NULL, NULL, NULL);
if(!hOpen)
{
return false;
}
DWORD dwContext = 123;
strStaus.Format("Connecting to server..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
if ( !(hConnect = InternetConnect( hOpen, "localhost" , nServerPort, NULL, NULL, INTERNET_SERVICE_FTP, 0 , 0) ) )
{
CString strMsg;
string strReposeFromServer;
GetLastResponse(strReposeFromServer);
strMsg.Format("Error:%d\nDescription:%s", GetLastError(), strReposeFromServer.c_str());
AfxMessageBox(strMsg, MB_OK);
return false;
}
strStaus.Format("Finding out if this server supoprts Pause & Resume..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
if(FindPauseResumeSupported(hConnect))
{
strStaus.Format("Pause & Resume Supported..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
}
else
{
strStaus.Format("Pause & Resume not Supported..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
}
double dCurrentFileSize;
if(IfLocalFileExist(strTmpFileName.c_str(), &dCurrentFileSize))
{
dOffsetToSeek = dCurrentFileSize;
}
dOffsetToSeek=40;
if(dOffsetToSeek >0)
{
strStaus.Format("Sending REST...");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
//Seek to the file first
char pszOffset[30];
HINTERNET hResponse;
ltoa(dOffsetToSeek, pszOffset, 10);
//sprintf(pszOffset,"%ld", dOffsetToSeek);
string strSeekOffsetCMD = "REST " + (string)pszOffset;
bRet =FtpCommand(hConnect, // WinInet Connection handle
FALSE, // No, I don't expect a response
FTP_TRANSFER_TYPE_BINARY, // I'm receiving ASCII
"REST 6000",//strSeekOffsetCMD.c_str(), // This is the FTP command I am passing
0, // No context needed
&hResponse); // The handle to read the response
if (!bRet)
{
CString strMsg;
strMsg.Format("Error:%d", GetLastError());
AfxMessageBox(strMsg, MB_OK);
}
}
hOpenFile = ::FtpOpenFile(hConnect,strFileNameAtServer.c_str(), GENERIC_READ, FTP_TRANSFER_TYPE_ASCII, 1);
// DWORD dd=InternetSetFilePointer(hOpenFile,100,NULL,FILE_BEGIN,0);
if(hOpenFile == NULL)
{
CString strMsg;
string strReposeFromServer;
GetLastResponse(strReposeFromServer);
strMsg.Format("Error:%d\nDescription:%s", GetLastError(), strReposeFromServer.c_str());
AfxMessageBox(strMsg, MB_OK);
return false;
}
if ( !(pFile = fopen (strTmpFileName.c_str(), "ab" ) ) )
{
CString strMsg;
strMsg.Format("Error:%d", GetLastError());
AfxMessageBox(strMsg, MB_OK);
return false;
}
if(dOffsetToSeek >=0)
{
strStaus.Format("Seeking to local file...");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
int n = fseek(pFile, dOffsetToSeek, SEEK_SET);
}
dwBytesWrrittenToFile = dOffsetToSeek;
GetDlgItem(IDC_BUTTON2)->EnableWindow(TRUE);
do
{
PUMPMESSAGE();
//Intentional delay so that user get chance to hit stop button
Sleep(100);
strStaus.Format("Sending RETRIVE..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
if(m_bStopped)
{
strStaus.Format("Stopped..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
AfxMessageBox("Download aborted\nThere is an incomplete temp file 'Temp_find-ls.txt.gz' at current directory. Don't delete it just check it out. It has useful data downloaded so far...\nOnce you are done click Start again, now download will start from exact location where it left off");
m_bStopped = FALSE;
bInComplete = TRUE;
GetDlgItem(IDC_BUTTON1)->EnableWindow(TRUE);
GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);
break;
}
if (!InternetReadFile (hOpenFile, (LPVOID)pBuffer, dwToRead, &dwSize) )
{
fclose (pFile);
CString strMsg;
string strReposeFromServer;
GetLastResponse(strReposeFromServer);
strMsg.Format("Error:%d\nDescription:%s", GetLastError(), strReposeFromServer.c_str());
AfxMessageBox(strMsg, MB_OK);
return false;
}
if (!dwSize)
{
m_ProgressCtl.SetPos(100);
CString strTmpPercentage;
strTmpPercentage.Format("Percentage Completed:%d%%", 100);
GetDlgItem(IDC_STATIC_PERCENTAGE)->SetWindowText(strTmpPercentage);
break; // Condition of dwSize=0 indicate EOF. Stop.
}
else
{
fwrite(pBuffer, sizeof (char), dwSize , pFile);
Sleep(2000);
dwBytesWrrittenToFile = dwBytesWrrittenToFile + dwSize;
int nPercentageComplete = (int)floor(((dwBytesWrrittenToFile) * 100)/dFileSize);
CString strTmpPercentage;
strTmpPercentage.Format("Percentage Completed:%d%%", nPercentageComplete);
GetDlgItem(IDC_STATIC_PERCENTAGE)->SetWindowText(strTmpPercentage);
//m_pMainFrame->m_ProgressCtl.SetBkColor(RGB(0, 255, 0));
int nLower, nUpper;
m_ProgressCtl.GetRange(nLower, nUpper );
m_ProgressCtl.SetPos(((nUpper-nLower)/100) * nPercentageComplete);
}
} // do
while (TRUE);
fflush (pFile);
fclose (pFile);
delete [] pBuffer;
if(!bInComplete)
{
strStaus.Format("Renaming file at local machine..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
if(!MoveFile(strTmpFileName.c_str(), strFileNameAtLocalMachine.c_str() ))
{
CString strMsg;
strMsg.Format("Error:%d", GetLastError());
AfxMessageBox(strMsg, MB_OK);
}
strStaus.Format("Done..");
GetDlgItem(IDC_STATIC_STATUSNEW)->SetWindowText(strStaus);
}
if(!bInComplete)
{
AfxMessageBox("File has downloaded..");
GetDlgItem(IDC_BUTTON2)->EnableWindow(FALSE);
GetDlgItem(IDC_BUTTON1)->EnableWindow(FALSE);
}
if(hConnect)
InternetCloseHandle(hConnect);
if(hOpen)
InternetCloseHandle(hOpen);
if(hOpenFile)
InternetCloseHandle(hOpenFile);
return TRUE;
}
thank you
|
|
|
|
|
This code does not work on IIS and Serv-U.
Because based on RFC 959 we must send REST command and then immediately RETR.
With WinInet we have REST, PASV, TYPE I, RETR.
So, at any normal ftp server this resuming wouldn't work.
|
|
|
|
|
I too have failed to get this to work on the IIS 5.1 FTP server. This server is supposed to happily support the REST command, and answers "350 Restarting at XXX." when commanded "REST XXX"; however the subsequent attempt to retrieve a file starts from the beginning of the file, possibly because of the reason you gave.
Does anybody know how to get the REST command to work on IIS ?
Dan Ababei
|
|
|
|
|
Hi!
I just can´t get it to work on other servers than ftp.gnu.org
Even if I upload the file you´re using it doesn´t work.
When resuming, the local file is appended with, as it seems, the entire
remote file, which makes the local file much larger than it should be.
The servers I´ve tested it on, they all support resuming. (ie ftp.microsoft.com)
The REST command which is sent to the server before the download starts seems to work fine,
after sending the command I recieve:
"Error Description:350 Restarting at 66560"
What am I doing wrong?
/Jonatan
|
|
|
|
|
Hi, sorry for the delay in reply.
Well I have tried with a lot of servers and it seems to be working in most of the cases I have not tried particularly at ftp.microsoft.com but you have to the source code. Why don't you try to debug the code and find out if there is something wrong with the code. I am sure there is nothing wrong with the logic as it is working with most of other servers, there could be differences in responses at Microsoft server itself which will be interesting to know.
Try debugging it.
Thanks!!
Narendra Chandel
__NarendraC
|
|
|
|
|
Hi!
Thanks for answering!
Well, I´ve tried to debug it for a couple of days but I can´t come up with a solution.
I´m pretty sure that the REST command, or at least what comes after it, is the problem.
After sending the rest command to my server I get the following respone:
350 Restarting at 112640
Send STOR or RETR to initiate transfer
The servers response seems OK.
Then the followinf happens after sending the REST command:
I open the remote file using ::FtpOpenFile()
Then the server sends me the followingresponse:
200 TYPE is now 8-bit binary
200 PORT command successful
213 384937
150-Connecting to 217.xxx.xxx.xx:34725
150 375.9 kbytes to download
384937 byte which is 375.9 kbytes is the filesize.
It tells me it´s gonna send me the whole file from the beginning.
This can´t be right, because earlier it told me it was starting
the download at 112640 byte.
The first response from server tells me to send the RETR command to initiate transfer,
isn´t this what the ::FtpOpenFile() or ::InternetReadFile() do?
I´ve heard that some servers need to be put in block mode
before sending the RETR command. This is done by sending the command "MODE B" to the server.
Anyway, this is just something I´ve heard and I don´t know if it´s correct or how to implement it.
Any clues?
Thanks!
/Jonatan Dahl
|
|
|
|
|
I have found the same problem.We can use REST and then use RETR or STORE command to resume file transfer,but if we use InternetReadFile() or InternetWriteFile() to resume the file transfer,the final file will have different size then the original file.For example,if I try to download a file
100k from a ftp,and I abort the file transfer as the file is 50k downloaded,and then I resume.after the file transfer is completed,the file I
get is much bigger then 100k.I test this with serv-u.
|
|
|
|
|
I have been having the same exact problem. In reading the email thread it appears to confirm what I have suspected. That the WinInet high level functions do not internally support the REST command by virtue of the fact that when you do the Open it resets the port connection, invalidating the any previous REST commands. So, the solution seems to be to invoke my own RETR without using the WinInet functions. With that in mind, does anyone know where I can find an example of how to use FTPCommand with the RETR verb?
Thank you.
|
|
|
|
|
In my sample I have used it. I definitely confirm that there exist issues when you use Wininet. But if you just follow the concept as I mentioned above it is at protocol level so use any method you like to send commands. I have seen it works find with WinSocks without any problem.
Thanks!!
Narendra Chandel
__NarendraC
|
|
|
|
|
I have made this work by a very "special" way,but only on Serv-U FTP Server.My solution is to incorporate multi-commands into one submiting,just like this:
CString Cmd;
Cmd="pasv\r\nnoop\r\nabor\r\nrest "+RestOffset+"\r\nretr "+FileName;
bRet=::FtpCommand(hConnect,TRUE,FTP_TRANSFER_TYPE_BINARY,Cmd,0,&hResponse);
Note that the "abor" is needed, I guess this will release the data connection or data transfer buffer or something for the next "retr" command. RFC-959(ftp://ftp.isi.edu/in-notes/rfc959.txt) says "abort" will make the Server close the data connection.On the other hand, the "noop" is not required but just for some "reliability" consideration.
I have tested on a FreeBSD and ftp.microsoft.com(Windows IIS/FTP Server),but have no luck. I expect a perfect solution adapting to most popular FTP Servers, or by checking the brand of the connecting server may be a compromise?
|
|
|
|
|
Hi,
I read this thread looking for an awnser to the same problem. I've written my own
implementation of the FTP protocol directly on top on winsock. - So no WinInet functions,
directly reading and writing to the socket.
I found that i couldn't use the REST command on ftp.microsoft.com
But i tried the suggestion that, you must send a REST then the RETR or STOR straight after.
(which makes sense)
I've done that and it seems to work fine.
But i don't have a solution that uses winInet functions sorry.
Jared Allen.
www.chironexsoftware.com
|
|
|
|
|
Thanks for the nice article.
Please suggest how to do the following also.
HTTP Resume/Pause.
Thanks
|
|
|
|
|
|
error C2039: 'FtpCommand' : is not a member of '`global namespace''
error C2065: 'FtpCommand' : undeclared identifier
|
|
|
|
|
You need to download latest Internet developement SDK from microsoft site.
This perticular API was not supported earlier.
Let me know if it helps.
Thanks
_Narendra Chandel_
|
|
|
|
|
Hi,
I searched in Microsoft for FTPCommand update.. i think they have not giving it in Seperate API and also i searched to find an update.. sorry to say, i can't find one.. can u pls. tell me the link to get that..
Thank you in Advance..
Regards,
Pravin.
|
|
|
|
|
Check the link.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wininet/wininet/ftpcommand.asp
It tells you that this is part of new winint.h which you can download from MS site.
Please download it from microsoft site I can not send whole SDK.
Thanks!!
Narendra
__NarendraC
|
|
|
|
|
the ste address is
http://www.microsoft.com/msdownload/platformsdk/sdkupdate/
|
|
|
|
|