mgfilemanager.cpp

来自「一款LINUX下的下载软件」· C++ 代码 · 共 1,343 行 · 第 1/3 页

CPP
1,343
字号
    return m_Index.size();

    //*/

}

//get file length,check if the length ok
llong CMgFileManager::FileSize( string sFileName )
{

    ifstream f;
    f.open( sFileName.c_str(), ios::binary | ios::in );

    if ( !f.good() || f.eof() || !f.is_open() )
    {
        return 0;
    }

    f.seekg( 0, ios::beg );
    ifstream::pos_type begin_pos = f.tellg();
    f.seekg( 0, std::ios::end );
    llong len = static_cast<llong>( f.tellg() - begin_pos );
    f.close();
    return len;

}


struct SAscendingDateSort
{
    bool operator() ( bindex a, bindex b )
    {
        return a.start < b.start;
    }
};

//order the index
void CMgFileManager::OrderIndex()
{ //按起点顺序从小到大排序

    if ( m_Index.size() <= 1 )
        return ;

    sort( m_Index.begin(), m_Index.end(), SAscendingDateSort() );
}

//lastsize returned for sometime thread can't get filesize ahead till task finish
bool CMgFileManager::IsTaskFinish( llong& lastsize )
{

    if ( m_Index.size() == 1 &&
            m_Index[ 0 ].start == 0 &&
            m_Index[ 0 ].end == m_nFileLen
       )
    {

        lastsize = m_nFileLen;
        return true;
    }
    else
    {
		if ( m_nFileLen == 0 ) 		{ 			lastsize=0; return true; 		} else {
        	lastsize = m_nFileLen;
        	return false;		}
    }

}

//对索引合并,应该加锁使用
//对没有作标记的0长度索引,删除
void CMgFileManager::MergeIndex()
{
    if ( m_Index.empty() )
        return ;

    if ( m_Index.size() == 1 )
    {
        if ( !m_Index.front().mark && m_Index.front().start == m_Index.front().end )
        {
            m_Index.clear();
            return ;
        }
    }

    vector<bindex> icopy;

    vector<bindex>::iterator it;

    bindex lastindex = m_Index.front();

    for ( it = m_Index.begin() + 1;it != m_Index.end();it++ )
    {
        if ( lastindex.end >= it->start )
        {
            if ( lastindex.end < it->end )
            {
                lastindex.end = it->end;
                lastindex.mark = it->mark;
            }
            else
            {
                continue;
            }
        }
        else
        {
            if ( !lastindex.mark && lastindex.start == lastindex.end )
            {
            }
            else
            {
                icopy.push_back( lastindex );
            }

            lastindex = *it;
        }
    }

    icopy.push_back( lastindex );

    m_Index.swap( icopy );

}

//thread give his data by calling this function
//if >0 returned thread should continue to get data
//if =0 returned thread should stop.
//if <0 returned ,means something error with write data,thread should stop.
//tid is 1 based
int CMgFileManager::FileData( int tid, llong offset, int len, void *data, bool end, int& us )
{

    //if posible ,check file length

    if ( end )
    {

        llong flen = offset + len;

        if ( m_nFileLen != -1 )
        { //have size

            if ( m_nFileLen != flen )
            { //socket close maybe not indicate the file end.
                //sometime overload server will close the connection
                //so we don't use this info if we alread have file size
                OutMsg( _MGSTR( _S_FILEMGR_ERRORCLOSESOCK ), MSG_WARNNING );
            }
            else
            {
                OutMsg( _MGSTR( _S_FILEMGR_FILELENCONFIRM ), MSG_SUCCESS );
            }
        }
        else
        { //no filesize,asume the flen is filesize,because server closed the connection
            //no function convert long long to string
            char lenstr[ 24 ];
            sprintf( lenstr, "%lld", flen );
            m_nFileLen = flen;
            OutMsg( _MGSTR( _S_FILEMGR_ENDFILELEN ) + string( lenstr ) );
        }
    }

    pthread_mutex_lock( &m_IndexMutex );

    us = gSpeedCtrl.DataIn( len ); //speed control

    bool combine;
    //write data to file
    int wret = WriteData( offset, len, data, combine );

    if ( wret >= 0 )
    {
        WriteIndex();	//write index

        if ( combine )
        {
            m_nSumBytes = SumBytes() - m_nOriginBytes;
        }
        else
        {
            m_nSumBytes += len;	//record data to calcu speed
        }
    }
    else
    {
        goto quit;
        //pthread_mutex_unlock(&m_IndexMutex);
        //return wret;
    }

    //OK,update ui data
    if ( m_bUpdateUI && m_pShowWin )
    {

        struct bindex data[ 20 ];

        for ( int i = 0;i < int( m_Index.size() ) && i < 20;i++ )
        {
            data[ i ] = m_Index[ i ];
        }

        m_pShowWin->SetData( m_Index.size(), data );

    }

quit:

    m_UrlList[ m_AntId2UrlIndex[ tid - 1 ] ].prior++; //multi url prior
    m_AntSpeed[ tid - 1 ] ++;
    m_SumPack++;


    if ( m_UrlList.size() > 1 && m_nSwap > 0 )
    {
        if ( m_nSwap == tid )
        {

            if ( wret > 0 )
                wret = -3;

            memset( m_AntSpeed, 0, 10 * sizeof( int ) );

            m_SumPack = 0;

            m_nSwap = -1;

        }

        pthread_mutex_unlock( &m_IndexMutex );
        return wret;

    }

    //10M check
    if ( m_SumPack * RECVBUF > 10 * 1024 * 1024 && m_UrlList.size() > 1 )
    {

        //检查我们这个线程的速度和最大速度的差异,如果>=2就试图切换
        //本线程速度=m_AntSpeed[tid-1];
        //找最大速度
        int maxspeed = -1;

        for ( int i = 0;i < 10;i++ )
        {
            if ( m_AntSpeed[ i ] > maxspeed )
                maxspeed = m_AntSpeed[ i ];
        }

        int minspeed = 1000000;
        int minpos = -1;
        //找最小速度

        for ( int i = 0;i < 10;i++ )
        {
            if ( m_AntSpeed[ i ] > 0 && m_AntSpeed[ i ] < minspeed )
            {
                minspeed = m_AntSpeed[ i ];
                minpos = i;
            }
        }

        //check if have new mirror.
        bool havenew = false;

        pthread_mutex_lock( &m_UListMutex );

        std::vector<_ul>::const_iterator itm;

        for ( itm = m_UrlList.begin();itm != m_UrlList.end();itm++ )
        {
            if ( !itm->bused )
            {
                havenew = true;
                break;
            }
        }

        pthread_mutex_unlock( &m_UListMutex );

        if ( havenew )
        {
            m_nSwap = minpos + 1;

            if ( m_nSwap == tid )
            {
                if ( wret > 0 )
                    wret = -3;

                memset( m_AntSpeed, 0, 10 * sizeof( int ) );

                m_SumPack = 0;

                m_nSwap = -1;
            }
        }

        else if ( float( maxspeed ) / minspeed >= 2.0 )
        {

            m_nSwap = minpos + 1;

            if ( m_nSwap == tid )
            {

                if ( wret > 0 )
                    wret = -3;

                memset( m_AntSpeed, 0, 10 * sizeof( int ) );

                m_SumPack = 0;

                m_nSwap = -1;
            }

        }
        else
        { //wait for next
            memset( m_AntSpeed, 0, 10 * sizeof( int ) );
            m_SumPack = 0;
            m_nSwap = -1;
        }
    }

    pthread_mutex_unlock( &m_IndexMutex );
    //if socks closed the end this session
    //2006/10/09 comment out 2 lines
    //if(end && wret<0) return wret;
    //else if(end && wret>=0) return 0;
    return wret;
}

//write data to file
//return:
// <0 error
// =0 merged with other block,stop
// >0 continue

int CMgFileManager::WriteData( llong offset, int len, void *data, bool& combine )
{

    FILE * fp;

    combine = false;//use wxwidgets preprocesser ,mac and bsd only have fopen
#if defined(WIN32) || defined(__BSD__) || defined(__WINDOWS__) || defined(__DARWIN__)  

    if ( NULL != ( fp = fopen( m_PartName.c_str(), "rb+" ) ) )
#else 

    if ( NULL != ( fp = fopen64( m_PartName.c_str(), "r+" ) ) )
#endif

    {

#ifdef WIN32

        if ( 0 != fseek( fp, offset, SEEK_SET ) )
#else

        if ( 0 != fseeko( fp, offset, SEEK_SET ) )
#endif

        {
            OutMsg( "fseeko fail.", MSG_ERROR );
            return -1;
        }

        //似乎要在这里防止数据过载,否则文件末尾会变化

        if ( m_nFileLen != -1 )
        { //know filelen

            if ( offset + ( llong ) len <= m_nFileLen )
            {
                if ( len != int( fwrite( data, 1, len, fp ) ) )
                {
                    OutMsg( "fwrite fail.", MSG_ERROR );
                    return -1;
                }
            }
            else if ( m_nFileLen - offset > 0 )
            {
                OutMsg( "data overload", MSG_ERROR );

                if ( m_nFileLen - offset != int( fwrite( data, 1, m_nFileLen - offset, fp ) ) )
                {
                    OutMsg( "fwrite fail.", MSG_ERROR );
                    return -1;
                }
            }
            else
            {
                OutMsg( "data overload", MSG_ERROR );
            }
        }
        else //unknow filelen
        {
            if ( len != int( fwrite( data, 1, len, fp ) ) )
            {
                OutMsg( "fwrite fail.", MSG_ERROR );
                return -1;
            }
        }

        fclose( fp );
        //是否继续下载要判断是否这段数据已经连接到了下一个已下载的数据段
        //首先找到这个数据段在索引中的项目,然后查找下一个索引的起点位置,如果能够重合,就停止本线程下载
        //bool found=false;

        for ( int i = 0;i < int( m_Index.size() );i++ )
        {
            if ( m_Index[ i ].end == offset )
            {
                //found

                if ( i == int( m_Index.size() - 1 ) )
                { //last block

                    m_Index[ i ].end += len;

                    if ( m_nFileLen != -1 )
                    { //have filelen,we can judge if data end

                        if ( m_Index[ i ].end > m_nFileLen )
                        {
                            OutMsg( _MGSTR( _S_FILEMGR_DATAOVERLOAD ), MSG_WARNNING );
                            m_Index[ i ].end = m_nFileLen;
                            combine = true;
                        }

                        return m_Index[ i ].end == m_nFileLen ? 0 : 1;
                    }
                    else //2006/10/02 add
                    { //no filelen,we can't judge if data end,just continue
                        return 1;
                    }
                }
                else if ( m_Index[ i + 1 ].start <= offset + len )
                { //block merge with next block
                    //是否让本线程退出取决于数据是否超越了下一个块的末尾,如果超越了下个快的末尾
                    //那么应该让本线程继续,否则应该退出本线程,继续选择下一个下载点。
                    int nret = m_Index[ i + 1 ].end > offset + len ? 0 : 1;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?