亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 1750 | 回復(fù): 1
打印 上一主題 下一主題

斷點(diǎn)續(xù)傳和下載原理分析 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2011-12-07 16:35 |只看該作者 |倒序?yàn)g覽
斷點(diǎn)續(xù)傳和下載原理分析










最近做一個(gè)文件上傳和下載的應(yīng)用對文件上傳和下載進(jìn)行了一個(gè)完整的流程分析

以來是方便自己對文件上傳和下載的理解,而來便于團(tuán)隊(duì)內(nèi)部的分享

故而做了幾張圖,將整體的流程都畫下來,便于大家的理解和分析,如果有不完善的地方希望

大家多提意見,

由于參考了網(wǎng)上許多的資料,特此感謝



首先是文件上傳,這個(gè)要用到服務(wù)器




關(guān)鍵代碼:


FileServer.java


Java代碼
  1. 1.import java.io.File;   
  2. 2.import java.io.FileInputStream;   
  3. 3.import java.io.FileOutputStream;   
  4. 4.import java.io.IOException;   
  5. 5.import java.io.InputStream;   
  6. 6.import java.io.OutputStream;   
  7. 7.import java.io.PushbackInputStream;   
  8. 8.import java.io.RandomAccessFile;   
  9. 9.import java.net.ServerSocket;   
  10. 10.import java.net.Socket;   
  11. 11.import java.text.SimpleDateFormat;   
  12. 12.import java.util.Date;   
  13. 13.import java.util.HashMap;   
  14. 14.import java.util.Map;   
  15. 15.import java.util.Properties;   
  16. 16.import java.util.Set;   
  17. 17.import java.util.concurrent.ExecutorService;   
  18. 18.import java.util.concurrent.Executors;   
  19. 19.  
  20. 20.import util.FileLogInfo;   
  21. 21.import util.StreamTool;   
  22. 22.  
  23. 23.  
  24. 24.  
  25. 25.public class FileServer {   
  26. 26.     private ExecutorService executorService;//線程池   
  27. 27.     private int port;//監(jiān)聽端口   
  28. 28.     private boolean quit = false;//退出   
  29. 29.     private ServerSocket server;   
  30. 30.     private Map<Long, FileLogInfo> datas = new HashMap<Long, FileLogInfo>();//存放斷點(diǎn)數(shù)據(jù),以后改為數(shù)據(jù)庫存放   
  31. 31.     public FileServer(int port)   
  32. 32.     {   
  33. 33.         this.port = port;   
  34. 34.         //創(chuàng)建線程池,池中具有(cpu個(gè)數(shù)*50)條線程   
  35. 35.         executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 50);   
  36. 36.     }   
  37. 37.        
  38. 38.    /**  
  39. 39.      * 退出  
  40. 40.      */  
  41. 41.     public void quit()   
  42. 42.     {   
  43. 43.        this.quit = true;   
  44. 44.        try   
  45. 45.        {   
  46. 46.            server.close();   
  47. 47.        }catch (IOException e)   
  48. 48.        {   
  49. 49.            e.printStackTrace();   
  50. 50.        }   
  51. 51.     }   
  52. 52.        
  53. 53.     /**  
  54. 54.      * 啟動服務(wù)  
  55. 55.      * @throws Exception  
  56. 56.      */  
  57. 57.     public void start() throws Exception   
  58. 58.     {   
  59. 59.         server = new ServerSocket(port);//實(shí)現(xiàn)端口監(jiān)聽   
  60. 60.         while(!quit)   
  61. 61.         {   
  62. 62.             try   
  63. 63.             {   
  64. 64.               Socket socket = server.accept();   
  65. 65.               executorService.execute(new SocketTask(socket));//為支持多用戶并發(fā)訪問,采用線程池管理每一個(gè)用戶的連接請求   
  66. 66.             }catch (Exception e)   
  67. 67.             {   
  68. 68.                 e.printStackTrace();   
  69. 69.             }   
  70. 70.         }   
  71. 71.     }   
  72. 72.        
  73. 73.     private final class SocketTask implements Runnable   
  74. 74.     {   
  75. 75.        private Socket socket = null;   
  76. 76.        public SocketTask(Socket socket)   
  77. 77.        {   
  78. 78.            this.socket = socket;   
  79. 79.        }   
  80. 80.        @Override  
  81. 81.        public void run()   
  82. 82.        {   
  83. 83.            try   
  84. 84.            {   
  85. 85.                System.out.println("FileServer accepted connection "+ socket.getInetAddress()+ ":"+ socket.getPort());   
  86. 86.                //得到客戶端發(fā)來的第一行協(xié)議數(shù)據(jù):Content-Length=143253434;filename=xxx.3gp;sourceid=   
  87. 87.                //如果用戶初次上傳文件,sourceid的值為空。   
  88. 88.                InputStream inStream = socket.getInputStream();   
  89. 89.                String head = StreamTool.readLine(inStream);   
  90. 90.                System.out.println("FileServer head:"+head);   
  91. 91.                if(head!=null)   
  92. 92.                {   
  93. 93.                    //下面從協(xié)議數(shù)據(jù)中提取各項(xiàng)參數(shù)值   
  94. 94.                    String[] items = head.split(";");   
  95. 95.                    String filelength = items[0].substring(items[0].indexOf("=")+1);   
  96. 96.                    String filename = items[1].substring(items[1].indexOf("=")+1);   
  97. 97.                    String sourceid = items[2].substring(items[2].indexOf("=")+1);         
  98. 98.                    //生成資源id,如果需要唯一性,可以采用UUID   
  99. 99.                    long id = System.currentTimeMillis();   
  100. 100.                    FileLogInfo log = null;   
  101. 101.                    if(sourceid!=null && !"".equals(sourceid))   
  102. 102.                    {   
  103. 103.                        id = Long.valueOf(sourceid);   
  104. 104.                        //查找上傳的文件是否存在上傳記錄   
  105. 105.                        log = find(id);   
  106. 106.                    }   
  107. 107.                    File file = null;   
  108. 108.                    int position = 0;   
  109. 109.                    //如果上傳的文件不存在上傳記錄,為文件添加跟蹤記錄   
  110. 110.                    if(log==null)   
  111. 111.                    {   
  112. 112.                        //設(shè)置存放的位置與當(dāng)前應(yīng)用的位置有關(guān)   
  113. 113.                        File dir = new File("c:/temp/");   
  114. 114.                        if(!dir.exists()) dir.mkdirs();   
  115. 115.                        file = new File(dir, filename);   
  116. 116.                        //如果上傳的文件發(fā)生重名,然后進(jìn)行改名   
  117. 117.                        if(file.exists())   
  118. 118.                        {   
  119. 119.                            filename = filename.substring(0, filename.indexOf(".")-1)+ dir.listFiles().length+ filename.substring(filename.indexOf("."));   
  120. 120.                            file = new File(dir, filename);   
  121. 121.                        }   
  122. 122.                        save(id, file);   
  123. 123.                    }   
  124. 124.                    // 如果上傳的文件存在上傳記錄,讀取上次的斷點(diǎn)位置   
  125. 125.                    else  
  126. 126.                    {   
  127. 127.                        System.out.println("FileServer have exits log not null");   
  128. 128.                        //從上傳記錄中得到文件的路徑   
  129. 129.                        file = new File(log.getPath());   
  130. 130.                        if(file.exists())   
  131. 131.                        {   
  132. 132.                            File logFile = new File(file.getParentFile(), file.getName()+".log");   
  133. 133.                            if(logFile.exists())   
  134. 134.                            {   
  135. 135.                                Properties properties = new Properties();   
  136. 136.                                properties.load(new FileInputStream(logFile));   
  137. 137.                                //讀取斷點(diǎn)位置   
  138. 138.                                position = Integer.valueOf(properties.getProperty("length"));   
  139. 139.                            }   
  140. 140.                        }   
  141. 141.                    }   
  142. 142.                    //***************************上面是對協(xié)議頭的處理,下面正式接收數(shù)據(jù)***************************************   
  143. 143.                    //向客戶端請求傳輸數(shù)據(jù)   
  144. 144.                    OutputStream outStream = socket.getOutputStream();   
  145. 145.                    String response = "sourceid="+ id+ ";position="+ position+ "%";   
  146. 146.                    //服務(wù)器收到客戶端的請求信息后,給客戶端返回響應(yīng)信息:sourceid=1274773833264;position=position   
  147. 147.                    //sourceid由服務(wù)生成,唯一標(biāo)識上傳的文件,position指示客戶端從文件的什么位置開始上傳   
  148. 148.                    outStream.write(response.getBytes());   
  149. 149.                    RandomAccessFile fileOutStream = new RandomAccessFile(file, "rwd");   
  150. 150.                    //設(shè)置文件長度   
  151. 151.                    if(position==0) fileOutStream.setLength(Integer.valueOf(filelength));   
  152. 152.                    //移動文件指定的位置開始寫入數(shù)據(jù)   
  153. 153.                    fileOutStream.seek(position);   
  154. 154.                    byte[] buffer = new byte[1024];   
  155. 155.                    int len = -1;   
  156. 156.                    int length = position;   
  157. 157.                    //從輸入流中讀取數(shù)據(jù)寫入到文件中,并將已經(jīng)傳入的文件長度寫入配置文件,實(shí)時(shí)記錄文件的最后保存位置   
  158. 158.                    while( (len=inStream.read(buffer)) != -1)   
  159. 159.                    {   
  160. 160.                        fileOutStream.write(buffer, 0, len);   
  161. 161.                        length += len;   
  162. 162.                        Properties properties = new Properties();   
  163. 163.                        properties.put("length", String.valueOf(length));   
  164. 164.                        FileOutputStream logFile = new FileOutputStream(new File(file.getParentFile(), file.getName()+".log"));   
  165. 165.                        //實(shí)時(shí)記錄文件的最后保存位置   
  166. 166.                        properties.store(logFile, null);   
  167. 167.                        logFile.close();   
  168. 168.                    }   
  169. 169.                    //如果長傳長度等于實(shí)際長度則表示長傳成功   
  170. 170.                    if(length==fileOutStream.length()){   
  171. 171.                        delete(id);   
  172. 172.                    }   
  173. 173.                    fileOutStream.close();                     
  174. 174.                    inStream.close();   
  175. 175.                    outStream.close();   
  176. 176.                    file = null;   
  177. 177.                }   
  178. 178.            }   
  179. 179.            catch (Exception e)   
  180. 180.            {   
  181. 181.                e.printStackTrace();   
  182. 182.            }   
  183. 183.            finally{   
  184. 184.                try  
  185. 185.                {   
  186. 186.                    if(socket!=null && !socket.isClosed()) socket.close();   
  187. 187.                }   
  188. 188.                catch (IOException e)   
  189. 189.                {   
  190. 190.                    e.printStackTrace();   
  191. 191.                }   
  192. 192.            }   
  193. 193.        }   
  194. 194.     }   
  195. 195.        
  196. 196.     /**   
  197. 197.      * 查找在記錄中是否有sourceid的文件   
  198. 198.      * @param sourceid   
  199. 199.      * @return  
  200. 200.      */   
  201. 201.     public FileLogInfo find(Long sourceid)   
  202. 202.     {   
  203. 203.         return datas.get(sourceid);   
  204. 204.     }   
  205. 205.        
  206. 206.     /**  
  207. 207.      * 保存上傳記錄,日后可以改成通過數(shù)據(jù)庫存放  
  208. 208.      * @param id  
  209. 209.      * @param saveFile  
  210. 210.      */  
  211. 211.     public void save(Long id, File saveFile)   
  212. 212.     {   
  213. 213.         System.out.println("save logfile "+id);   
  214. 214.         datas.put(id, new FileLogInfo(id, saveFile.getAbsolutePath()));   
  215. 215.     }   
  216. 216.        
  217. 217.     /**  
  218. 218.      * 當(dāng)文件上傳完畢,刪除記錄  
  219. 219.      * @param sourceid  
  220. 220.      */  
  221. 221.     public void delete(long sourceid)   
  222. 222.     {   
  223. 223.         System.out.println("delete logfile "+sourceid);   
  224. 224.         if(datas.containsKey(sourceid)) datas.remove(sourceid);   
  225. 225.     }   
  226. 226.        
  227. 227.}  
  228. import java.io.File;
  229. import java.io.FileInputStream;
  230. import java.io.FileOutputStream;
  231. import java.io.IOException;
  232. import java.io.InputStream;
  233. import java.io.OutputStream;
  234. import java.io.PushbackInputStream;
  235. import java.io.RandomAccessFile;
  236. import java.net.ServerSocket;
  237. import java.net.Socket;
  238. import java.text.SimpleDateFormat;
  239. import java.util.Date;
  240. import java.util.HashMap;
  241. import java.util.Map;
  242. import java.util.Properties;
  243. import java.util.Set;
  244. import java.util.concurrent.ExecutorService;
  245. import java.util.concurrent.Executors;

  246. import util.FileLogInfo;
  247. import util.StreamTool;



  248. public class FileServer {
  249.          private ExecutorService executorService;//線程池
  250.          private int port;//監(jiān)聽端口
  251.          private boolean quit = false;//退出
  252.          private ServerSocket server;
  253.          private Map<Long, FileLogInfo> datas = new HashMap<Long, FileLogInfo>();//存放斷點(diǎn)數(shù)據(jù),以后改為數(shù)據(jù)庫存放
  254.          public FileServer(int port)
  255.          {
  256.                  this.port = port;
  257.                  //創(chuàng)建線程池,池中具有(cpu個(gè)數(shù)*50)條線程
  258.                  executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 50);
  259.          }
  260.          
  261.         /**
  262.           * 退出
  263.           */
  264.          public void quit()
  265.          {
  266.                 this.quit = true;
  267.                 try
  268.                 {
  269.                         server.close();
  270.                 }catch (IOException e)
  271.                 {
  272.                         e.printStackTrace();
  273.                 }
  274.          }
  275.          
  276.          /**
  277.           * 啟動服務(wù)
  278.           * @throws Exception
  279.           */
  280.          public void start() throws Exception
  281.          {
  282.                  server = new ServerSocket(port);//實(shí)現(xiàn)端口監(jiān)聽
  283.                  while(!quit)
  284.                  {
  285.                  try
  286.                  {
  287.                    Socket socket = server.accept();
  288.                    executorService.execute(new SocketTask(socket));//為支持多用戶并發(fā)訪問,采用線程池管理每一個(gè)用戶的連接請求
  289.                  }catch (Exception e)
  290.                  {
  291.                      e.printStackTrace();
  292.                  }
  293.              }
  294.          }
  295.          
  296.          private final class SocketTask implements Runnable
  297.          {
  298.                 private Socket socket = null;
  299.                 public SocketTask(Socket socket)
  300.                 {
  301.                         this.socket = socket;
  302.                 }
  303.                 @Override
  304.                 public void run()
  305.                 {
  306.                         try
  307.                         {
  308.                                 System.out.println("FileServer accepted connection "+ socket.getInetAddress()+ ":"+ socket.getPort());
  309.                                 //得到客戶端發(fā)來的第一行協(xié)議數(shù)據(jù):Content-Length=143253434;filename=xxx.3gp;sourceid=
  310.                                 //如果用戶初次上傳文件,sourceid的值為空。
  311.                                 InputStream inStream = socket.getInputStream();
  312.                                 String head = StreamTool.readLine(inStream);
  313.                                 System.out.println("FileServer head:"+head);
  314.                                 if(head!=null)
  315.                                 {
  316.                                         //下面從協(xié)議數(shù)據(jù)中提取各項(xiàng)參數(shù)值
  317.                                         String[] items = head.split(";");
  318.                                         String filelength = items[0].substring(items[0].indexOf("=")+1);
  319.                                         String filename = items[1].substring(items[1].indexOf("=")+1);
  320.                                         String sourceid = items[2].substring(items[2].indexOf("=")+1);               
  321.                                         //生成資源id,如果需要唯一性,可以采用UUID
  322.                                         long id = System.currentTimeMillis();
  323.                                         FileLogInfo log = null;
  324.                                         if(sourceid!=null && !"".equals(sourceid))
  325.                                         {
  326.                                                 id = Long.valueOf(sourceid);
  327.                                                 //查找上傳的文件是否存在上傳記錄
  328.                                                 log = find(id);
  329.                                         }
  330.                                         File file = null;
  331.                                         int position = 0;
  332.                                         //如果上傳的文件不存在上傳記錄,為文件添加跟蹤記錄
  333.                                         if(log==null)
  334.                                         {
  335.                                                 //設(shè)置存放的位置與當(dāng)前應(yīng)用的位置有關(guān)
  336.                                                 File dir = new File("c:/temp/");
  337.                                                 if(!dir.exists()) dir.mkdirs();
  338.                                                 file = new File(dir, filename);
  339.                                                 //如果上傳的文件發(fā)生重名,然后進(jìn)行改名
  340.                                                 if(file.exists())
  341.                                                 {
  342.                                                         filename = filename.substring(0, filename.indexOf(".")-1)+ dir.listFiles().length+ filename.substring(filename.indexOf("."));
  343.                                                         file = new File(dir, filename);
  344.                                                 }
  345.                                                 save(id, file);
  346.                                         }
  347.                                         // 如果上傳的文件存在上傳記錄,讀取上次的斷點(diǎn)位置
  348.                                         else
  349.                                         {
  350.                                                 System.out.println("FileServer have exits log not null");
  351.                                                 //從上傳記錄中得到文件的路徑
  352.                                                 file = new File(log.getPath());
  353.                                                 if(file.exists())
  354.                                                 {
  355.                                                         File logFile = new File(file.getParentFile(), file.getName()+".log");
  356.                                                         if(logFile.exists())
  357.                                                         {
  358.                                                                 Properties properties = new Properties();
  359.                                                                 properties.load(new FileInputStream(logFile));
  360.                                                                 //讀取斷點(diǎn)位置
  361.                                                                 position = Integer.valueOf(properties.getProperty("length"));
  362.                                                         }
  363.                                                 }
  364.                                         }
  365.                                         //***************************上面是對協(xié)議頭的處理,下面正式接收數(shù)據(jù)***************************************
  366.                                         //向客戶端請求傳輸數(shù)據(jù)
  367.                                         OutputStream outStream = socket.getOutputStream();
  368.                                         String response = "sourceid="+ id+ ";position="+ position+ "%";
  369.                                         //服務(wù)器收到客戶端的請求信息后,給客戶端返回響應(yīng)信息:sourceid=1274773833264;position=position
  370.                                         //sourceid由服務(wù)生成,唯一標(biāo)識上傳的文件,position指示客戶端從文件的什么位置開始上傳
  371.                                         outStream.write(response.getBytes());
  372.                                         RandomAccessFile fileOutStream = new RandomAccessFile(file, "rwd");
  373.                                         //設(shè)置文件長度
  374.                                         if(position==0) fileOutStream.setLength(Integer.valueOf(filelength));
  375.                                         //移動文件指定的位置開始寫入數(shù)據(jù)
  376.                                         fileOutStream.seek(position);
  377.                                         byte[] buffer = new byte[1024];
  378.                                         int len = -1;
  379.                                         int length = position;
  380.                                         //從輸入流中讀取數(shù)據(jù)寫入到文件中,并將已經(jīng)傳入的文件長度寫入配置文件,實(shí)時(shí)記錄文件的最后保存位置
  381.                                         while( (len=inStream.read(buffer)) != -1)
  382.                                         {
  383.                                                 fileOutStream.write(buffer, 0, len);
  384.                                                 length += len;
  385.                                                 Properties properties = new Properties();
  386.                                                 properties.put("length", String.valueOf(length));
  387.                                                 FileOutputStream logFile = new FileOutputStream(new File(file.getParentFile(), file.getName()+".log"));
  388.                                                 //實(shí)時(shí)記錄文件的最后保存位置
  389.                                                 properties.store(logFile, null);
  390.                                                 logFile.close();
  391.                                         }
  392.                                         //如果長傳長度等于實(shí)際長度則表示長傳成功
  393.                                         if(length==fileOutStream.length()){
  394.                                                 delete(id);
  395.                                         }
  396.                                         fileOutStream.close();                                       
  397.                                         inStream.close();
  398.                                         outStream.close();
  399.                                         file = null;
  400.                                 }
  401.                         }
  402.                         catch (Exception e)
  403.                         {
  404.                                 e.printStackTrace();
  405.                         }
  406.                         finally{
  407.                     try
  408.                     {
  409.                         if(socket!=null && !socket.isClosed()) socket.close();
  410.                     }
  411.                     catch (IOException e)
  412.                     {
  413.                             e.printStackTrace();
  414.                     }
  415.                 }
  416.                 }
  417.          }
  418.          
  419.          /**
  420.           * 查找在記錄中是否有sourceid的文件
  421.           * @param sourceid
  422.           * @return
  423.           */
  424.          public FileLogInfo find(Long sourceid)
  425.          {
  426.                  return datas.get(sourceid);
  427.          }
  428.          
  429.          /**
  430.           * 保存上傳記錄,日后可以改成通過數(shù)據(jù)庫存放
  431.           * @param id
  432.           * @param saveFile
  433.           */
  434.          public void save(Long id, File saveFile)
  435.          {
  436.                  System.out.println("save logfile "+id);
  437.                  datas.put(id, new FileLogInfo(id, saveFile.getAbsolutePath()));
  438.          }
  439.          
  440.          /**
  441.           * 當(dāng)文件上傳完畢,刪除記錄
  442.           * @param sourceid
  443.           */
  444.          public void delete(long sourceid)
  445.          {
  446.                  System.out.println("delete logfile "+sourceid);
  447.                  if(datas.containsKey(sourceid)) datas.remove(sourceid);
  448.          }
  449.          
  450. }
復(fù)制代碼
由于在上面的流程圖中已經(jīng)進(jìn)行了詳細(xì)的分析,我在這兒就不講了,只是在存儲數(shù)據(jù)的時(shí)候服務(wù)器沒有用數(shù)據(jù)庫去存儲,這兒只是為了方便,所以要想測試斷點(diǎn)上傳,服務(wù)器是不能停的,否則數(shù)據(jù)就沒有了,在以后改進(jìn)的時(shí)候應(yīng)該用數(shù)據(jù)庫去存儲數(shù)據(jù)。

文件上傳客戶端:

3.jpg (34.38 KB, 下載次數(shù): 3)

3.jpg

1.jpg (40.37 KB, 下載次數(shù): 2)

1.jpg

2.jpg (38.92 KB, 下載次數(shù): 3)

2.jpg

3.jpg (34.38 KB, 下載次數(shù): 3)

3.jpg

論壇徽章:
0
2 [報(bào)告]
發(fā)表于 2011-12-23 22:43 |只看該作者
謝謝分享  希望于樓主多多交流
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP