📄 filetransferclientview.cpp
字号:
strTemp = strIP.Mid( 0, nDex);
strIP = strIP.Mid( nDex+1 );
b[ii] = atoi( strTemp );
}
b[3] = atoi( strIP );
if ( bErr )
{
m_ctlTargetIP.SetAddress( b[0], b[1], b[2], b[3] );
}
*/
}
#define PRE_AGREED_PORT 8686
#define RECV_BUFFER_SIZE 4096
BOOL CFileTransferClientView::GetFileFromRemoteSender(CString strIP, CString fName)
{
/***************************
// connects to a remote server and downloads a file from it
// the remote server must be running a counterpart SendFileToRemoteRecipient function
// Inputs: CString strIP = IP address of remote server, in dotted IP format (like "127.0.0.1") or a manchine name (like "localhost")
// CString fName = name of local file to which downlaoded data will be stored
// Output: BOOL return value indiactes success or failure of the download
****************************/
// create client socket and connect to server
/// AfxSocketInit(NULL); // make certain this is done somewhere in each thread (usually in InitInstance for main thread)
CSocket sockClient;
sockClient.Create();
sockClient.Connect( strIP, PRE_AGREED_PORT ); // PRE_AGREED_PORT is #define'd as 8686
// local variables used in file transfer (declared here to avoid "goto skips definition"-style compiler errors)
BOOL bRet = TRUE; // return value
int dataLength, cbBytesRet, cbLeftToReceive; // used to monitor the progress of a receive operation
BYTE* recdData = NULL; // pointer to buffer for receiving data (memory is allocated after obtaining file size)
CFile destFile;
CFileException fe;
BOOL bFileIsOpen = FALSE;
// open/create target file that receives the transferred data
if( !( bFileIsOpen = destFile.Open( fName, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary, &fe ) ) )
{
TCHAR strCause[256];
fe.GetErrorMessage( strCause, 255 );
TRACE( "GetFileFromRemoteSender encountered an error while opening the local file\n"
"\tFile name = %s\n\tCause = %s\n\tm_cause = %d\n\tm_IOsError = %d\n",
fe.m_strFileName, strCause, fe.m_cause, fe.m_lOsError );
/* you should handle the error here */
bRet = FALSE;
goto PreReturnCleanup;
}
// get the file's size first
cbLeftToReceive = sizeof( dataLength );
do
{
BYTE* bp = (BYTE*)(&dataLength) + sizeof(dataLength) - cbLeftToReceive;
cbBytesRet = sockClient.Receive( bp, cbLeftToReceive );
// test for errors and get out if they occurred
if ( cbBytesRet == SOCKET_ERROR || cbBytesRet == 0 )
{
int iErr = ::GetLastError();
TRACE( "GetFileFromRemoteSite returned a socket error while getting file length\n"
"\tNumber of Bytes received (zero means connection was closed) = %d\n"
"\tGetLastError = %d\n", cbBytesRet, iErr );
/* you should handle the error here */
bRet = FALSE;
goto PreReturnCleanup;
}
// good data was retrieved, so accumulate it with already-received data
cbLeftToReceive -= cbBytesRet;
}
while ( cbLeftToReceive > 0 );
dataLength = ntohl( dataLength );
// now get the file in RECV_BUFFER_SIZE chunks at a time
recdData = new byte[RECV_BUFFER_SIZE];
cbLeftToReceive = dataLength;
do
{
int iiGet, iiRecd;
iiGet = (cbLeftToReceive<RECV_BUFFER_SIZE) ? cbLeftToReceive : RECV_BUFFER_SIZE ;
iiRecd = sockClient.Receive( recdData, iiGet );
// test for errors and get out if they occurred
if ( iiRecd == SOCKET_ERROR || iiRecd == 0 )
{
int iErr = ::GetLastError();
TRACE( "GetFileFromRemoteSite returned a socket error while getting chunked file data\n"
"\tNumber of Bytes received (zero means connection was closed) = %d\n"
"\tGetLastError = %d\n", iiRecd, iErr );
/* you should handle the error here */
bRet = FALSE;
goto PreReturnCleanup;
}
/*************************
un-comment this code and put a breakpoint here to prove to yourself that sockets can return fewer bytes than requested
if ( iiGet != iiRecd )
{
int ii=0;
}
***************************/
// good data was retrieved, so accumulate it with already-received data
destFile.Write( recdData, iiRecd); // Write it
cbLeftToReceive -= iiRecd;
}
while ( cbLeftToReceive > 0 );
PreReturnCleanup: // labelled "goto" destination
// free allocated memory
// if we got here from a goto that skipped allocation, delete of NULL pointer
// is permissible under C++ standard and is harmless
delete[] recdData;
if ( bFileIsOpen )
destFile.Close(); // only close file if it's open (open might have failed above)
sockClient.Close();
return bRet;
}
UINT CFileTransferClientView::ThreadedGetFileFromRemoteSender(LPVOID pVoid)
{
CFileTransferClientView* pThis = (CFileTransferClientView*)pVoid;
// advise main thread that this thread has started
pThis->PostMessage( UWM_GETFILEEVENT, GFE_THREADSTART, 0L );
// create client socket and connect to server
AfxSocketInit(NULL); // make certain this is done somewhere in each thread (usually in InitInstance for main thread)
CSocket sockClient;
sockClient.Create();
sockClient.Connect( pThis->m_strTargetIP, PRE_AGREED_PORT ); // PRE_AGREED_PORT is #define'd as 8686
pThis->PostMessage( UWM_GETFILEEVENT, GFE_STATUSCONNECTED, 0L );
// local variables used in file transfer (declared here to avoid "goto skips definition"-style compiler errors)
int dataLength, cbBytesRet, cbLeftToReceive; // used to monitor the progress of a receive operation
int simulate; // used to simulate mismatch events (if designated by user)
BYTE* recdData = NULL; // pointer to buffer for receiving data (memory is allocated after obtaining file size)
int pbInterval = 0; int curPB = 0; // progress bar variables
CFile destFile;
CFileException fe;
BOOL bFileIsOpen = FALSE;
// open/create target file that receives the transferred data
if( !( bFileIsOpen = destFile.Open( pThis->m_strFileName,
CFile::modeCreate | CFile::modeWrite | CFile::typeBinary, &fe ) ) )
{
TCHAR strCause[256];
fe.GetErrorMessage( strCause, 255 );
TRACE( "GetFileFromRemoteSender encountered an error while opening the local file\n"
"\tFile name = %s\n\tCause = %s\n\tm_cause = %d\n\tm_IOsError = %d\n",
fe.m_strFileName, strCause, fe.m_cause, fe.m_lOsError );
/* you should handle the error here */
goto PreReturnCleanup;
}
// get the file's size first
cbLeftToReceive = sizeof( dataLength );
// Inject mismatch events (if selected by user)
// Seed the random-number generator with current time
srand( (unsigned)time( NULL ) );
simulate = 1 + rand() % 2; // either 1 or 2
simulate = ( pThis->m_bSimulateEvents ) ? simulate : 0; // zero if user de-selected event simulation
do
{
BYTE* bp = (BYTE*)(&dataLength) + sizeof(dataLength) - cbLeftToReceive;
cbBytesRet = sockClient.Receive( bp, cbLeftToReceive - simulate );
simulate = 0;
// test for errors and get out if they occurred
if ( cbBytesRet == SOCKET_ERROR || cbBytesRet == 0 )
{
int iErr = ::GetLastError();
TRACE( "GetFileFromRemoteSite returned a socket error while getting file length\n"
"\tNumber of Bytes received (zero means connection was closed) = %d\n"
"\tGetLastError = %d\n", cbBytesRet, iErr );
/* you should handle the error here */
goto PreReturnCleanup;
}
// good data was retrieved, so accumulate it with already-received data
cbLeftToReceive -= cbBytesRet;
}
while ( cbLeftToReceive > 0 );
dataLength = ntohl( dataLength );
// set up progress bar based on expected length of file
pbInterval = dataLength>>7; // divide by 128
curPB = 0;
pThis->m_ctlProgressGet.PostMessage( PBM_SETPOS, (WPARAM) curPB, 0L );
// now get the file in RECV_BUFFER_SIZE chunks at a time
recdData = new byte[RECV_BUFFER_SIZE];
cbLeftToReceive = dataLength;
do
{
int iiGet, iiRecd;
// simulate mismatch events
simulate = rand();
simulate = ( simulate>RAND_MAX/10 ) ? 0 : 2560*simulate/RAND_MAX ; // up to 256 but only inject mismatches 10% of the time
simulate = ( pThis->m_bSimulateEvents ) ? simulate : 0 ; // zero if user de-selected event simulation
iiGet = (cbLeftToReceive<RECV_BUFFER_SIZE) ? cbLeftToReceive : RECV_BUFFER_SIZE ;
iiRecd = sockClient.Receive( recdData, iiGet - simulate );
simulate = 0;
// test for errors and get out if they occurred
if ( iiRecd == SOCKET_ERROR || iiRecd == 0 )
{
int iErr = ::GetLastError();
TRACE( "GetFileFromRemoteSite returned a socket error while getting chunked file data\n"
"\tNumber of Bytes received (zero means connection was closed) = %d\n"
"\tGetLastError = %d\n", iiRecd, iErr );
/* you should handle the error here */
goto PreReturnCleanup;
}
// good data was retrieved, so accumulate it with already-received data
// but first, advise main thread of a receive mismatch if we have not yet received everything expected
if ( iiGet != iiRecd )
{
pThis->m_iNumMismatches++;
pThis->PostMessage( UWM_GETFILEEVENT, GFE_UPDATECONTROLS, 0L );
}
destFile.Write( recdData, iiRecd); // Write it
cbLeftToReceive -= iiRecd;
// update progress bar
if ( pbInterval*curPB < (dataLength-cbLeftToReceive) )
{
curPB++;
pThis->m_ctlProgressGet.PostMessage( PBM_SETPOS, (WPARAM) curPB, 0L );
}
}
while ( cbLeftToReceive > 0 );
PreReturnCleanup: // labelled "goto" destination
// free allocated memory
// if we got here from a goto that skipped allocation, delete of NULL pointer
// is permissible under C++ standard and is harmless
delete[] recdData;
if ( bFileIsOpen )
destFile.Close(); // only close file if it's open (open might have failed above)
sockClient.Close();
pThis->PostMessage( UWM_GETFILEEVENT, GFE_THREADCOMPLETE, 0L );
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -