<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Http多線程下載與斷點續(xù)傳分析

    Http多線程下載與斷點續(xù)傳分析

        找了很多天的工作,真是找得有點郁悶,也就惰了下來!發(fā)現(xiàn)現(xiàn)在的簡歷真是不值錢。上次面試的時候本來投的是“高級程序員”職位,筆試也筆試,面試也面了。本來還是信心滿滿的. 不過后來在談到薪水的時候,被貶到了初級程序員,給的高級程序員標(biāo)準(zhǔn)我還達不到,中級程序員的標(biāo)準(zhǔn)也需要一定條件--中級證書,郁悶的是我也沒有!最后被定位為初級程序員!還真是有點打擊人。

        不過我到現(xiàn)在也不知道初中高級程序員的標(biāo)準(zhǔn)究竟在哪里,平時總是盡量讓自己提高,也很少去考濾到證書的重要性!總之最后就是泡湯了

        好了,口水就吐到這里吧,轉(zhuǎn)入正題!投簡歷歸投簡歷,剩余時間總是喜歡做一點自己喜歡做的事。

        有時候發(fā)現(xiàn)最快樂的事就是靜靜的聽著音樂,敲著代碼,寫一些東西與朋友一起分享,一起研究。

        上次的 - “Mp3在線搜索工具”還有很多可以改進的地方,也得到一些朋友的建議,非常感謝。這個版本中加入了斷點續(xù)傳的功能,使用了XML文件保存任務(wù)列表及狀態(tài)信息,并且支持多線程分段下載, 提高下載速度,在這一個版本中,我把它叫做: JLoading 因為我還想不出一個更好聽一點或更酷一些的名字,而且我還想讓他可以下載一些其它文件。程序不想做大,但想做得極致一些,比如從速度上。歡迎交流學(xué)習(xí), huliqing(huliqing@live.com)

    Jloading完整程序下載

    Jloading源碼下載(僅供學(xué)習(xí)研究使用,有任何問題請與本人聯(lián)系)





    協(xié)議針對于Http,先談一下簡單原理。因為代碼太多,在這里只取重點分析。

        如果你對http協(xié)議比較了解,那么你應(yīng)該已經(jīng)知道原理了,只要在請求頭中加入以下代碼就可以只請求部分?jǐn)?shù)據(jù): Content-Range: bytes 20000-40000/47000 ,
    即從第20000字節(jié)請求到第40000個字節(jié),(文件長度是47000字節(jié)).知道了這一點之后,請求數(shù)據(jù)就非常容易了,
    只要利用Java中的URL,先探測數(shù)據(jù)的長度,然后再將這個長度分片段進行多段程下載就可以了,以下是我的實現(xiàn)方式:
            // 對文件進行分塊
            try {
                totalBytes 
    = new URL(url).openConnection().getContentLength();
                
    if (totalBytes == -1) state = STATE_NONE;
            } 
    catch (IOException ioe) {
                
    return;
            }
            
    // 創(chuàng)建分塊,并創(chuàng)建相應(yīng)的負(fù)責(zé)下載的線程
            long pieceSize = (long) Math.ceil((double) totalBytes / (double) threads);
            
    long pStart = 0;
            
    long pEnd = 0;
            tasksAll.clear();
            tasks.clear();
            
    for (int i = 0; i < threads; i++) {
                
    if (i == 0) {
                    pStart 
    = pieceSize * i;
                }
                
    if (i == threads - 1) {
                    pEnd 
    = totalBytes;
                } 
    else {
                    pEnd 
    = pStart + pieceSize;
                }
                Piece piece 
    = new Piece(pStart, pStart, pEnd);
                tasksAll.add(piece);
                tasks.add(piece);
                pStart 
    = pEnd + 1;
            }

      程序根據(jù)線程數(shù)目劃分成相應(yīng)的分片信息(Piece)并放入任務(wù)列表中,由線程池中的線程去負(fù)責(zé)下載,每個線程負(fù)責(zé)一個片段(Piece),當(dāng)線程下載完自己的分片之后并不立即消毀,而是到任務(wù)隊列中繼續(xù)獲取任務(wù),
    若任務(wù)池為空,則將自己放入空閑池中并等待新任務(wù),其他線程在發(fā)現(xiàn)有空閑線程時,則將自己所負(fù)責(zé)的任務(wù)分片再進行切割,并放入到任務(wù)隊列中,同時喚醒空閑線程幫助下載,這樣不會出現(xiàn)懶惰線程,也可以實現(xiàn)動態(tài)增刪線程的功能,注意的是一些線程同步的問題。
    public void run() {
            
    while (!dl.isOk()) {
                
                
    // 暫停任務(wù)
                synchronized (this) {
                    
    if (dl.isPaused()) {
                        
    try {
                            
    this.wait();
                        } 
    catch (InterruptedException e) {
                        }
                    }
                }
                
                
    // 中斷停止
                if (Thread.interrupted() || dl.isStopped()) {
                    
    return;
                }
                
                
    // 等待獲取任務(wù)
                Piece piece;
                
    synchronized (tasks) {
                    
    while (tasks.isEmpty()) {
                        
    if (dl.isOk()) return;
                        
    try {
                            tasks.wait();
                            
    //System.out.println(this.getName() + ":wait");
                        } catch (InterruptedException ie) {
                            
    //System.out.println(this.getName() + 
                            
    //        ":InterruptedException:" + ie.getMessage());
                        }
                    }
                    piece 
    = tasks.remove(0);
                    dl.removeFreeLoader(
    this);
                    
    //System.out.println(this.getName() + ":loading");
                }
                
    try {
                    URL u 
    = new URL(dl.getURL());
                    URLConnection uc 
    = u.openConnection();
                    
    // 設(shè)置斷點續(xù)傳位置
                    uc.setAllowUserInteraction(true);
                    uc.setRequestProperty(
    "Range""bytes=" + piece.getPos() + "-" + piece.getEnd());
                    in 
    = new BufferedInputStream(uc.getInputStream());

                    out 
    = new RandomAccessFile(dl.getFileProcess(), "rw");
                    out.seek(piece.getPos()); 
    // 設(shè)置指針位置

                    
    long start;
                    
    long end;
                    
    int len = 0;
                    
    while (piece.getPos() < piece.getEnd()) {
                        start 
    = System.currentTimeMillis();
                        len 
    = in.read(buff, 0, buff.length);
                        
    if (len == -1break;
                        out.write(buff, 
    0, len);
                        end 
    = System.currentTimeMillis();
                        timeUsed 
    += end - start;    // 累計時間使用
                        
                        
    long newPos = piece.getPos() + len;
                        
                        
    // 如果該區(qū)段已經(jīng)完成,如果該線程負(fù)責(zé)的區(qū)域已經(jīng)完成,或出界
                        if (newPos > piece.getEnd()) {
                            piece.setPos(piece.getEnd());   
                            
    long offset = newPos - piece.getEnd();
                            
    long trueReads = (len - offset + 1);
                            dl.growReadBytes(trueReads);    
    // 修正偏移量
                            dl.setOffsetTotal(dl.getOffsetTotal() + trueReads);
                            readBytes 
    += trueReads;
                            
    //System.out.println(this.getName() + ":read=" + trueReads);
                        } else {
                            dl.growReadBytes(len);
                            piece.setPos(piece.getPos() 
    + len);
                            readBytes 
    += len;
                            
    //System.out.println(this.getName() + ":read=" + len);
                        }
                        
    // 如果存在空閑的任務(wù)線程,則切割出新的區(qū)域至任務(wù)隊列中。由空閑
                        
    // 的線程輔助下載
                        if (dl.isFreeLoader()) {
                            Piece newPiece 
    = piece.cutPiece();
                            
    if (newPiece != null) {
                                
    synchronized (tasks) {
                                    dl.addTask(newPiece);
                                    dl.setRepairCount(dl.getRepairCount() 
    + 1); // 增加切割次數(shù)
                                    tasks.notifyAll();  // 喚醒等待任務(wù)中的空閑線程
                                }
                            }
                            
                        }
                        
    // 暫停任務(wù)
                        synchronized (this) {
                            
    if (dl.isPaused()) {
                                
    try {
                                    
    this.wait();
                                } 
    catch (InterruptedException e) {
                                }
                            }
                        }
                        
                        
    // 中斷停止
                        if (Thread.interrupted() || dl.isStopped()) {
                            in.close();
                            out.close();
                            
    return;
                        }
                        
    //System.out.println(this.getName() + ":read:" + dl.getReadBytes());
                    }
                    out.close();
                    in.close(); 
                    dl.addFreeLoader(
    this);
                    
    //System.out.println("切割次數(shù):" + dl.getRepairCount());
                    if (dl.isOk()) dl.processWhenOk();
                } 
    catch (IOException e) {
                    
    //System.out.println(this.getName() + ":無法讀取數(shù)據(jù)");
                }
            }
        }

    這里使用了RandomAccessFile進行保存本地文件,使用RandomAccessFile可以快速移動指針。另外一個就是需要在運行過程中,記得定時保存分片信息,以免在程序意外崩潰的情況下無法正常保存狀態(tài)信息。
    程序可能還存在一些不足并且還有很多可以改進的地方。

    以下是狀態(tài)文件Config的XML結(jié)構(gòu),這里記錄了每個任務(wù)的運行狀態(tài),piece作為每個分段的狀態(tài),在程序重啟之后載入這個配置文件,并在下載完成之后刪除這一文件.另外主目錄還有一個task.xml文件,用于記錄所有下載任務(wù),及狀態(tài)文件的位置。
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <file id="1207786769343_4046.6321122755676" 
        length
    ="3895507" 
        name
    ="讀你  36首經(jīng)典精選" 
        save
    ="C:\Documents and Settings\huliqing.TBUY-HULIQING\桌面\dist\musics\讀你  36首經(jīng)典精選[1].mp3" 
        threads
    ="12">
    <urls>
        
    <url src="http://zlq.zust.edu.cn/Uploadfiles/wlhx/20071224220653927.mp3"/>
    </urls>
    <pieces>
        
    <piece end="324626" pos="20767" start="0"/>
        
    <piece end="649253" pos="419439" start="324627"/>
        
    <piece end="973880" pos="892414" start="649254"/>
        
    <piece end="1298507" pos="1068702" start="973881"/>
        
    <piece end="1623134" pos="1318124" start="1298508"/>
        
    <piece end="1947761" pos="1706453" start="1623135"/>
        
    <piece end="2272388" pos="1987815" start="1947762"/>
        
    <piece end="2597015" pos="2535705" start="2272389"/>
        
    <piece end="2921642" pos="2671690" start="2597016"/>
        
    <piece end="3246269" pos="3176315" start="2921643"/>
        
    <piece end="3570896" pos="3522551" start="3246270"/>
        
    <piece end="3895507" pos="3678693" start="3570897"/>
    </pieces>




    - huliqing@huliqing.name
    - http://www.huliqing.name

    posted on 2008-04-10 08:38 huliqing 閱讀(18901) 評論(27)  編輯  收藏 所屬分類: Swing

    評論

    # re: Http多線程下載與斷點續(xù)傳分析[未登錄] 2008-04-10 09:07 Frank

    一直在看你的blog,今天又有新的收獲 ,先謝謝了 哦
      回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2008-04-10 09:16 huliqing

    @Frank
    呵呵,歡迎互相交流學(xué)習(xí)!  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析[未登錄] 2008-04-10 09:18 Frank

    你的程序下載的時候很快,但合并文件的時候沒有用到多線程,所以下載完畢后,文件不能立即就使用  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2008-04-10 09:28 ljwan12

    提供下載速度,單靠多線程是不行的,比如你選擇的一個下載源,他的速度本來就很慢,這樣你即使使用很多線程連接,速度也不會有多大的提高。
    我認(rèn)為有兩種方法可以提高:
    (1)、使用P2P,但此對于你的這個估計沒多大效果,因為這個小軟件的使用人數(shù)不多,同時下載某一個文件的概率太小。
    (2)、選擇更快的下載源,你的程序是通過百度MP3搜索查找歌曲,你可以通過程序來判斷某一個下載源的速度,選擇最快的一個。本人認(rèn)為這種實現(xiàn)對于你的這個程序比較有效。
    迅雷下載速度很快,他結(jié)合了很多種技術(shù)。
    本人的一點建議,僅供參考!!  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2008-04-10 09:35 huliqing

    @Frank
    我使用的是多個RandomAccessFile同時利用一個File對象寫同一個文件,操作系統(tǒng)本身會同步對文件的寫操作。在利用多個File對象寫同一個文件時,遇到一些問題, 另外我認(rèn)為速度的瓶頸主要還是來自網(wǎng)絡(luò),本地文件讀寫應(yīng)該不會是什么大問題。:)  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2008-04-10 09:40 huliqing

    @ljwan12
    <urls>
    <url src="http://zlq.zust.edu.cn/Uploadfiles/wlhx/20071224220653927.mp3"/>
    </urls>
    呵呵,我在配置文件中預(yù)留這一個,我想,在有可能的情況下讓程序從多個下載源中進行文件下載。有時候我們會搜到很多同文件而不同URL的源地址。利用這個應(yīng)該可以更好的提升速度  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2008-04-10 09:40 Paul Lin

    多謝樓主分享!  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2008-04-10 10:01 netnova

    中級程序員的標(biāo)準(zhǔn)也需要一定條件--中級證書
    什么公司,這么土。  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析[未登錄] 2008-04-10 10:02 Samuel

    1、在選擇需要下載的歌曲的時候,不能支持雙擊加入下載列表。也沒有右鍵,這樣挺不方便的  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2008-04-10 10:11 太陽

    繼續(xù)關(guān)注樓主的作品, 大家一起出謀劃策  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2008-04-10 14:48 ljwan12

    @huliqing
    你的想法,在其他的很多下載軟件中就是這么實現(xiàn)的,但是這個實現(xiàn)起來就比較復(fù)雜了,你還得建立自己的后臺服務(wù)器來保存這些資源的一些信息,另外還有一個更加重要的是你需要有一套很好的機制來判斷是否是完全一樣的!!!
    可以參考一些開源下載軟件的代碼,他們實現(xiàn)的都比較好!比如電驢  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析[未登錄] 2008-04-10 18:47 huliqing

    謝謝大家的意見,作這一個只是研究或者學(xué)習(xí)一些技術(shù),還無意做大,只是與大家共同研究學(xué)習(xí)一下,畢竟個人能力,時間與精力還是有限,呵呵!  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析[未登錄] 2008-04-11 16:55 TY

    那公司也是真夠土了.  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2008-04-15 00:33 endswel

    后臺機制,其實也不是什么。 他們都是算軟件的MD5碼或者其他一些不可逆的算法。 不過對于大軟件的MD5碼,你會算死的。
    不過也有解決方案。 截取你對軟件的部分信息。 取軟件的3~5段來進行計算。  回復(fù)  更多評論   

    # 你好 2008-07-06 11:23 landwang

    你好,最近在做一個項目。用到斷點續(xù)傳方面的東西,也在研究。希望和你探討一下。huliqing@live.com是你msn地址嗎?
    我的msn:landwang2001@hotmail.com  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2008-08-16 07:14 pig

    樓主考慮過網(wǎng)絡(luò)斷開以后又恢復(fù)會出現(xiàn)什么情況嗎?期待答復(fù)......  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2009-07-24 13:16 liouxiao

    現(xiàn)在百度的mp3搜索頁面改了,不是在<a href="...">中直接給出下載鏈接,導(dǎo)致工具無法抓取到有用的下載地址。

    可以使用Mozilla的Javascript庫Rhino執(zhí)行頁面里內(nèi)嵌的Javascript代碼,得到最終的下載地址。需要改動的類是biz.tbuy.huliqing.jloading.ext.mp3.CodeFilter,改動的方法是getMp3Address

    具體代碼已經(jīng)發(fā)給你的郵箱了。  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2009-07-25 15:56 huliqing

    @liouxiao
    謝謝.已經(jīng)收到郵件  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2009-08-30 10:31 BLOVE

    博主,你好,我是第一次來能不能把getMp3Address方法代碼再分享下,謝謝.
      回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2009-08-31 10:07 huliqing

    @BLOVE
    參照一下原來的getMp3Address,再比較一下百度現(xiàn)有頁面代碼,應(yīng)該很快可以寫出來,或者聯(lián)系一下上面的liouxiao吧,已經(jīng)有很長一段時間沒有寫這個軟件,代碼目前還真找不到在哪里了。呵呵!  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2009-12-11 16:19 Moryk

    仔細(xì)看看,也是老帖了.想問樓主
    這樣會不會耗費服務(wù)器資源呢?多線程下載開多個SOCKET連接DNS,會影響很大的吧.  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析[未登錄] 2010-05-25 10:35 M

    你好。。能發(fā)個demo給我學(xué)習(xí)學(xué)習(xí)嗎?
    myx8178633@163.com
    謝了。。  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2012-01-09 17:11 VARCHAR

    有這個demo沒有 發(fā)一個吧 謝謝 QQ:874729211  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2012-03-22 14:41 zhagnming

    畢業(yè)設(shè)計和你這個有關(guān)系 不錯 參考一下 很好  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析[未登錄] 2013-04-06 15:31 小天

    尼瑪,你程序不能用呢,我 win7
    java version "1.7.0_09"
    Java(TM) SE Runtime Environment (build 1.7.0_09-b05)
    Java HotSpot(TM) 64-Bit Server VM (build 23.5-b02, mixed mode)  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2013-04-18 12:56 梁翠怡

    博主您好,最近在做一個項目。用到斷點續(xù)傳方面的東西。希望您能指導(dǎo)一下或發(fā)個完整源碼給我,謝謝您,這是我的郵箱:2565776764@qq.com  回復(fù)  更多評論   

    # re: Http多線程下載與斷點續(xù)傳分析 2013-08-02 10:31 rambo_xue

    怎么搜不到東西  回復(fù)  更多評論   

    導(dǎo)航

    統(tǒng)計

    公告

    文章原創(chuàng),歡迎轉(zhuǎn)載
    ——轉(zhuǎn)載請注明出處及原文鏈接

    隨筆分類(60)

    隨筆檔案(33)

    最新評論

    評論排行榜

    主站蜘蛛池模板: 国产日产亚洲系列| 亚洲人成在线播放| 亚洲精品国产精品乱码不卡| 亚洲乳大丰满中文字幕| 亚洲永久在线观看| 黄色网址在线免费| xvideos亚洲永久网址| 亚洲性一级理论片在线观看| 好吊色永久免费视频大全 | 亚洲成a人片在线观看老师| 亚洲国产女人aaa毛片在线 | 亚洲风情亚Aⅴ在线发布| 91精品国产免费网站| 亚洲成a人片在线观看国产| 搜日本一区二区三区免费高清视频 | 亚洲人成伊人成综合网久久久| 永久免费无码日韩视频| 亚洲中文久久精品无码ww16| 免费看成人AA片无码视频吃奶| 日本免费v片一二三区| 亚洲国产精品乱码在线观看97| 91黑丝国产线观看免费| 亚洲色偷偷偷鲁综合| 日本视频在线观看永久免费| 亚洲国产av无码精品| 国产午夜无码片免费| 亚洲无码黄色网址| 老子影院午夜伦不卡亚洲| 成年女人毛片免费播放人| 久久精品国产亚洲av影院| 免费国产成人18在线观看| 亚洲精品国产福利片| 最近免费中文字幕大全高清大全1| 亚洲另类小说图片| 亚洲成a人在线看天堂无码| 国产免费A∨在线播放| 亚洲高清中文字幕综合网| 精品无码人妻一区二区免费蜜桃| 亚洲一级免费毛片| 青青青免费国产在线视频小草| 精品亚洲A∨无码一区二区三区|