Axel之 -axel_do剖析
生活随笔
收集整理的這篇文章主要介紹了
Axel之 -axel_do剖析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
axel_do主體部分,嘗試從多個連接select方式去讀取數據,如果讀取失敗或者連接超時就重新連接。
下面是代碼分析.
- //下載的主循環
- void axel_do( axel_t *axel )
- {
- ? ? ? ? fd_set fds[1];
- ? ? ? ? int hifd, i;
- ? ? ? ? long long int remaining,size;
- ? ? ? ? struct timeval timeval[1];
- ? ? ? ??
- ? ? ? ? /* Create statefile if necessary? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
- ? ? ? ? //如果到了保存狀態的時間,保存當前狀態到狀態文件
- ? ? ? ? if( gettime() > axel->next_state )
- ? ? ? ? {
- ? ? ? ? ? ? ? ? //把連接的個數,當前下載量,每個連接當前的下載進度保存起來,
- ? ? ? ? ? ? ? ? //如果狀態文件已經存在,就清空重寫,目的是只保存一份
- ? ? ? ? ? ? ? ? //這樣的話,如果程序異常退出,下次開啟任務時,就能從狀態文件中
- ? ? ? ? ? ? ? ? //重新加載最近的下載狀態(不是100%準確的狀態,因為保存狀態是有周期的),
- ? ? ? ? ? ? ? ? //接著下載
- ? ? ? ? ? ? ? ? save_state( axel );
- ? ? ? ? ? ? ? ? //計算下一次狀態保存時間
- ? ? ? ? ? ? ? ? axel->next_state = gettime() + axel->conf->save_state_interval;
- ? ? ? ? }
- ? ? ? ??
- ? ? ? ? ? ? ? ? //采用多線程做連接,但是還是單線程select做傳輸
- ? ? ? ? /* Wait for data on (one of) the connections? ? ? ? ? ? ? ? ? ? ? ? */
- ? ? ? ? FD_ZERO( fds );
- ? ? ? ? hifd = 0;
- ? ? ? ? //經典的select方式,把有用的socket描述符加入到集合中
- ? ? ? ? //而且,限于文件下載的特殊任務方式,基本上每個建立好的連接
- ? ? ? ? //都不會太空,有恒定持續的數據傳輸,因此在這里select的效率并不弱于epoll
- ? ? ? ? for( i = 0; i < axel->conf->num_connections; i ++ )
- ? ? ? ? {
- ? ? ? ? ? ? ? ? if( axel->conn[i].enabled )
- ? ? ? ? ? ? ? ? ? ? ? ? FD_SET( axel->conn[i].fd, fds );
- ? ? ? ? ? ? ? ? hifd = max( hifd, axel->conn[i].fd );
- ? ? ? ? }
- ? ? ? ? //沒有任何連接,等待重試
- ? ? ? ? if( hifd == 0 )
- ? ? ? ? {
- ? ? ? ? ? ? ? ? /* No connections yet. Wait...? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
- ? ? ? ? ? ? ? ? usleep( 100000 );
- ? ? ? ? ? ? ? ? goto conn_check;
- ? ? ? ? }
- ? ? ? ? else
- ? ? ? ? {
- ? ? ? ? ? ? ? ? //超時0.1秒
- ? ? ? ? ? ? ? ? timeval->tv_sec = 0;
- ? ? ? ? ? ? ? ? timeval->tv_usec = 100000;
- ? ? ? ? ? ? ? ? /* A select() error probably means it was interrupted
- ? ? ? ? ? ? ? ?? ? by a signal, or that something else's very wrong...? ? ? ? */
- ? ? ? ? ? ? ? ? //select等待數據到來
- ? ? ? ? ? ? ? ? if( select( hifd + 1, fds, NULL, NULL, timeval ) == -1 )
- ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? //值位ready為-1,這樣,下載的主循環將退出,下載失敗
- ? ? ? ? ? ? ? ? ? ? ? ? axel->ready = -1;
- ? ? ? ? ? ? ? ? ? ? ? ? return;
- ? ? ? ? ? ? ? ? }
- ? ? ? ? }
- ? ? ? ??
- ? ? ? ? /* Handle connections which need attention? ? ? ? ? ? ? ? ? ? ? ? */
- ? ? ? ? //循環讀取每個socket的數據
- ? ? ? ? for( i = 0; i < axel->conf->num_connections; i ++ )
- ? ? ? ? if( axel->conn[i].enabled ) {
- ? ? ? ? //檢測,如果該socket有數據到來,就讀取
- ? ? ? ? ? ? ? ? if( FD_ISSET( axel->conn[i].fd, fds ) )
- ? ? ? ? {
- ? ? ? ? ? ? ? ? //更新最后一次讀取數據的時間
- ? ? ? ? ? ? ? ? axel->conn[i].last_transfer = gettime();
- ? ? ? ? ? ? ? ? //嘗試讀取數據
- ? ? ? ? ? ? ? ? size = read( axel->conn[i].fd, buffer, axel->conf->buffer_size );
- ? ? ? ? ? ? ? ? //讀取失敗
- ? ? ? ? ? ? ? ? if( size == -1 )
- ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? if( axel->conf->verbose )
- ? ? ? ? ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? axel_message( axel, _("Error on connection %i! "
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "Connection closed"), i );
- ? ? ? ? ? ? ? ? ? ? ? ? }
- ? ? ? ? ? ? ? ? ? ? ? ? //關閉當前連接,并不等于放棄,還可能重新連接。。
- ? ? ? ? ? ? ? ? ? ? ? ? axel->conn[i].enabled = 0;
- ? ? ? ? ? ? ? ? ? ? ? ? conn_disconnect( &axel->conn[i] );
- ? ? ? ? ? ? ? ? ? ? ? ? continue;
- ? ? ? ? ? ? ? ? }//當前連接的數據讀取結束
- ? ? ? ? ? ? ? ? else if( size == 0 )
- ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? if( axel->conf->verbose )
- ? ? ? ? ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* Only abnormal behaviour if:? ? ? ? ? ? ? ? */
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if( axel->conn[i].currentbyte < axel->conn[i].lastbyte && axel->size != INT_MAX )
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? axel_message( axel, _("Connection %i unexpectedly closed"), i );
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? else
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? axel_message( axel, _("Connection %i finished"), i );
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
- ? ? ? ? ? ? ? ? ? ? ? ? }
- ? ? ? ? ? ? ? ? ? ? ? ? //如果是不支持并發分片下載(也就是說是單連接下載),表明下載完成
- ? ? ? ? ? ? ? ? ? ? ? ? if( !axel->conn[0].supported )
- ? ? ? ? ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? axel->ready = 1;
- ? ? ? ? ? ? ? ? ? ? ? ? }
- ? ? ? ? ? ? ? ? ? ? ? ? axel->conn[i].enabled = 0;
- ? ? ? ? ? ? ? ? ? ? ? ? conn_disconnect( &axel->conn[i] );
- ? ? ? ? ? ? ? ? ? ? ? ? continue;
- ? ? ? ? ? ? ? ? }
- ? ? ? ? ? ? ? ? /* remaining == Bytes to go? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
- ? ? ? ? ? ? ? ? remaining = axel->conn[i].lastbyte - axel->conn[i].currentbyte + 1;
- ? ? ? ? ? ? ? ? //需要填充的小于讀取的,下載完成
- ? ? ? ? ? ? ? ? if( remaining < size )
- ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? if( axel->conf->verbose )
- ? ? ? ? ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? axel_message( axel, _("Connection %i finished"), i );
- ? ? ? ? ? ? ? ? ? ? ? ? }
- ? ? ? ? ? ? ? ? ? ? ? ? axel->conn[i].enabled = 0;
- ? ? ? ? ? ? ? ? ? ? ? ? //關閉連接
- ? ? ? ? ? ? ? ? ? ? ? ? conn_disconnect( &axel->conn[i] );
- ? ? ? ? ? ? ? ? ? ? ? ? //修改需要的數據量大小,比如需要20字節,下載了30字節,那么就只要20字節
- ? ? ? ? ? ? ? ? ? ? ? ? size = remaining;
- ? ? ? ? ? ? ? ? ? ? ? ? /* Don't terminate, still stuff to write!? ? ? ? */
- ? ? ? ? ? ? ? ? }
- ? ? ? ? ? ? ? ? /* This should always succeed..? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
- ? ? ? ? ? ? ? ? //調整偏移,寫文件
- ? ? ? ? ? ? ? ? lseek( axel->outfd, axel->conn[i].currentbyte, SEEK_SET );
- ? ? ? ? ? ? ? ? if( write( axel->outfd, buffer, size ) != size )
- ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? //寫失敗,退出
- ? ? ? ? ? ? ? ? ? ? ? ? axel_message( axel, _("Write error!") );
- ? ? ? ? ? ? ? ? ? ? ? ? axel->ready = -1;
- ? ? ? ? ? ? ? ? ? ? ? ? return;
- ? ? ? ? ? ? ? ? }
- ? ? ? ? ? ? ? ? //修改偏移
- ? ? ? ? ? ? ? ? axel->conn[i].currentbyte += size;
- ? ? ? ? ? ? ? ? axel->bytes_done += size;
- ? ? ? ? }
- ? ? ? ? else //當前socket描述符不在select中,檢查超時
- ? ? ? ? {
- ? ? ? ? ? ? ? ? //傳輸超時,關閉連接
- ? ? ? ? ? ? ? ? if( gettime() > axel->conn[i].last_transfer + axel->conf->connection_timeout )
- ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? if( axel->conf->verbose )
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? axel_message( axel, _("Connection %i timed out"), i );
- ? ? ? ? ? ? ? ? ? ? ? ? conn_disconnect( &axel->conn[i] );
- ? ? ? ? ? ? ? ? ? ? ? ? axel->conn[i].enabled = 0;
- ? ? ? ? ? ? ? ? }
- ? ? ? ? } }
- ? ? ? ? //如果一切ok,就返回
- ? ? ? ? if( axel->ready )
- ? ? ? ? ? ? ? ? return;
- ? ? ? ??
- conn_check:
- ? ? ? ? /* Look for aborted connections and attempt to restart them.? ? ? ? */
- ? ? ? ? //檢查有問題的連接,如果未下載完,并且出錯了,重新啟動線程,開始傳輸
- ? ? ? ? for( i = 0; i < axel->conf->num_connections; i ++ )
- ? ? ? ? {
- ? ? ? ? ? ? ? ? //連接無效并且未下載完
- ? ? ? ? ? ? ? ? if( !axel->conn[i].enabled && axel->conn[i].currentbyte < axel->conn[i].lastbyte )
- ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? //狀態為0,表明setup_thread是成功執行了的,并且已經執行問,因此,連接的初始化沒問題,調用join回收
- ? ? ? ? ? ? ? ? ? ? ? ? if( axel->conn[i].state == 0 )
- ? ? ? ? ? ? ? ? ? ? ? ? {? ? ? ??
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // Wait for termination of this thread
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pthread_join(*(axel->conn[i].setup_thread), NULL);
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? conn_set( &axel->conn[i], axel->url->text );
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? axel->url = axel->url->next;
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* axel->conn[i].local_if = axel->conf->interfaces->text;
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? axel->conf->interfaces = axel->conf->interfaces->next; */
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if( axel->conf->verbose >= 2 )
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? axel_message( axel, _("Connection %i downloading from %s:%i using interface %s"),
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ?? ?? ?? ? ? ?? ?? ? i, axel->conn[i].host, axel->conn[i].port, axel->conn[i].local_if );
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //狀態設置為1,表示setup_thread開始執行,設置為0,表示setup_thread線程執行結束
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? axel->conn[i].state = 1;
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if( pthread_create( axel->conn[i].setup_thread, NULL, setup_thread, &axel->conn[i] ) == 0 )
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? axel->conn[i].last_transfer = gettime();
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? else
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? axel_message( axel, _("pthread error!!!") );
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? axel->ready = -1;
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
- ? ? ? ? ? ? ? ? ? ? ? ? }
- ? ? ? ? ? ? ? ? ? ? ? ? else //setup_thread線程還未執行完,也就是說連接建立過程還未完成,需要檢查連接超時
- ? ? ? ? ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //超時了,就取消她...
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if( gettime() > axel->conn[i].last_transfer + axel->conf->reconnect_delay )
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? {
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pthread_cancel( *axel->conn[i].setup_thread );
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? axel->conn[i].state = 0;
- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
- ? ? ? ? ? ? ? ? ? ? ? ? }
- ? ? ? ? ? ? ? ? }
- ? ? ? ? }
- ? ? ? ? /* Calculate current average speed and finish_time? ? ? ? ? ? ? ? */
- ? ? ? ? //計算平均速度
- ? ? ? ? axel->bytes_per_second = (int) ( (double) ( axel->bytes_done - axel->start_byte ) / ( gettime() - axel->start_time ) );
- ? ? ? ? //估算結束時間
- ? ? ? ? axel->finish_time = (int) ( axel->start_time + (double) ( axel->size - axel->start_byte ) / axel->bytes_per_second );
- ? ? ? ? /* Check speed. If too high, delay for some time to slow things
- ? ? ? ?? ? down a bit. I think a 5% deviation should be acceptable.? ? ? ? */
- ? ? ? ? //速度調整
- ? ? ? ? if( axel->conf->max_speed > 0 )
- ? ? ? ? {
- ? ? ? ? ? ? ? ? //如果超速了
- ? ? ? ? ? ? ? ? if( (float) axel->bytes_per_second / axel->conf->max_speed > 1.05 )
- ? ? ? ? ? ? ? ? ? ? ? ? axel->delay_time += 10000;
- ? ? ? ? ? ? ? ? //速度太低,少休息會兒
- ? ? ? ? ? ? ? ? else if( ( (float) axel->bytes_per_second / axel->conf->max_speed < 0.95 ) && ( axel->delay_time >= 10000 ) )
- ? ? ? ? ? ? ? ? ? ? ? ? axel->delay_time -= 10000;
- ? ? ? ? ? ? ? ? //速度太低,干脆不休息
- ? ? ? ? ? ? ? ? else if( ( (float) axel->bytes_per_second / axel->conf->max_speed < 0.95 ) )
- ? ? ? ? ? ? ? ? ? ? ? ? axel->delay_time = 0;
- ? ? ? ? ? ? ? ? usleep( axel->delay_time );
- ? ? ? ? }
- ? ? ? ??
- ? ? ? ? /* Ready?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
- ? ? ? ? //下載完了?
- ? ? ? ? if( axel->bytes_done == axel->size )
- ? ? ? ? ? ? ? ? axel->ready = 1;
- }
轉載于:https://www.cnblogs.com/shepherd2012/archive/2012/08/06/2625670.html
總結
以上是生活随笔為你收集整理的Axel之 -axel_do剖析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序编辑SHP文件并应用更改到数据源
- 下一篇: 详细的体检项目有哪些?大概需要多少钱?癌