服务器端:
- UINT CFileTransferServerView::ThreadedSendFileToRemoteRecipient(LPVOID pVoid)
- {
- CFileTransferServerView* pThis = (CFileTransferServerView*)pVoid;
- pThis->PostMessage( UWM_FILESENDEVENT, FSE_THREADSTART, 0L );
- AfxSocketInit(NULL); // make certain this is done somewhere in each thread (usually in InitInstance for main thread)
- CSocket sockSrvr;
- sockSrvr.Create(PRE_AGREED_PORT); // Creates our server socket
- sockSrvr.Listen(); // Start listening for the client at PORT
- CSocket sockConnection;
- sockSrvr.Accept(sockConnection); // Use another CSocket to accept the connection
- pThis->PostMessage( UWM_FILESENDEVENT, FSE_STATUSCONNECTED, 0L );
- // local variables used in file transfer (declared here to avoid "goto skips definition"-style compiler errors)
- int fileLength, cbLeftToSend; // used to monitor the progress of a sending operation
- int simulate; // used to simulate mismatch events (if designated by user)
- BYTE* sendData = NULL; // pointer to buffer for sending data (memory is allocated after sending file size)
- int pbInterval = 0; int curPB = 0; // progress bar variables
- CFile sourceFile;
- CFileException fe;
- BOOL bFileIsOpen = FALSE;
- if( !( bFileIsOpen = sourceFile.Open( pThis->m_strFileName, CFile::modeRead | CFile::typeBinary, &fe ) ) )
- {
- TCHAR strCause[256];
- fe.GetErrorMessage( strCause, 255 );
- TRACE( "SendFileToRemoteRecipient 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;
- }
- // first send length of file
- fileLength = sourceFile.GetLength();
- fileLength = htonl( fileLength );
- cbLeftToSend = sizeof( fileLength );
- // 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
- {
- int cbBytesSent;
- BYTE* bp = (BYTE*)(&fileLength) + sizeof(fileLength) - cbLeftToSend;
- cbBytesSent = sockConnection.Send( bp, cbLeftToSend - simulate );
- simulate = 0;
- // test for errors and get out if they occurred
- if ( cbBytesSent == SOCKET_ERROR )
- {
- int iErr = ::GetLastError();
- TRACE( "SendFileToRemoteRecipient returned a socket error while sending file length/n"
- "/tNumber of Bytes sent = %d/n"
- "/tGetLastError = %d/n", cbBytesSent, iErr );
- /* you should handle the error here */
- goto PreReturnCleanup;
- }
- // data was successfully sent, so account for it with already-sent data
- cbLeftToSend -= cbBytesSent;
- }
- while ( cbLeftToSend>0 );
- // now send the file's data
- sendData = new BYTE[SEND_BUFFER_SIZE];
- cbLeftToSend = sourceFile.GetLength();
- // set up progress bar
- fileLength = cbLeftToSend;
- pbInterval = fileLength>>7; // divide by 128
- curPB = 0;
- pThis->m_ctlProgressSend.PostMessage( PBM_SETPOS, (WPARAM) curPB, 0L );
- do
- {
- // read next chunk of SEND_BUFFER_SIZE bytes from file
- int sendThisTime, doneSoFar, buffOffset;
- sendThisTime = sourceFile.Read( sendData, SEND_BUFFER_SIZE );
- buffOffset = 0;
- // 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
- do
- {
- doneSoFar = sockConnection.Send( sendData + buffOffset, sendThisTime - simulate );
- simulate = 0;
- // test for errors and get out if they occurred
- if ( doneSoFar == SOCKET_ERROR )
- {
- int iErr = ::GetLastError();
- TRACE( "SendFileToRemoteRecipient returned a socket error while sending chunked file data/n"
- "/tNumber of Bytes sent = %d/n"
- "/tGetLastError = %d/n", doneSoFar, iErr );
- /* you should handle the error here */
- goto PreReturnCleanup;
- }
- // data was successfully sent, so account for it with already-sent data
- // but first, advise main thread of a send mismatch if everything was not sent in one shot
- if ( doneSoFar != sendThisTime )
- {
- pThis->m_iNumMismatches++;
- pThis->PostMessage( UWM_FILESENDEVENT, FSE_UPDATECONTROLS, 0L );
- }
- buffOffset += doneSoFar;
- sendThisTime -= doneSoFar;
- cbLeftToSend -= doneSoFar;
- }
- while ( sendThisTime > 0 );
- // update progress bar
- if ( pbInterval*curPB < (fileLength-cbLeftToSend) )
- {
- curPB++;
- pThis->m_ctlProgressSend.PostMessage( PBM_SETPOS, (WPARAM) curPB, 0L );
- }
- }
- while ( cbLeftToSend > 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[] sendData;
- if ( bFileIsOpen )
- sourceFile.Close(); // only close file if it's open (open might have failed above)
- sockConnection.Close();
- // advise main thread that we're completed
- pThis->PostMessage( UWM_FILESENDEVENT, FSE_THREADCOMPLETE, 0L );
- return 0;
- }
客户端:
- 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;
- }
这个程序是从服务器发送数据到客户端,第一步先发送要发送的文件的大小.然后才开始发送文件.