基于HTTP协议的多线程下载he断点续传的实现
Android下使用Http协议实现多线程断点续传下载
0.使用多线程下载会提升文件下载的速度,那么多线程下载文件的过程是:(1)首先获得下载文件的长度,然后设置本地文件的长度HttpURLConnection.getContentLength();RandomAccessFile file = new RandomAccessFile("QQWubiSetup.exe","rwd");file.setLength(filesize);//设置本地文件的长度(2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置。
如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如下图所示。
例如10M大小,使用3个线程来下载,线程下载的数据长度 (10%3 == 0 ? 10/3:10/3+1) ,第1,2个线程下载长度是4M,第三个线程下载长度为2M下载开始位置:线程id*每条线程下载的数据长度 = ?下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?(3)使用Http的Range头字段指定每条线程从文件的什么位置开始下载,下载到什么位置为止,如:指定从文件的2M位置开始下载,下载到位置(4M-1byte)为止代码如下:HttpURLConnection.setRequestProperty("Range","bytes=2097152-4194303");(4)保存文件,使用RandomAccessFile类指定每条线程从本地文件的什么位置开始写入数据。
RandomAccessFile threadfile = new RandomAccessFile("QQWubiSetup.exe ","rwd");threadfile.seek(2097152);//从文件的什么位置开始写入数据1.多线程下载的核心代码示例Java代码1.public class MulThreadDownload2.{3. /**4. * 多线程下载5. * @param args6. */7. public static void main(String[] args)8. {9. String path = "/QQWubiSetup.exe";10. try11. {12. new MulThreadDownload().download(path, 3);13. }14. catch (Exception e)15. {16. e.printStackTrace();17. }18. }19. /**20. * 从路径中获取文件名称21. * @param path 下载路径22. * @return23. */24. public static String getFilename(String path)25. {26. return path.substring(stIndexOf('/')+1);27. }28. /**29. * 下载文件30. * @param path 下载路径31. * @param threadsize 线程数32. */33. public void download(String path, int threadsize) throwsException34. {35. URL url = new URL(path);36. HttpURLConnection conn = (HttpURLConnection)url.openConnection();37. conn.setRequestMethod("GET");38. conn.setConnectTimeout(5 * 1000);39. //获取要下载的文件的长度40. int filelength = conn.getContentLength();41. //从路径中获取文件名称42. String filename = getFilename(path);43. File saveFile = new File(filename);44. RandomAccessFile accessFile = new RandomAccessFile(saveFile, "rwd");45. //设置本地文件的长度和下载文件相同46. accessFile.setLength(filelength);47. accessFile.close();48. //计算每条线程下载的数据长度49. int block = filelength%threadsize==0? filelength/threadsize : filelength/threadsize+1;50. for(int threadid=0 ; threadid < threadsize ; threadid++){51. new DownloadThread(url, saveFile, block, threadid).start();52. }53. }54.55. private final class DownloadThread extends Thread56. {57. private URL url;58. private File saveFile;59. private int block;//每条线程下载的数据长度60. private int threadid;//线程id61. public DownloadThread(URL url, File saveFile, int block, int threadid)62. {63. this.url = url;64. this.saveFile = saveFile;65. this.block = block;66. this.threadid = threadid;67. }68.@Override69. public void run()70. {71. //计算开始位置公式:线程id*每条线程下载的数据长度= ?72. //计算结束位置公式:(线程id +1)*每条线程下载的数据长度-1 =?73. int startposition = threadid * block;74. int endposition = (threadid + 1 ) * block - 1;75. try76. {77. RandomAccessFile accessFile = new RandomAccessFile(saveFile, "rwd");78. //设置从什么位置开始写入数据79. accessFile.seek(startposition);80. HttpURLConnection conn = (HttpURLConnection)url.openConnection();81. conn.setRequestMethod("GET");82. conn.setConnectTimeout(5 * 1000);83. conn.setRequestProperty("Range", "bytes="+ startposition+ "-"+ endposition);84. InputStream inStream = conn.getInputStream();85. byte[] buffer = new byte[1024];86. int len = 0;87. while( (len=inStream.read(buffer)) != -1 )88. {89. accessFile.write(buffer, 0, len);90. }91. inStream.close();92. accessFile.close();93. System.out.println("线程id:"+ threadid+ "下载完成");94. }95. catch (Exception e)96. {97. e.printStackTrace();98. }99. }100. }101.}2.多线程断点下载功能,这里把断点数据保存到数据库中:注意代码注释的理解(0)主Activity,关键点使用Handler更新进度条与开启线程下载避免ANR若不使用Handler却要立即更新进度条数据,可使用://resultView.invalidate(); UI线程中立即更新进度条方法//resultView.postInvalidate(); 非UI线程中立即更新进度条方法Java代码1./**2. * 注意这里的设计思路,UI线程与参数保存问题,避免ANR问题,UI控件的显示3. * @author kay4. *5. */6.public class DownloadActivity extends Activity7.{8. private EditText downloadpathText;9. private TextView resultView;10. private ProgressBar progressBar;11.12.@Override13. public void onCreate(Bundle savedInstanceState)14. {15. super.onCreate(savedInstanceState);16. setContentView(yout.main);17.18. downloadpathText = (EditText) this.findViewById(R.id.downloadpath);19. progressBar = (ProgressBar) this.findViewById(R.id.downloadbar);20. resultView = (TextView) this.findViewById(R.id.result);21. Button button = (Button) this.findViewById(R.id.button);22. button.setOnClickListener(new View.OnClickListener()23. {24.@Override25. public void onClick(View v)26. {27. //取得下载路径28. String path = downloadpathText.getText().toString();29. //判断SDCard是否存在30. if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))31. {32. //下载操作33. download(path, Environment.getExternalStorageDirectory());34. }35. else36. {37. Toast.makeText(DownloadActivity.this, R.string.sdcarderror, 1).show();38. }39. }40. });41. }42. //主线程(UI线程)43. //业务逻辑正确,但是该程序运行的时候有问题(可能出现ANR问题)44. //对于显示控件的界面更新只是由UI线程负责,如果是在非UI线程更新控件的属性值,更新后的显示界面不会反映到屏幕上45. /**46. * 参数类型:因为启动一个线程还需要使用到上面方法的参数,而主方法启动后很快就会销毁,47. * 那么使用Final可以解决参数丢失的问题48. * path 注意是Final类型49. * savedir 注意是Final类型50. */51. private void download(final String path, final File savedir)52. {53. //这里开启一个线程避免ANR错误54. new Thread(new Runnable()55. {56.@Override57. public void run()58. {59. FileDownloader loader = new FileDownloader(DownloadActivity.this, path, savedir, 3);60. //设置进度条的最大刻度为文件的长度61. progressBar.setMax(loader.getFileSize());62. try63. {64. loader.download(new DownloadProgressListener()65. {66. /**67. * 注意这里的设计,显示进度条数据需要使用Handler来处理68. * 因为非UI线程更新后的数据不能被刷新69. */70.@Override71. public void onDownloadSize(int size)72. {73. //实时获知文件已经下载的数据长度74. Message msg = new Message();75. //设置消息标签76. msg.what = 1;77. msg.getData().putInt("size", size);78. //使用Handler对象发送消息79. handler.sendMessage(msg);80. }81. });82. }83. catch (Exception e)84. {85. //发送一个空消息到消息队列86. handler.obtainMessage(-1).sendToTarget();87. /**88. * 或者使用下面的方法发送一个空消息89. * Message msg = new Message();90. * msg.what = 1;91. * handler.sendMessage(msg);92. */93. }94. }95. }).start();96. }97.98.99. /**Handler原理:当Handler被创建时会关联到创建它的当前线程的消息队列,该类用于往消息队列发送消息100. *101. * 消息队列中的消息由当前线程内部进行处理102. */103. private Handler handler = new Handler()104. {105. //重写Handler里面的handleMessage方法处理消息106.@Override107. public void handleMessage(Message msg)108. {109. switch (msg.what)110. {111. case 1:112. //进度条显示113. progressBar.setProgress(msg.getData().getInt("size"));114. float num = (float)progressBar.getProg ress()/(float)progressBar.getMax();115. int result = (int)(num*100);116. //resultView.invalidate(); UI线程中立即更新进度条方法117. //resultView.postInvalidate(); 非UI线程中立即更新进度条方法118. resultView.setText(result+ "%"); 119. //判断是否下载成功120. if(progressBar.getProgress()==progress Bar.getMax())121. {122. Toast.makeText(DownloadActivity.th is, R.string.success, 1).show();123. }124. break;125. case -1:126. Toast.makeText(DownloadActivity.this, R.string.error, 1).show();127. break;128. }129. }130. };131.132.}(1)下载类:注意计算每条线程的下载长度与下载起始位置的方法Java代码1.public class DownloadThread extends Thread2.{3. private static final String TAG = "DownloadThread";4. private File saveFile;5. private URL downUrl;6. private int block;7. //下载开始位置8. private int threadId = -1;9. //下载文件长度10. private int downLength;11. private boolean finish = false;12. private FileDownloader downloader;13. public DownloadThread(FileDownloader downloader, URL downUrl, File saveFile, int block, int downLength, int threadId)14. {15. this.downUrl = downUrl;16. this.saveFile = saveFile;17. this.block = block;18. this.downloader = downloader;19. this.threadId = threadId;20. this.downLength = downLength;21. }22.23.@Override24. public void run()25. {26. //未下载完成27. if(downLength < block)28. {29. try30. {31. HttpURLConnection http = (HttpURLConnection)downUrl.openConnection();32. http.setConnectTimeout(5 * 1000);33. http.setRequestMethod("GET");34. http.setRequestProperty("Accept", "image/gif,image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave -flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, applicati on/vnd.ms-excel, application/vnd.ms-powerpoint, application/ms word, */*");35. http.setRequestProperty("Accept-Language", "zh-CN");36. http.setRequestProperty("Referer", downUrl.toString());37. http.setRequestProperty("Charset", "UTF-8");38. //下载开始位置:线程id*每条线程下载的数据长度 = ?39. int startPos = block * (threadId - 1) + downLength;40. //下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?41. int endPos = block * threadId -1;42. //设置获取实体数据的范围43. http.setRequestProperty("Range", "bytes=" + startPos + "-"+ endPos);44. http.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");45. http.setRequestProperty("Connection", "Keep-Alive");46.47. InputStream inStream = http.getInputStream();48. byte[] buffer = new byte[1024];49. int offset = 0;50. print("Thread " + this.threadId + " start download from position "+ startPos);51. RandomAccessFile threadfile = new RandomAccessFile(this.saveFile, "rwd");52. threadfile.seek(startPos);53. while ((offset = inStream.read(buffer, 0, 1024)) != -1)54. {55. threadfile.write(buffer, 0, offset);56. downLength += offset;57. downloader.update(this.threadId, downLength);58. downloader.append(offset);59. }60. threadfile.close();61. inStream.close();62. print("Thread " + this.threadId + " downloadfinish");63. //标记是否完成64. this.finish = true;65. }66. catch (Exception e)67. {68. this.downLength = -1;69. print("Thread "+ this.threadId+ ":"+ e);70. }71. }72. }73.74. private static void print(String msg)75. {76. Log.i(TAG, msg);77. }78.79. /**80. * 下载是否完成81. * @return82. */83. public boolean isFinish()84. {85. return finish;86. }87.88. /**89. * 已经下载的内容大小90. * @return 如果返回值为-1,代表下载失败91. */92. public long getDownLength()93. {94. return downLength;95. }96.}文件下载器,使用Java代码1./**2. * 文件下载器,使用这个类的方法如下示例:3. * FileDownloader loader = new FileDownloader(context, "http:///ejb3/ActivePort.exe",4. * new File("D:\\androidsoft\\test"), 2);5. * loader.getFileSize();//得到文件总大小6. * try {7. * loader.download(new DownloadProgressListener(){8. * public void onDownloadSize(int size) {9. * print("已经下载:"+ size);10. * }11. * });12. * }13. * catch (Exception e)14. * {15. * e.printStackTrace();16. * }17. */18.public class FileDownloader19.{20. private static final String TAG = "FileDownloader";21. private Context context;22. private FileService fileService;23. //已下载文件长度24. private int downloadSize = 0;25. //原始文件长度26. private int fileSize = 0;27. ///线程数28. private DownloadThread[] threads;29. //本地保存文件30. private File saveFile;31. //缓存各线程下载的长度32. private Map<Integer, Integer> data = new ConcurrentHashMap<Integer, Integer>();33. //每条线程下载的长度34. private int block;35. //下载路径36. private String downloadUrl;37. //获取线程数38. public int getThreadSize()39. {40. return threads.length;41. }42. /**43. * 获取文件大小44. * @return45. */46. public int getFileSize()47. {48. return fileSize;49. }50. /**51. * 累计已下载大小52. * @param size53. */54. protected synchronized void append(int size)55. {56. downloadSize += size;57. }58. /**59. * 更新指定线程最后下载的位置60. * @param threadId 线程id61. * @param pos 最后下载的位置62. */63. protected synchronized void update(int threadId, int pos)64. {65. this.data.put(threadId, pos);66. this.fileService.update(this.downloadUrl, this.data);67. }68. /**69. * 文件下载构造器70. * @param downloadUrl 下载路径71. * @param fileSaveDir 文件保存目录72. * @param threadNum 下载线程数73. */74. public FileDownloader(Context context, String downloadUrl, File fileSaveDir, int threadNum)75. {76. try77. {78. this.context = context;79. this.downloadUrl = downloadUrl;80. fileService = new FileService(this.context);81. URL url = new URL(this.downloadUrl);82. if(!fileSaveDir.exists()) fileSaveDir.mkdirs();83. this.threads = new DownloadThread[threadNum];84. HttpURLConnection conn = (HttpURLConnection) url.openConnection();85. conn.setConnectTimeout(5*1000);86. conn.setRequestMethod("GET");87. conn.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-fla sh, application/xaml+xml, application/vnd.ms-xpsdocument, appl ication/x-ms-xbap, application/x-ms-application, application/v nd.ms-excel, application/vnd.ms-powerpoint, application/msword , */*");88. conn.setRequestProperty("Accept-Language", "zh-CN");89. conn.setRequestProperty("Referer", downloadUrl);90. conn.setRequestProperty("Charset", "UTF-8");91. conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR1.1.4322; .NET CLR2.0.50727; .NET CLR3.0.04506.30; .NET CLR3.0.4506.2152; .NET CLR 3.5.30729)");92. conn.setRequestProperty("Connection", "Keep-Alive");93. conn.connect();94. printResponseHeader(conn);95. if (conn.getResponseCode()==200)96. {97. //根据响应获取文件大小98. this.fileSize = conn.getContentLength();99. if (this.fileSize <= 0) throw new RuntimeException("Unkown file size ");100. //获取文件名称101. String filename = getFileName(conn); 102. //构建保存文件103. this.saveFile = new File(fileSaveDir, file name);104. //获取下载记录105. Map<Integer, Integer> logdata = fileService.getData(downloadUrl);106. //如果存在下载记录107. if(logdata.size()>0)108. {109. //把各条线程已经下载的数据长度放入data 中110. for(Map.Entry<Integer, Integer> entry : logdata.entrySet())111. data.put(entry.getKey(), entry.get Value());112. }113. //下面计算所有线程已经下载的数据长度114. if(this.data.size()==this.threads.length)115. {116. for (int i = 0; i < this.threads.lengt h; i++)117. {118. this.downloadSize += this.data.get (i+1);119. }120. print("已经下载的长度"+ this.downloadSize);121. }122. //计算每条线程下载的数据长度123. this.block = (this.fileSize % this.threads .length)==0? this.fileSize / this.threads.length : this.fileSi ze / this.threads.length + 1;124. }125. else126. {127. throw new RuntimeException("server no resp onse ");128. }129. }130. catch (Exception e)131. {132. print(e.toString());133. throw new RuntimeException("don't connection t his url");134. }135. }136. /**137. * 获取文件名138. */139. private String getFileName(HttpURLConnection conn) 140. {141. String filename = this.downloadUrl.substring(this.stIndexOf('/') + 1);142. if(filename==null || "".equals(filename.trim())){/ /如果获取不到文件名称143. for (int i = 0;; i++) {144. String mine = conn.getHeaderField(i); 145. if (mine == null) break;146. if("content-disposition".equals(conn.getHe aderFieldKey(i).toLowerCase())){147. Matcher m = pile(".*filenam e=(.*)").matcher(mine.toLowerCase());148. if(m.find()) return m.group(1); 149. }150. }151. filename = UUID.randomUUID()+ ".tmp";//默认取一个文件名152. }153. return filename;154. }155.156. /**157. * 开始下载文件158. * @param listener 监听下载数量的变化,如果不需要了解实时下载的数量,可以设置为null159. * @return 已下载文件大小160. * @throws Exception161. */162. public int download(DownloadProgressListener listener) throws Exception{163. try164. {165. //创建本地文件166. RandomAccessFile randOut = new RandomAccessFil e(this.saveFile, "rw");167. if(this.fileSize>0) randOut.setLength(this.fil eSize);168. randOut.close();169. URL url = new URL(this.downloadUrl);170. if(this.data.size() != this.threads.length) 171. {172. this.data.clear();173. for (int i = 0; i < this.threads.length; i ++)174. {175. //初始化每条线程已经下载的数据长度为176. this.data.put(i+1, 0);177. }178. }179. //开启线程进行下载180. for (int i = 0; i < this.threads.length; i++)181. {182. int downLength = this.data.get(i+1); 183. //判断线程是否已经完成下载,否则继续下载184. if(downLength < this.block && this.downloa dSize<this.fileSize)185. {186. this.threads[i] = new DownloadThread(t his, url, this.saveFile, this.block, this.data.get(i+1), i+1);187. this.threads[i].setPriority(7);//可删除这条188. this.threads[i].start();189. }190. else191. {192. this.threads[i] = null;193. }194. }195. this.fileService.save(this.downloadUrl, this.d ata);196. //下载未完成197. boolean notFinish = true;198. // 循环判断所有线程是否完成下载199. while (notFinish)200. {201. Thread.sleep(900);202. //假定全部线程下载完成203. notFinish = false;204. for (int i = 0; i < this.threads.length; i ++)205. {206. //如果发现线程未完成下载207. if (this.threads[i] != null && !this.t hreads[i].isFinish())208. {209. //设置标志为下载没有完成210. notFinish = true;211. //如果下载失败,再重新下载212. if(this.threads[i].getDownLength() == -1)213. {214. this.threads[i] = new Download Thread(this, url, this.saveFile, this.block, this.data.get(i+1 ), i+1);215. this.threads[i].setPriority(7) ;216. this.threads[i].start(); 217. }218. }219. }220. //通知目前已经下载完成的数据长度221. if(listener!=null) listener.onDownloadSize (this.downloadSize);222. }223. //删除数据库中下载信息224. fileService.delete(this.downloadUrl);225. }226. catch (Exception e)227. {228. print(e.toString());229. throw new Exception("file download fail"); 230. }231. return this.downloadSize;232. }233.234. /**235. * 获取Http响应头字段236. * @param http237. * @return238. */239. public static Map<String, String> getHttpResponseHeade r(HttpURLConnection http) {240. Map<String, String> header = new LinkedHashMap<Str ing, String>();241. for (int i = 0;; i++) {242. String mine = http.getHeaderField(i); 243. if (mine == null) break;244. header.put(http.getHeaderFieldKey(i), mine);245. }246. return header;247. }248. /**249. * 打印Http头字段250. * @param http251. */252. public static void printResponseHeader(HttpURLConnecti on http)253. {254. Map<String, String> header = getHttpResponseHeader (http);255. for(Map.Entry<String, String> entry : header.entry Set())256. {257. String key = entry.getKey()!=null ? entry.getK ey()+ ":" : "";258. print(key+ entry.getValue());259. }260. }261. private static void print(String msg)262. {263. Log.i(TAG, msg);264. }265.}Java代码1.public interface DownloadProgressListener2.{3. public void onDownloadSize(int size);4.}(2)文件操作,断点数据库存储Java代码1.public class DBOpenHelper extends SQLiteOpenHelper2.{3. private static final String DBNAME = "itcast.db";4. private static final int VERSION = 1;5.6. public DBOpenHelper(Context context)7. {8. super(context, DBNAME, null, VERSION);9. }10.11.@Override12. public void onCreate(SQLiteDatabase db)13. {14. db.execSQL("CREATE TABLE IF NOT EXISTS filedownlog (id integer primary key autoincrement, downpath varchar(100), threadid INTEGER, downlength INTEGER)");15. }16.@Override17. public void onUpgrade(SQLiteDatabase db, int oldVersion,int newVersion)18. {19. db.execSQL("DROP TABLE IF EXISTS filedownlog");20. onCreate(db);21. }22.}Java代码1./**2. * 文件下载业务bean3. */4.public class FileService5.{6. private DBOpenHelper openHelper;7. public FileService(Context context)8. {9. openHelper = new DBOpenHelper(context);10. }11. /**12. * 获取每条线程已经下载的文件长度13. * @param path14. * @return15. */16. public Map<Integer, Integer> getData(String path)17. {18. SQLiteDatabase db = openHelper.getReadableDatabase();19. Cursor cursor = db.rawQuery("select threadid, downlength from filedownlog where downpath=?", new String[]{path});20. Map<Integer, Integer> data = new HashMap<Integer, Integer>();21. while(cursor.moveToNext())22. {23. data.put(cursor.getInt(0), cursor.getInt(1));24. }25. cursor.close();26. db.close();27. return data;28. }29. /**30. * 保存每条线程已经下载的文件长度31. * @param path32. * @param map33. */34. public void save(String path, Map<Integer, Integer> map)35. {//int threadid, int position36. SQLiteDatabase db = openHelper.getWritableDatabase();37. db.beginTransaction();38. try39. {40. for(Map.Entry<Integer, Integer> entry : map.entrySet())41. {42. db.execSQL("insert into filedownlog(downpath,threadid, downlength) values(?,?,?)",43. new Object[]{path, entry.getKey(), entry.getValue()});44. }45. db.setTransactionSuccessful();46. }47. finally48. {49. db.endTransaction();50. }51. db.close();52. }53. /**54. * 实时更新每条线程已经下载的文件长度55. * @param path56. * @param map57. */58. public void update(String path, Map<Integer, Integer> map)59. {60. SQLiteDatabase db = openHelper.getWritableDatabase();61. db.beginTransaction();62. try{63. for(Map.Entry<Integer, Integer> entry : map.entrySet()){64. db.execSQL("update filedownlog set downlength=? where downpath=? and threadid=?",65. new Object[]{entry.getValue(), path,entry.getKey()});66. }67. db.setTransactionSuccessful();68. }finally{69. db.endTransaction();70. }71. db.close();72. }73. /**74. * 当文件下载完成后,删除对应的下载记录75. * @param path76. */77. public void delete(String path)78. {79. SQLiteDatabase db = openHelper.getWritableDatabase();80. db.execSQL("delete from filedownlog where downpath=?", new Object[]{path});81. db.close();82. }83.}。
基于多线程的断点续传实现
基于多线程的断点续传实现
周翔;阮世颖
【期刊名称】《电脑知识与技术》
【年(卷),期】2007(000)022
【摘要】网络的不稳定常常造成数据传送的不稳定,为了获得可靠、高效的数据传输,断点续传技术应运而生.本文介绍了所开发的一种基于多线程的文件传输系统,具有断点续传的功能,详细给出了这个系统的设计方案和所用到的关键技术.
【总页数】3页(P1000-1002)
【作者】周翔;阮世颖
【作者单位】南昌大学软件学院,江西南昌,330047;南昌大学医学院,江西南
昌,330006
【正文语种】中文
【中图分类】TP311
【相关文献】
1.用VC实现基于TCP/IP的点对点多线程断点续传 [J], 刘洪旭;徐国天
2.一种基于SIP和MSRP协议实现文件断点续传的方法 [J], 罗有平;周炳然
3.基于多线程的断点续传实现 [J], 周翔;阮世颖
4.基于HTML5大文件断点续传的实现方案 [J], 王莉敏;梁正和;段全锋
5.基于Android平台多线程断点续传技术研究 [J], 石建华;聂文芳;文晓棠
因版权原因,仅展示原文概要,查看原文内容请购买。
[VC++]点对点(P2P)多线程断点续传的实现
fname=zmfile[n].name;
CString tmep;
//初使化文件名
tmep.Format("\\temp\\%s",fname);
//给主函数发消息
CString aaa;
aaa="正在读取 "+fname+" 信息,马上开始下载。。。\n";
AfxGetMainWnd()->SendMessageToDescendants(WM_AGE1,(LPARAM)aaa.GetBuffer(0),1);
aaa.ReleaseBuffer();
//如果文件长度小于0就返回
我写了一个以此为基础的实用程序(网络传圣,包含源代码),可用了基于TCP/IP的电脑上,供大家学习。
实现方法(VC++,基于TCP/IP协议)如下:
仍釆用服务器与客户模式,需分别对其设计与编程。
服务器端较简单,主要就是加入待传文件,监听客户,和传送文件。而那些断点续传的功能,以及文件的管理都放在客户端上。
//发文件消息给主函数
aaa.Format("%s 文件被请求!%s\n",zmfile[fiinfo->fileno].name,nameph[fiinfo->fileno]);
AfxGetMainWnd()->SendMessageToDescendants(WM_AGE1,(LPARAM)aaa.GetBuffer(0),1);
aa.ReleaseBuffer();
DWORD dwthread;
//建立用户线程
::CreateThread(NULL,0,clientthread,(LPVOID)s1,0,&dwthread);
C#实现支持断点续传多线程下载的 Http Web 客户端工具类
Throw,
CancelAll,
Ignore,
Retry
}
/// <summary>
/// 包含 Exception 事件数据的类
/// </summary>
public class ExceptionEventArgs : System.EventArgs
{
private System.Exception _Exception;
private ExceptionActions _ExceptionAction;
private DownLoadState _DownloadState;
public DownLoadState DownloadState
namespace Microshaoft.Utils
{
using System;
using System.IO;
using ;
using System.Text;
using System.Security;
using System.Threading;
{
get
{
return _ExceptionAction;
}
set
{
_ExceptionAction = value;
}
}
internal ExceptionEventArgs(System.Exception e, DownLoadState DownloadState)
this._Position = Position;
this._Data = Data;
this._Length = Length;
web端断点续传研究
假如一个文件有1000个字节,那么其范围就是0-999,则:
Range: bytes=500表示读取该文件的500-999字节,共500字节。 Range: bytes=500-599 表示读取该文件的500-599字节,共100字节。 Range还有其它几种写法,但上面这两种是最常用的,对于断点续传也足矣了。如果HTTP 请求中包含Range字段,那么服务器会返回206(Partial Content),同时HTTP头中也会有一个相 应的Content-Range字段,类似下面的格式: Content-Range: bytes 500-999/1000 Content-Range字段说明服务器返回了文件的某个范围及文件的总长度。这时ContentLength字段就不是整个文件的大小了,而是对应文件这个范围的字节数,这一点一定要注意。
2.应用分析
• 2.1.web端上传下载 • 2.2.客户端上传下载
2.1.web端上传下载
• • • • • • • • • • • • • • • • • • • • • • • • 下载实例 $fname = './MMLDZG.mp3'; $fp = fopen($fname,'rb'); $fsize = filesize($fname); if (isset($_SERVER['HTTP_RANGE']) && ($_SERVER['HTTP_RANGE'] != "") && preg_match("/^bytes=([0-9]+)-$/i", $_SERVER['HTTP_RANGE'], $match) && ($match[1] < $fsize)) { $start = $match[1]; } else { $start = 0; } header("Cache-control: public"); header("Pragma: public"); if ($star > 0) { fseek($fp, $start); ‘ Header("HTTP/1.1 206 Partial Content"); Header("Content-Length: " . ($fsize - $start)); Header("Content-Ranges: bytes" . $start . "-" . ($fsize - 1) . "/" . $fsize); } else { header("Content-Length: $fsize"); Header("Accept-Ranges: bytes"); } header("Content-Type: application/octet-stream"); header("Content-Disposition: attachment;filename=mmdld.mp3"); fpassthru($fp); fclose($fp);
断点续传方案
断点续传方案简介断点续传是指在网络传输过程中,当连接中断或者文件传输中止时,能够从中断处重新开始传输,而不是从头开始。
这样可以提高文件传输的可靠性和传输效率。
在实际应用中,断点续传方案常常用于大文件的上传或下载过程中,以确保用户在网络不稳定的情况下能够顺利完成文件传输,而无需重新开始。
本文将介绍几种常见的断点续传方案,并分析各种方案的优缺点,帮助读者选择适合自己应用场景的方案。
方案一:基于HTTP的断点续传HTTP协议是应用层协议中最常用的协议之一,支持断点续传的HTTP服务器通常会在响应头中添加Range字段,用于指定服务器传输的起始位置。
客户端在进行文件下载时,通过设置请求头中的Range字段来请求指定范围的数据。
服务器接收到请求后,根据Range字段返回相应的数据片段。
如果客户端在下载过程中中断,可以通过设置Range字段重新发送请求,从中断处继续下载。
HTTP的断点续传方案具有以下优点:-:基于HTTP的断点续传方案使用标准的HTTP协议,不需要额外的协议和框架支持,方便快捷。
-:基于HTTP的断点续传方案通常兼容多种操作系统和终端设备,使用广泛。
-:通过设置不同的Range字段,可以实现下载指定范围的数据,具有较高的灵活性。
-:HTTP协议本身就具有较高的可靠性,断点续传方案在一定程度上增强了文件传输的可靠性。
然而,基于HTTP的断点续传方案也存在一些局限性:-:由于每次续传都需要从中断处开始,可能会导致重复传输已经传输过的数据,降低传输效率。
-:对于非常大的文件,服务器需要保存大量的中断点信息,占用较多的磁盘空间和内存资源。
-:如果服务器不支持断点续传,那么即使客户端实现了断点续传方案,也无法成功续传。
方案二:基于FTP的断点续传FTP(File Transfer Protocol)是一种文件传输协议,也常用于文件上传和下载。
FTP支持断点续传的机制,能够在网络中断或传输中止后从中断处继续传输。
java下载功能
java下载功能Java是一种跨平台的编程语言,能够在各种操作系统上运行,因此非常适合用于开发具有下载功能的应用程序。
Java提供了丰富的API和库,使开发者能够轻松地实现下载功能。
下面是一些常用的Java下载功能的实现方式:1. 使用URLConnection类来进行下载:URLConnection类是Java提供的用于网络连接的类,可以通过该类来实现下载。
使用URLConnection的步骤包括创建URL对象、打开连接、获取输入流、创建输出流、将数据从输入流写入输出流等。
2. 使用HttpClient库来进行下载:HttpClient是一个功能强大的开源HTTP客户端库,可以用于发送HTTP请求并处理HTTP响应。
通过使用HttpClient库,可以实现更为复杂的下载功能,例如断点续传、多线程下载等。
3. 使用多线程来进行下载:在下载大文件时,为了加快下载速度,可以使用多线程来并行下载。
通过将文件分成多个部分,每个部分由一个线程负责下载,可以同时下载多个部分,提高下载速度。
4. 使用下载管理器来进行下载:下载管理器是一种用于管理下载任务的工具,可以对下载任务进行管理和控制,例如暂停、取消、进度监控等。
Java提供了一些第三方库,如Downpour 和Download4j,可以用于实现下载管理器。
5. 使用流式处理来进行下载:在Java中,可以使用流式处理来处理大文件的下载。
通过使用BufferedInputStream和BufferedOutputStream,可以将下载的文件分块读取并写入本地文件,避免一次性读取整个文件导致内存溢出。
总之,Java提供了多种方式来实现下载功能,开发者可以根据需求选择合适的方法来实现。
通过合理利用Java的API和库,能够实现高效、安全的下载功能,并提供给用户优质的下载体验。
用Java实现HTTP断点续传——多线程下载文件
用Java实现HTTP断点续传——多线程下载文件钟华本文介绍了一种利用Java 来实现断点续传的方法。
断点续传的原理Http断点续传的原理其实很简单,就是在请求上和一般的下载有所不同而已。
例如浏览器请求服务器上的一个文件时,所发出的请求如下(假设服务器域名为,文件名为down.zip):GET /down.zip HTTP/1.1Accept: image/gif, image/x-xbitmap, image/jpeg, image/jpg,application/vnd.ms-excel, application/msword,application/vnd.ms-powerpoint, */*Accept-Language: zh-cnAccept-Encoding: gzip, deflautUser-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0) Connection: Keep-Alive服务器收到请求后,按要求寻找请求的文件,提取文件的信息,然后返回给浏览器,返回信息如下:200Content-Length=106786028Accept-Ranges=bytesDate=Mon, 30 Apr 2001 12:56:11 GMTETag=W/"02ca57e173c11:95b"Content-Type=application/octet-streamServer=Microsoft-IIS/5.0Last-Modified=Mon, 30 Apr 2001 12:56:11 GMT所谓断点续传,就是从文件已经下载的地方开始继续下载。
所以在客户端浏览器传给Web服务器的时候要多加一条信息——从哪里开始。
下面是用自己编的一个“浏览器”来传递请求信息给Web服务器,要求从2000070字节开始。
用C#语言实现http协议下的多线程文件传输.
用C#语言实现http协议下的多线程文件传输很多人都有过使用网络蚂蚁或网络快车软件下载互联网文件的经历,这些软件的使用可以大大加速互联网上文件的传输速度,减少文件传输的时间。
这些软件为什么有如此大的魔力呢?其主要原因是这些软件都采用了多线程下载和断点续传技术。
如果我们自己来编写一个类似这样的程序,也能够快速的在互联网上下载文件,那一定是非常愉快的事情。
下面我就讲一讲如何利用C#语言编写一个支持多线程下载文件的程序,你会看到利用C#语言编写网络应程序是多么的容易,从中也能体会到C#语言中强大的网络功能。
首先介绍一下HTTP协议,HTTP亦即Hpyer Text Transfer Protocal的缩写,它是现代互联网上最重要的一种网络协议,超文本传输协议位于TCP/IP协议的应用层,是一个面向无连接、简单、快速的C/S结构的协议。
HTTP的工作过程大体上分连接、请求、响应和断开连接四个步骤。
C#语言对HTTP协议提供了良好的支持,在.NET类库中提供了WebRequest和WebResponse类,这两个类都包含在命名空间中,利用这两个类可以实现很多高级的网络功能,本文中多线程文件下载就是利用这两个类实现的。
WebRequest和WebResponse都是抽象基类,因此在程序中不能直接作为对象使用,必须被继承,实际使用中,可根据URI参数中的URI前缀选用它们合适的子类,对于HTTP这类URI,HttpWebRequest 和HttpWebResponse类可以用于处理客户程序同WEB服务器之间的HTTP通讯。
HttpWebRequest类实现了很多通过HTTP访问WEB服务器上文件的高级功能。
HttpWebRequest类对WebRequest中定义的属性和方法提供支持,HttpWebRequest将发送到Internet资源的公共HTTP标头的值公开为属性,由方法或系统设置,常用的由属性或方法设置的HTTP标头为:接受, 由Accept属性设置, 连接, 由Connection属性和KeepAlive属性设置, Content-Length, 由ContentLength属性设置, Content-Type, 由ContentType属性设置, 范围, 由AddRange方法设置. 实际使用中是将标头信息正确设置后,传递到WEB服务器,WEB服务器根据要求作出回应。
android多线程下载技术详解
Android 多线程、断点续传下载技术1.为什么使用该技术?答:(1)之所以采用多线程下载是因为考虑到手机,及移动设备的cup处理能力,让下载任务多抢占cup资源,从而加快了下载的速度,提高了用户体验(2)断点续传技术,就是在下载过程中如果网络出现问题,导致文件没有下载完,那么下次下载时,接着上次终端位置继续下载,从而减轻了服务器的负担。
2.下面我们就开始建一个多线程下载的项目,来体验多线程下载的优势,项目的结构如下2.1设计UImain.xml代码如下:<?xml version="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="/apk/res /android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:text="@string/path"/><EditTextandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:text="/kcn/pc/K anbox_10012.exe"android:id="@+id/path"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/button"android:id="@+id/button"/><ProgressBarandroid:layout_width="fill_parent"android:layout_height="20px"style="?android:attr/progressBarStyleHorizontal"android:id="@+id/downloadbar"/><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:gravity="center"android:id="@+id/result"/></LinearLayout>其中引用的string.xml如下:<?xml version="1.0"encoding="utf-8"?><resources><string name="hello">Hello World, SmartDownload!</string><string name="app_name">SMART多线程断点下载器</string><string name="path">下载路径</string><string name="button">下载</string><string name="success">下载完成</string><string name="error">下载失败</string><string name="sdcarderror">SDCard不存在或者写保护</string></resources>3.数据库阶段:3.1编写数据库工具类DBOpenHelerpackage com.smart.db;import android.content.Context;import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper;public class DBOpenHelper extends SQLiteOpenHelper {private static final String DBNAME = "smart.db";private static final int VERSION = 1;public DBOpenHelper(Context context) {super(context, DBNAME, null, VERSION);}@Overridepublic voiddb.execSQL("CREATE TABLE IF NOT EXISTS SmartFileDownlog (id integer primary key autoincrement, downpath varchar(100), threadid INTEGER, downlength INTEGER)");}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {db.execSQL("DROP TABLE IF EXISTS SmartFileDownlog");onCreate(db);}}3.2对各个线程的下载记录进行数据库的操作,编写Fileservice 类代码如下package com.smart.db;import java.util.HashMap;import java.util.Map;import android.content.Context;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase; /*** 业务bean**/public class FileService {private DBOpenHelper openHelper;public FileService(Context context) { openHelper = new DBOpenHelper(context);}/*** 获取每条线程已经下载的文件长度* @param path* @return*/public Map<Integer, Integer> getData(String path){openHelper.getReadableDatabase();Cursor cursor = db.rawQuery("select threadid, downlength from SmartFileDownlog where downpath=?", new String[]{path});Map<Integer, Integer> data = newHashMap<Integer, Integer>();while(cursor.moveToNext()){data.put(cursor.getInt(0),cursor.getInt(1));}cursor.close();db.close();return data;}/*** 保存每条线程已经下载的文件长度* @param path* @param map*/public void save(String path, Map<Integer, Integer> map){//int threadid, int positionopenHelper.getWritableDatabase();db.beginTransaction();try{for(Map.Entry<Integer, Integer> entry : map.entrySet()){db.execSQL("insert intoSmartFileDownlog(downpath, threadid, downlength) values(?,?,?)",new Object[]{path, entry.getKey(), entry.getValue()});}db.setTransactionSuccessful();}finally{db.endTransaction();}db.close();}/*** 实时更新每条线程已经下载的文件长度* @param path* @param map*/public void update(String path, Map<Integer, Integer> map){SQLiteDatabase db =openHelper.getWritableDatabase();db.beginTransaction();try{for(Map.Entry<Integer, Integer> entry : map.entrySet()){db.execSQL("update SmartFileDownlog set downlength=? where downpath=? and threadid=?",new Object[]{entry.getValue(), path, entry.getKey()});}db.setTransactionSuccessful();}finally{db.endTransaction();}db.close();}/*** 当文件下载完成后,删除对应的下载记录* @param path*/public void delete(String path){SQLiteDatabase db =openHelper.getWritableDatabase();db.execSQL("delete from SmartFileDownlog where downpath=?", new Object[]{path});db.close();}}4.实现文件下载阶段4.1建立SmartFileDownloader类用来实现文件的下载功能代码如下package com.smart.impl;import java.io.File;import java.io.RandomAccessFile;import .HttpURLConnection;import .URL;import java.util.LinkedHashMap;import java.util.Map;import java.util.UUID;import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher;import java.util.regex.Pattern;import android.content.Context;import android.util.Log;import com.smart.db.FileService;public class SmartFileDownloader {private static final String TAG = "SmartFileDownloader";private Context context;private FileService fileService;/* 已下载文件长度 */private int downloadSize = 0;/* 原始文件长度 */private int fileSize = 0;/* 线程数 */private SmartDownloadThread[] threads;/* 本地保存文件 */private File saveFile;/* 缓存各线程下载的长度*/private Map<Integer, Integer> data = new ConcurrentHashMap<Integer, Integer>();/* 每条线程下载的长度 */private int block;/* 下载路径 */private String downloadUrl;/*** 获取线程数*/public int getThreadSize() {return threads.length;}/*** 获取文件大小* @return*/public int getFileSize() {return fileSize;}* 累计已下载大小* @param size*/protected synchronized void append(int size) { downloadSize += size;}/*** 更新指定线程最后下载的位置* @param threadId 线程id* @param pos 最后下载的位置*/protected void update(int threadId, int pos) { this.data.put(threadId, pos);}/*** 保存记录文件*/protected synchronized void saveLogFile() { this.fileService.update(this.downloadUrl, this.data);}* 构建文件下载器* @param downloadUrl 下载路径* @param fileSaveDir 文件保存目录* @param threadNum 下载线程数*/public SmartFileDownloader(Context context, String downloadUrl, File fileSaveDir, int threadNum) {try {this.context = context;this.downloadUrl = downloadUrl;fileService = newFileService(this.context);URL url = new URL(this.downloadUrl);if(!fileSaveDir.exists())fileSaveDir.mkdirs();this.threads = newSmartDownloadThread[threadNum];HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setConnectTimeout(5*1000);conn.setRequestMethod("GET");conn.setRequestProperty("Accept","image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash,application/xaml+xml,application/vnd.ms-xpsdocument,application/x-ms-xbap,application/x-ms-application,application/vnd.ms-excel,application/vnd.ms-powerpoint, application/msword, */*");conn.setRequestProperty("Accept-Language", "zh-CN");conn.setRequestProperty("Referer", downloadUrl);conn.setRequestProperty("Charset","UTF-8");conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR2.0.50727; .NET CLR3.0.04506.30; .NET CLR3.0.4506.2152; .NET CLR 3.5.30729)");conn.setRequestProperty("Connection", "Keep-Alive");conn.connect();printResponseHeader(conn);if (conn.getResponseCode()==200) {this.fileSize =conn.getContentLength();//根据响应获取文件大小if (this.fileSize <= 0) throw new RuntimeException("Unkown file size ");String filename = getFileName(conn);this.saveFile = new File(fileSaveDir, filename);/* 保存文件 */Map<Integer, Integer> logdata = fileService.getData(downloadUrl);if(logdata.size()>0){for(Map.Entry<Integer, Integer> entry : logdata.entrySet())data.put(entry.getKey(),entry.getValue());}this.block = (this.fileSize %this.threads.length)==0? this.fileSize /this.threads.length : this.fileSize /this.threads.length + 1;if(this.data.size()==this.threads.length){for(int i = 0; i < this.threads.length; i++) {this.downloadSize +=this.data.get(i+1);}print("已经下载的长度"+this.downloadSize);}}else{throw new RuntimeException("server no response ");}} catch (Exception e) {print(e.toString());throw new RuntimeException("don't connection this url");}}/*** 获取文件名*/private String getFileName(HttpURLConnection conn) {String filename =this.downloadUrl.substring(stI ndexOf('/') + 1);if(filename==null ||"".equals(filename.trim())){//如果获取不到文件名称for (int i = 0;; i++) {String mine = conn.getHeaderField(i);if (mine == null) break;if("content-disposition".equals(conn.getHeader FieldKey(i).toLowerCase())){Matcher m =pile(".*filename=(.*)").matcher(mine.t oLowerCase());if(m.find()) return m.group(1);}}filename = UUID.randomUUID()+ ".tmp";//默认取一个文件名}return filename;}/*** 开始下载文件* @param listener 监听下载数量的变化,如果不需要了解实时下载的数量,可以设置为null* @return已下载文件大小* @throws Exception*/public intdownload(SmartDownloadProgressListener listener) throws Exception{try {RandomAccessFile randOut = new RandomAccessFile(this.saveFile, "rw");if(this.fileSize>0)randOut.setLength(this.fileSize);randOut.close();URL url = new URL(this.downloadUrl);if(this.data.size() !=this.threads.length){this.data.clear();//清除数据for (int i = 0; i < this.threads.length; i++) {this.data.put(i+1, 0);}}for(int i = 0; i < this.threads.length; i++) {int downLength = this.data.get(i+1);if(downLength < this.block &&this.downloadSize<this.fileSize){ //该线程未完成下载时,继续下载this.threads[i] = new SmartDownloadThread(this, url, this.saveFile, this.block, this.data.get(i+1), i+1);this.threads[i].setPriority(7);this.threads[i].start();}else{this.threads[i] = null;}}this.fileService.save(this.downloadUrl, this.data);boolean notFinish = true;//下载未完成while (notFinish) {// 循环判断是否下载完毕Thread.sleep(900);notFinish = false;//假定下载完成for (int i = 0; i < this.threads.length; i++){if (this.threads[i] != null&& !this.threads[i].isFinish()) {notFinish = true;//下载没有完成if(this.threads[i].getDownLength() == -1){//如果下载失败,再重新下载this.threads[i] = new SmartDownloadThread(this, url, this.saveFile, this.block, this.data.get(i+1), i+1);this.threads[i].setPriority(7);this.threads[i].start();}}}if(listener!=null)listener.onDownloadSize(this.downloadSize);}fileService.delete(this.downloadUrl);} catch (Exception e) {print(e.toString());throw new Exception("file download fail");}return this.downloadSize;}/*** 获取Http响应头字段* @param http* @return*/public static Map<String, String> getHttpResponseHeader(HttpURLConnection http) { Map<String, String> header = new LinkedHashMap<String, String>();for (int i = 0;; i++) {String mine = http.getHeaderField(i);if (mine == null) break;header.put(http.getHeaderFieldKey(i), mine);}return header;}/*** 打印Http头字段* @param http*/public static voidprintResponseHeader(HttpURLConnection http){ Map<String, String> header = getHttpResponseHeader(http);for(Map.Entry<String, String> entry : header.entrySet()){String key = entry.getKey()!=null ? entry.getKey()+ ":" : "";print(key+ entry.getValue());}}//打印日志private static void print(String msg){ Log.i(TAG, msg);}}4.2下载过程中的线程实现建立SmartDownloadThread类具体代码如下:package com.smart.impl;import java.io.File;import java.io.InputStream;import java.io.RandomAccessFile;import .HttpURLConnection;import .URL;import android.util.Log;public class SmartDownloadThread extends Thread { private static final String TAG = "SmartDownloadThread";private File saveFile;private URL downUrl;private int block;/* *下载开始位置 */private int threadId = -1;private int downLength;private boolean finish = false;private SmartFileDownloader downloader;public SmartDownloadThread(SmartFileDownloader downloader, URL downUrl, File saveFile, int block, int downLength, int threadId) {this.downUrl = downUrl;this.saveFile = saveFile;this.block = block;this.downloader = downloader;this.threadId = threadId;this.downLength = downLength;}@Overridepublic void run() {if(downLength < block){//未下载完成try {HttpURLConnection http = (HttpURLConnection) downUrl.openConnection();http.setConnectTimeout(5 * 1000);http.setRequestMethod("GET");http.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash,application/xaml+xml,application/vnd.ms-xpsdocument,application/x-ms-xbap,application/x-ms-application,application/vnd.ms-excel,application/vnd.ms-powerpoint, application/msword, */*");http.setRequestProperty("Accept-Language","zh-CN");http.setRequestProperty("Referer", downUrl.toString());http.setRequestProperty("Charset", "UTF-8");int startPos = block * (threadId - 1) + downLength;//开始位置int endPos = block * threadId -1;//结束位置http.setRequestProperty("Range","bytes=" + startPos + "-"+ endPos);//设置获取实体数据的范围http.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR2.0.50727; .NET CLR3.0.04506.30; .NET CLR3.0.4506.2152; .NET CLR 3.5.30729)");http.setRequestProperty("Connection", "Keep-Alive");InputStream inStream =http.getInputStream();byte[] buffer = new byte[1024];int offset = 0;print("Thread "+ this.threadId+ " start download from position "+ startPos);RandomAccessFile threadfile = new RandomAccessFile(this.saveFile, "rwd");threadfile.seek(startPos);while((offset = inStream.read(buffer, 0, 1024)) != -1) {threadfile.write(buffer, 0, offset);downLength += offset;downloader.update(this.threadId, downLength);downloader.saveLogFile();downloader.append(offset);}threadfile.close();inStream.close();print("Thread " + this.threadId + " download finish");this.finish = true;} catch (Exception e) {this.downLength = -1;print("Thread "+ this.threadId+ ":"+ e);}}}private static void print(String msg){Log.i(TAG, msg);}/*** 下载是否完成* @return*/public boolean isFinish() {return finish;}/*** 已经下载的内容大小* @return如果返回值为-1,代表下载失败*/public long getDownLength() {return downLength;}}4.3 建立interface SmartDownloadProgressListener 侦听线程的下载进度代码如下:package com.smart.impl;public interface SmartDownloadProgressListener { public void onDownloadSize(int size);}5.建立activity 实现下载的触发,和界面的实时更新具体代码如下:package com.smart.activoty.download;import java.io.File;import android.app.Activity;import android.os.Bundle;import android.os.Environment;import android.os.Handler;import android.os.Message;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.ProgressBar;import android.widget.TextView;import android.widget.Toast;importcom.smart.impl.SmartDownloadProgressListener; import com.smart.impl.SmartFileDownloader;public class SmartDownloadActivity extends Activity {private ProgressBar downloadbar;private EditText pathText;private TextView resultView;private Handler handler = new Handler(){@Override//信息public void handleMessage(Message msg) { switch (msg.what) {case 1:int size = msg.getData().getInt("size");downloadbar.setProgress(size);float result =(float)downloadbar.getProgress()/(float)downloadbar.getMax();int p = (int)(result*100);resultView.setText(p+"%");if(downloadbar.getProgress()==downloadbar.getM ax())Toast.makeText(SmartDownloadActivity.this, R.string.success, 1).show();break;case -1:Toast.makeText(SmartDownloadActivity.this, R.string.error, 1).show();break;}}};@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.main);Button button =(Button)this.findViewById(R.id.button);downloadbar =(ProgressBar)this.findViewById(R.id.downloadbar); pathText =(EditText)this.findViewById(R.id.path);resultView =(TextView)this.findViewById(R.id.result);button.setOnClickListener(newView.OnClickListener() {@Overridepublic void onClick(View v) {String path =pathText.getText().toString();if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){File dir =Environment.getExternalStorageDirectory();//文件保存目录download(path, dir);}else{Toast.makeText(SmartDownloadActivity.this,R.string.sdcarderror, 1).show();}}});}//对于UI控件的更新只能由主线程(UI线程)负责,如果在非UI 线程更新UI控件,更新的结果不会反映在屏幕上,某些控件还会出错private void download(final String path, final File dir){new Thread(new Runnable() {@Overridepublic void run() {try {SmartFileDownloader loader = new SmartFileDownloader(SmartDownloadActivity.this, path, dir, 3);int length = loader.getFileSize();//获取文件的长度downloadbar.setMax(length);loader.download(new SmartDownloadProgressListener(){@Overridepublic void onDownloadSize(int size) {//可以实时得到文件下载的长度Message msg = new Message();msg.what = 1;msg.getData().putInt("size", size);handler.sendMessage(msg);}});} catch (Exception e) {Message msg = new Message();//信息提示msg.what = -1;msg.getData().putString("error", "下载失败");//如果下载错误,显示提示失败!handler.sendMessage(msg);}}}).start();//开始}}6.到此为止运行会报错,因为没有向sdcard的协数据的权限,访问Internet的权限这需要在AndroidManifest.xml配置具体代码如下:<?xml version="1.0"encoding="utf-8"?><manifestxmlns:android="/apk/res /android"package="com.smart.activoty.download"android:versionCode="1"android:versionName="1.0"><application android:icon="@drawable/icon" android:label="@string/app_name"><activityandroid:name=".SmartDownloadActivity"android:label="@string/app_name"> <intent-filter><actionandroid:name="android.intent.action.MAIN"/><categoryandroid:name="UNCHER"/> </intent-filter></activity></application><uses-sdk android:minSdkVersion="8"/><!-- 访问internet权限 --><uses-permissionandroid:name="android.permission.INTERNET"/><!-- 在SDCard中创建与删除文件权限 --><uses-permissionandroid:name="android.permission.MOUNT_UNMOUNT_FI LESYSTEMS"/><!-- 往SDCard写入数据权限 --><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_S TORAGE"/></manifest>。
外审论文评阅意见模板
外审论文:《通信网络告警相关性的研究》外审论文:《基于web矢量图形处理技术的研究》http多线程断点续传下载软件的设计与开发研究基于多线程技术的下载软件,提高了下载软件的下载能力。
论文研究了多线程断点续传下载软件的设计与实现,选题明确,具有很高的应用价值。
论文研究了多线程技术,HTTP协议分析与断点续传技术,针对软件系统进行了需求分析,总体设计。
在设计中,重点对文件分段进行了分析,下载功能的设计。
对断点续传软件的开发中的多个重点问题进行了探讨。
给出了详细的分析设计和实现过程。
论文的工作在技术上有一定难度和新颖性。
论文结构严谨,逻辑严密,体现了该同学比较扎实的专业基础知识和较强的动手能力。
论文达到优秀水平。
9 10 28 28 18华夏学院毕业设计管理系统的设计与实现研究基于Java Web的高校毕业论文管理系统。
论文对高校毕业论文包括选题、指导老师管理和学生管理进行了需求分析,并且在此基础上进行了分析和设计。
对Java Web开发的主要技术进行了分析和选择。
论文的选题具有实用价值,但是对系统的分析不够明确清晰,没有使用到前面部分提到的SSH技术。
论文结构不够合理,不推荐作为优秀论文。
7 6 20 25 15武汉供电企业事务管理系统的设计与开发研究了一个基于Web的事务管理系统。
论文对企业事务管理系统进行了可行性分析、概要设计、详细设计、编码和测试的完整的软件工程。
对采用的技术进行了比较详细的分析与比较。
论文的选题具有应用价值,但是对系统的分析不够清晰明确,没有采用比较新的技术,缺乏创新点。
不推荐该文作为优秀论文。
7 6 20 24 12基于ASP的华夏书城的设计与开发研究了一个B2C的网上商城的设计与开发流程。
论文对网上商城进行了需求分析。
模块划分、概要设计、详细设计。
论文的选题具有实用性。
对文献的综述也能反映学科的发展现状。
文章作者有比较强的动手能力。
但是文章没有创新点,也没有采用比较新的技术。
断点续传和多线程下载(上)
H T 蜘议简介 TP
下载 文件是 电皓与w E B服务器交互的过程 ,它们交互 的 “ 语 言 的专业名称是协议。传送文件的协议有多种,最常用的是 HTTP ( 超文本传输协设)和F P ( T 文件传送协议 ),我采用 ̄ HTTP 。
Ht l e tx ndRe e S qu  ̄
基本的下蠢过程
犏写下载程序 .可以直接 使用S c e 函数 ,但是这 要求开 发 ok t
人员理解 ,熟悉TC / P P I 执议。为 了简化I t r e 客 户端软件的开 nen t 发 ,Wi d ws n o 提供 了 套Wil e I 对常用的网络协议进行 了 一 n n t AP , 封装 ,把开 发I t ne 软件的 门槛 大太降低 了 我 们需要使用的 n e t r
I tn Ra tl 件 le e t Fe 读文 n r t d l
『t e leM d 美可It re旬辆 I e t o E nl nm Cs e ne nt
1
墨'
章 中难以垒 部阐 明 ,所 以 ,与 下载过 程关 系不 直接 的部 分基 本上
都忽 略 了 ,如异 常处理 和 尉络 错 误处 理等 ,敬请 各 位读 者注意 。 税使 用的开发环境是c ++ B i e 5 0 u l r . ,使用其他开发环 境或者 d 编 程 语 言的 腿友 请 自扦作适 当修 改 。 H t Ie R q e  ̄用h o c ̄ t fp n e us i t Cr t m ̄ 柄,定义为h q  ̄t Re u 。
体的 函数原型请 参考M S 。 DN 在使 用这些 函数时 ,必 须 严格 区分它
下载 中断 ,在 重新建 立连 接后 ,跳 过 已经下 载的部 丹 ,而 只下载
断点续传的原理
断点续传的原理断点续传是指在文件传输过程中,如果传输中断,可以从中断处继续传输,而不需要重新开始传输整个文件。
这种技术可以大大提高文件传输的效率,尤其是在网络不稳定或者文件较大的情况下。
断点续传的原理主要是利用HTTP协议中的Range头部字段。
当客户端请求一个文件时,可以在请求头中添加Range字段,指定需要下载的文件范围。
服务器接收到请求后,会根据Range字段返回相应的文件片段。
客户端接收到文件片段后,可以将其拼接到已经下载的文件末尾,从而实现断点续传。
具体来说,断点续传的实现需要以下几个步骤:1. 客户端向服务器发送一个请求,请求下载文件,并在请求头中添加Range字段,指定需要下载的文件范围。
2. 服务器接收到请求后,根据Range字段返回相应的文件片段。
如果Range字段为空,则返回整个文件。
3. 客户端接收到文件片段后,将其拼接到已经下载的文件末尾。
4. 客户端记录已经下载的文件大小,下次请求时在Range字段中指定已经下载的文件大小,以便服务器返回正确的文件片段。
5. 如果下载中断,客户端可以记录已经下载的文件大小,并在下次请求时在Range字段中指定已经下载的文件大小,从而实现断点续传。
需要注意的是,断点续传的实现需要服务器支持Range头部字段,并且客户端需要记录已经下载的文件大小。
此外,如果文件被修改,断点续传可能会出现问题,因为文件的大小和内容可能会发生变化。
总之,断点续传是一种非常实用的技术,可以大大提高文件传输的效率和稳定性。
它的原理主要是利用HTTP协议中的Range头部字段,通过请求文件的片段来实现文件的断点续传。
在实际应用中,需要注意服务器和客户端的支持,以及文件的修改可能会影响断点续传的效果。
移动应用开发技术中的断点续传功能实现方法
移动应用开发技术中的断点续传功能实现方法随着移动应用的迅速发展,用户对于应用的要求也越来越高。
其中,断点续传功能成为了很多应用的必备特性之一。
断点续传功能可以在文件传输过程中,当网络出现问题或者用户主动暂停传输时,能够记录传输的进度并在网络恢复或者用户重新启动传输时自动从上次的断点处继续传输,提升用户体验。
在移动应用开发技术中,实现断点续传功能有许多方法和技术。
一、分片上传分片上传是实现断点续传功能的一种常见方法。
这种方法将文件切割成多个较小的片段,在上传的过程中,每传输完成一个片段,在服务器端都能保留下来。
如果在传输过程中出现了中断,下次再次发起上传请求时,服务器会根据已经传输完成的片段信息来判断上次传输的进度,并继续传输下一个未完成的片段。
这种方法实现起来相对简单,而且适用于各种类型的文件传输。
二、断点标记使用断点标记也是常见的断点续传实现方法之一。
在传输过程中,可以将每个传输的片段的字节数和传输进度等信息记录下来。
下次再次发起传输请求时,可以通过读取这些标记信息来判断上次传输的进度,并从断点处继续传输。
这种方法比较灵活,可以适用于各种传输方式,但需要服务器端和客户端之间进行相应的状态记录和交互。
三、使用断点恢复库移动应用开发中有一些成熟的断点续传库可以使用,例如Android平台上的"AndroidResumableUpload"库。
这些库提供了一系列的API和功能,能够方便地实现断点续传功能。
通过这些库,我们可以简单地调用相应的接口来实现文件的断点续传。
这种方法省去了开发者自己去实现断点续传的繁琐工作,提高了开发效率。
四、断点续传策略除了实现方法之外,制定合适的断点续传策略也是非常重要的。
在断点续传过程中,如何合理地选择和配置断点参数,以及如何应对各种特殊情况都需要仔细考虑。
例如,可以通过设置最大传输速度、最大传输片段数以及传输超时时间等参数来优化传输效率并避免网络拥堵。
一种简易的多线程下载工具的实现
科 技 天 地79INTELLIGENCE・・・・・・・・・・・・・・・・・・・・・・・・987058.0525.0213.0X X X +++计算各位老师的综合得分并进行系统评价。
根据4个主成份,先计算各个老师的主成分得分1F 、2F 、3F 、4F 。
再以各主成分的方差贡献率占4个主成分总方差贡献率的比重作为权重进行汇总,得出各位老师的综合得分F 即516.88/)*825.9*716.13*554.24*422.40(4321F F F F F +++=结果如表三若某个老师的得分为正,则表示该老师的教学综合业务能力在平均水平之上;反之,则在平均水平以下。
四、结论通过上面的讨论可以知道,主成分分析能对教师做出比较客观的评价,教师基本都能接受评判结果。
通过计算综合得分,每位教师可以看到自己的长处与不足,能有针对性地改进自己的工作。
作为教学主管部门能对高分的老师给予奖励,对低分老师进行帮助,使教学评估对提高教学质量起到实际意义。
参考文献:[1] 叶双峰:《关于主成分分析做综合评价的改进》,《数理统计与管理》,2001,20(2)。
[2] 高惠旋:《应用多元统计分析》,北京大学出版社,2005年。
[3] 余建英等编:《数据统计分析与SPSS 应用》,人民邮电出版社,2003年。
[4] 林海明、张文霖:《主成分分析与因子分析的异同和SPSS 软件》,《统计研究》, 2005,(3):69一种简易的多线程下载工具的实现吉林农业科技学院招生就业办 付 宁摘 要:线程可以理解为下载的通道,一个线程就是一个文件的下载通道,多线程也就是同时开起好几个下载通道。
本文首先对多线程的主要研究现状,与多线程下载相关的语言、技术以及开发工具等进行了研究,其次详细介绍了简单的多线程下载工具的编写过程,最后进行了功能测试以及相关软件的对比测试。
关键词:多线程 下载 断点续传引言网络下载技术一直是网络发展的重要推动力之一。
原先的信息资源共享主要通过Web 技术实现,即先把共享的文件放到服务器上,然后客户机便可以通过HTTP 和FTP 等协议从服务器下载这些文件,这就是所谓的C/S 结构,采用的也是传统的单线程下载。
高速下载的文件分流和断点续传技巧
高速下载的文件分流和断点续传技巧随着互联网的发展和普及,我们经常需要从网络上下载大文件、视频、音频或者软件等内容。
然而,由于网络环境的不稳定和文件大小的问题,我们可能会遇到下载速度缓慢、下载中断等困扰。
为了解决这些问题,本文将介绍一些高速下载的文件分流和断点续传技巧,以提高下载效率和稳定性。
一、多线程下载多线程下载是一种通过同时使用多个线程下载文件的方法。
利用多线程,我们可以同时从不同的服务器或网络地址下载同一个文件的不同部分,从而大大提高下载速度。
在使用多线程下载时,我们可以借助一些专门的下载工具或下载软件。
这些工具通常会自动将文件分成多个部分,并同时启动多个线程进行下载。
同时,它们还可以根据不同的网络环境和连接速度,自动选择最佳的下载线程,以确保下载效率最大化。
二、资源分流下载资源分流下载是指将一个文件分成多个部分,然后从多个服务器或网络地址下载这些部分,最后再进行合并,以完成整个文件的下载。
通过资源分流,我们可以充分利用网络资源,提高下载速度和稳定性。
在实施资源分流下载时,我们可以使用一些专门的下载工具或下载软件。
这些工具通常会自动将文件进行分割,并同时从不同的服务器或网络地址下载这些分割的部分。
最后,它们会将这些部分合并成完整的文件,从而完成下载过程。
三、断点续传技巧断点续传是指在下载过程中,当下载中断或暂停后再次开始时,能够从中断或暂停的地方继续下载,而不需要重新开始下载整个文件。
这种技巧可以节省时间和流量,并提高下载效率。
为了实现断点续传,我们需要使用支持此功能的下载工具或下载软件。
这些工具通常会将下载文件的下载进度保存在本地,当下载中断或暂停后再次开始时,它们会自动检测并读取本地保存的下载进度,并从断点处继续下载。
这样,我们可以避免重新下载整个文件,节省时间和流量。
四、其他注意事项在使用高速下载的文件分流和断点续传技巧时,我们还需要注意以下几点:1. 选择稳定的网络环境:高速下载需要良好的网络环境支持,因此我们应选择稳定的网络连接,避免在下载过程中频繁出现网络中断或波动。
文件上传下载原理:http协议分析及实现
⽂件上传下载原理:http协议分析及实现 我们现在⽤得⾮常多互联⽹下载⽂件,⾮常直观。
有⼀个下载按钮,然后我点击了下载,然后⽂件慢慢就下载到本地了。
就好像是⼀个复制的过程。
⽽既然是互联⽹,那么必然会是使⽤⽹络进⾏传输的。
那么到底是怎样传输的呢? 当然,下载⽂件有两种⽅式:⼀是直接针对某个⽂件资源进⾏下载,⽆需应⽤开发代码;⼆是应⽤代码临时⽣成需要的内容⽂件,然后输出给到下载端。
其中,直接下载资源⽂件的场景给我们感觉是下载就是针对这个⽂件本⾝的⼀个操作,和复制⼀样没有什么疑义。
⽽由应⽤代码进⾏下载⽂件时,⼜当如何处理呢?1. 上传下载⽂件demo 在⽹上你可以⾮常容易地找到相应的模板代码,然后处理掉。
基本的样⼦就是设置⼏个头信息,然后将数据写⼊到response中。
demo1. 服务端接收⽂件上传,并同时输出⽂件到客户端@PostMapping("fileUpDownTest")@ResponseBodypublic Object fileUpDownTest(@ModelAttribute EncSingleDocFileReqModel reqModel,MultipartFile file,HttpServletResponse response) {// 做两件事:1. 接收上传的⽂件; 2. 将⽂件下载给到上传端;// 即向双向⽂件的传输,下载的⽂件可以是你处理之后的任意⽂件。
String tmpPath = saveMultipartToLocalFile(file);outputEncFileStream(tmpPath, response);System.out.println("path:" + tmpPath);return null;}/*** 保存⽂件到本地路径** @param file ⽂件流* @return本地存储路径*/private String saveMultipartToLocalFile(MultipartFile file) {try (InputStream inputStream = file.getInputStream()){// 往临时⽬录写⽂件String fileSuffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.'));File tmpFile = File.createTempFile(file.getName(), ".tmp" + fileSuffix);FileUtils.copyInputStreamToFile(inputStream, tmpFile);return tmpFile.getCanonicalPath();}catch (Exception e){log.error("【加密⽂件】⽂件流处理失败:" + file.getName(), e);throw new EncryptSysException("0011110", "⽂件接收失败");}}/*** 输出⽂件流数据** @param encFileLocalPath ⽂件所在路径* @param response servlet io 流*/private void outputEncFileStream(String encFileLocalPath, HttpServletResponse response) {File outFile = new File(encFileLocalPath);OutputStream os = null;InputStream inputStream = null;try {response.reset();response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");// response.setHeader("Content-Length", file.getContentLength()+"");String outputFileName = encFileLocalPath.substring(stIndexOf('/') + 1);response.setHeader("Content-Disposition", String.format("attachment; filename=%s", URLEncoder.encode(outputFileName, "UTF-8")));response.setContentType("application/octet-stream; charset=utf-8");response.setHeader("Pragma", "no-cache");response.setHeader("Expires", "0");inputStream = new FileInputStream(outFile);//写⼊信息os = CommonUtil.readInputStream(inputStream, response.getOutputStream());}catch (Exception re) {log.error("输出⽂件流失败,", re);throw new RuntimeException("0011113: 输出加密后的⽂件失败");}finally {os.flush();os.close();}catch (IOException e) {log.error("输出流⽂件失败", e);}}if(inputStream != null) {try {inputStream.close();}catch (IOException e) {log.error("加密⽂件输⼊流关闭失败", e);}}}} 我们在做开发时,⾯对的仅仅是 Request, Response 这种什么都有对象,直接问其要相关信息即可。
idm断点续传原理
idm断点续传原理
IDM(Internet Download Manager)断点续传原理:
IDM的断点续传功能是基于HTTP协议实现的。
具体原理如下:
1. 当用户下载一个文件时,IDM首先会将文件下载链接发送
给服务器并请求下载。
2. 服务器会将文件切分成多个小块(称为数据包)进行传输,并为每个数据包生成一个唯一的标识符。
3. IDM接收到服务器的响应后,会开始下载并将文件分成多
个部分(称为下载任务),每个任务对应一个数据包。
4. 当一个数据包下载完成后,IDM会将下载的数据写入硬盘
上的临时文件中,并记录已下载的文件大小。
5. 如果下载过程中断或者用户中止了下载,IDM会保存已下
载的数据包信息,以便后续继续下载。
6. 当用户再次启动下载任务时,IDM会读取临时文件中的下
载信息,并向服务器发送请求,告知服务器已经下载的数据包,并请求继续下载。
7. 服务器收到请求后,会检查已下载的数据包,并将剩余的数据包发送给IDM。
8. IDM接收到服务器发送的数据包后,会将它们写入临时文件中的对应位置,并更新已下载的文件大小。
9. 当文件下载完成时,IDM会将临时文件重命名为最终文件名,并移动到指定的下载目录。
通过上述的断点续传机制,IDM可以在网络中断、重新启动或用户中止下载时,记录已下载的数据并从中断的地方继续下载,避免了重新下载整个文件的问题,提高了下载效率。
HTTP协议解析
基于HTTP的协议的网络文件下载,工作原理建立在请求/响应模式(Request/Response)上:一个客户端与服务器建立连接后,客户端向Web服务器发出一个HTTP请求行;Web 服务器在收到有效的请求后,返回一个状态行或多个响应标题、一个空白行和相关文档。
HTTP协议使用的端口号,通常为80。
开发基于http协议的网络文件下载必须掌握HTTP 协议,包括向服务器发送请求和获取服务器响应状态的过程。
HTTP1.0协议不支持断点续传功能. 本文用java提供了一个简单的实现.1.HTTP协议工作方式基于HTTP协议的客户/服务器模式的信息交换过程,它分四个过程:建立连接、发送请求信息、获取服务器响应状态、关闭连接。
其中较为复杂的过程是:发送请求信息、获取服务器响应状态.1)向服务器发送请求信息一个HTTP请求由一个请求行、可选数目的请求标题、一个空白行,以及在POST情况下的一些额外的数据组成。
请求行的格式是:Method Request-URI HTTP-Vsersion CRLFMethod表示请求方法,如GET和POSTRequest-URI标识了要请求的资源,HTTP-Version表示请求的HTTP协议版本,CRLF表示回车换行。
HTTP请求报文格式如下:HTTP Command: //方法字段(GET方法,POST方法)URI: //URL字段,发送请求至保存该网站的服务器。
HTTP Version: //http协议版本字段Accept: //指示可被接受的请求回应的介质类型范围列表。
Accept-Language: //限制了请求回应中首选的语言为简体中文,否则使用默认值。
Accept-Encoding: //限制了回应中可接受的内容编码值User-Agent: //定义用户代理,即发送请求的浏览器类型Host: //定义了目标所在的主机Connection: //告诉服务器使用连接类型2)获取服务器响应状态在发送HTTP请求行以后,程序就可以读取服务器的响应状态了。
http下载协议
http下载协议HTTP(Hypertext Transfer Protocol)是一种被广泛应用于万维网(World Wide Web)的协议,用于在计算机网络中传输超文本文档的应用层协议。
在HTTP协议中,客户端向服务器发送请求,服务器根据请求返回相应的内容,实现了客户端与服务器之间的通信。
HTTP的下载功能是其最常用的功能之一。
通过HTTP下载,用户可以从服务器上获取所需的文件,如图片、音频、视频等。
HTTP下载协议的操作非常简单,只需要通过HTTP请求向服务器发送一个GET请求,然后服务器将文件以字节流的形式返回给客户端。
HTTP下载协议的具体流程如下:1. 客户端发起下载请求:客户端将文件的URL发送给服务器,请求下载文件。
2. 服务器响应请求:服务器接收到下载请求后,检查请求的文件是否存在,如果存在则返回一个HTTP响应,状态码为200(表示成功)。
3. 建立连接:客户端与服务器之间建立TCP连接,以便进行文件的传输。
4. 下载文件:服务器将文件以字节流的形式通过TCP连接发送给客户端,客户端接收到文件数据后保存到本地磁盘。
在HTTP下载协议中,还可以使用一些可选的请求头字段来控制文件的下载行为。
例如:- Range:可以指定下载文件的起始位置和结束位置,实现下载文件的分块下载。
- If-Modified-Since:能够实现断点续传的功能,指定下载文件的修改时间,服务器会检查文件的修改时间,如果没有变化则返回304,客户端可以使用已经下载的部分文件进行断点续传。
值得注意的是,HTTP协议本身不提供下载速度的限制机制。
如果需要限制下载速度,可以通过一些其他的手段来实现,如在服务器端进行限制或者使用下载工具进行限速。
总结起来,HTTP下载协议是一种简单而有效的协议,通过客户端向服务器发送请求,服务器返回文件数据,实现了文件的下载功能。
同时,通过一些可选的请求头字段,可以实现更多的功能,如文件的分块下载和断点续传等。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
毕业设计(论文)题目基于HTTP协议的多线程下载和断点续传的实现学生姓名学号专业计算机科学与技术班级指导教师评阅教师完成日期年月日学位论文原创性声明本人郑重声明:所呈交的论文是本人在导师的指导下独立进行研究所取得的研究成果。
除了文中特别加以标注引用的内容外,本论文不包含任何其他个人或集体已经发表或撰写的成果作品。
本人完全意识到本声明的法律后果由本人承担。
作者签名:年月日学位论文版权使用授权书本学位论文作者完全了解学校有关保障、使用学位论文的规定,同意学校保留并向有关学位论文管理部门或机构送交论文的复印件和电子版,允许论文被查阅和借阅。
本人授权省级优秀学士学位论文评选机构将本学位论文的全部或部分内容编入有关数据库进行检索,可以采用影印、缩印或扫描等复制手段保存和汇编本学位论文。
本学位论文属于1、保密□,在_________年解密后适用本授权书。
2、不保密□。
(请在以上相应方框内打“√”)作者签名:年月日导师签名:年月日目录摘要 (1)前言 (2)1 HTTP协议 (3)1.1HTTP协议的发展 (3)1.2HTTP协议的特点 (4)1.3HTTP会话及报文格式 (6)2 Windows套接字 (8)2.1 什么是套接字 (8)2.2 套接字规范 (9)2.3 Windows套接字的发展 (11)2.4 套接字的使用和WinSock API (12)3 多线程及断点续传技术 (15)3.1 多线程的优点 (18)3.2 多线程之间的互斥和同步 (16)3.3 什么是断点续传技术 (17)4 下载工具的设计与实现 (18)4.1 基本结构与数据流程图 (18)4.2 程序基本功能设计与实现 (19)4.3 代码分析 (24)4.4主要功能实现算法 (28)5 总结 (35)致谢 (36)参考文献 (37)附录 (38)基于HTTP协议的多线程下载和断点续传的实现学生:叶升路指导教师:覃颖(三峡大学电气信息学院)摘要:本文介绍了网络下载软件中的最新技术——多线程下载和断点续传技术,同时也介绍了HTTP协议的发展、特点以及WinSock编程技术。
最后在这些技术的基础上成功设计并实现了基于HTTP协议的具有多线程下载和断点续传功能的下载软件。
本软件的实现代码未使用任何WinInet API函数如InternetOpen , InternetConnect等,而是直接使用WinSock编程,逐步解析HTTP协议来完成会话和文件下载等功能。
经测试,下载速度有所提高。
关键词:下载;多线程;断点续传;HTTP;WinSock;Abstract:This paper introduces the latest downloading technology called multi-threaded downloading and resume in network downloading software. But also descripes the development of HTTP protocol, characteristics and WinSock programming. Finally, based on these technologies successfully designed and implemented a downloading tool based on the HTTP protocol with multi-threaded and resume features. The realization of the software code does not use any WinInet API functions such as InternetOpen, InternetConnect, etc., but directly use WinSock to programming, and complete the functions of conversation and file downloads and others by parse HTTP protocol steply. After tested, the speed of downloading has increased.Keywords:Downloading;Multi-thread;Resume;HTTP;WinSock;前言最近几年,随着计算机网络的飞速发展,因特网(Internet)已经逐渐成为人们生活、工作、学习必不可缺的一部分。
因特网上存储了大量丰富的信息资源,我们可以使用下载工具,把需要的信息资源下载到本地。
但是由于受到各种因素的限制,例如服务器性能、网络带宽、下载的信息量以及下载工具等等,下载速度受到不同程度的影响。
因此人们不断地提高服务器性能,扩展网络带宽,开发效率更高的下载工具以达到最大化提高下载速度的目的。
在限制下载速度的众多因素中,研究新的网络下载技术开发出更高效的下载工具无疑是其中最节约,环保以及方便的方式。
网络下载技术,也可以称为网络文件共享技术,它一直是网络发展的重要推动力之一。
早期人们共享资源的普遍方法是将资源文件上传至服务器上,然后其他用户可以通过HTTP或FTP等协议将其下载到本地电脑。
这种模式称为客户机/服务器模式即C/S模式,它对服务器的依赖性很大,当下载用户很少时,比如说一个,他将独享服务器的带宽,很显然其下载速度会非常快。
然而当下载的人数较多而服务器带宽有限时,比如服务器带宽为3MB/S,而下载人数为100人,则众多下载用户不得不共享一个带宽(3MB/S)最终结果是下载速度均分(30KB/S),普遍不高。
P2P技术的出现使得人们终于摆脱了服务器的枷锁。
它的主要特点是资源分散、负载均衡、和非中心化,它将共享的文件存储在各个客户机节点上,用户之间可以直接共享和传输文件而不需要通过服务器。
客户机不再只利用服务器带宽进行下载,它同时也可以利用其他客户机节点的带宽,这样大大提高了下载速度。
纵观网络下载技术发展的历史,可以将其划分为四个阶段:单线程下载阶段、多线程下载及断点续传阶段、P2P阶段、P2SP阶段。
一、单线下载时代:应对有限时间流量的办法早在上个世纪90年代,当时互联网并不普及,很多人使用Modem拨号,通过Telnet 软件连接到拨接式BBS上获取资讯并与别人交流(收发邮件等),由于服务器的电话线路数量有限,因此都会限制连接时间,一般新注册用户只有10分钟左右。
这点时间用来看帖回帖显然不够的,因此有人就开发了软件,进入BBS后,能够将整个BBS上所有内容都下载回来,然后可以断线慢慢看慢慢回,最后再次拨入BBS上传回复。
二、断点续传与多线程下载时代:大幅度提高速度进入Windows与WWW(World Wide Web,互联网)时代之后,IE,Netscape等浏览器都可以通过点击左键下载,那个时候网络速度最快不过5KB/s,下载一首5MB的MP3歌曲要15分钟以上!中途万一断线就前功尽弃,于是有人开发了支持断点续传的下载软件。
世界上第一款支持断点续传的下载软件应该是GetRight。
它可让你用浏览器下载文件时有续传功能,可设定时间来下载文件或是中断Modem拨接,下载完毕时自动中断Modem拨接或关机。
为了更好的利用带宽,在断点续传的基础上,多线程下载软件逐渐发展了起来。
最早出现的多线程下载软件是中国人开发的NetAnts(网络蚂蚁)。
网络蚂蚁其实也是一个断点续传软件,但它对断点续传功能进行了扩展:可进行多点续传,即利用断点续传的原理同时建立多个连接下载同一个软件并最终将其合并为一个完整的软件。
三、P2P时代:下载再也不怕人多挤破服务器最早的P2P网络当属1979年的FidoNet(惠多网)和1984年的Usenet,经过不断发展,才有了现在人们常用的“BT”,“电驴”等P2P软件。
这类软件应用了P2P(Peer-to-Peer)技术,能够最大限度地利用网络带宽。
如今,BitComet、BitTorrent、eMule等P2P软件已经拥有极为庞大的用户群,每个人既是下载者也是上传者,一个新发布的文件转瞬之间就会像燎原之火一样遍布全世界,这是任何服务器都无法比拟的。
四、P2SP时代:多技术结合,进一步提高速度现在人们在整合了HTTP和FTP的服务器技术之后,对BT下载也进行了改进,独创了P2SP技术P2SP(Peer to Server&Peer)即点对服务器和点对点。
P2SP除了包含P2P,还多了一个“S”是指服务器。
P2SP有效地把原本孤立的服务器和其镜像资源以及P2P资源整合到了一起。
在下载的稳定性和下载的速度上,都比传统单一的P2P有了非常大的提高。
1 HTTP协议1.1HTTP协议的发展万维网WWW(World Wide Web) 之父蒂姆•贝纳斯•李早在1990年就提出了超文本传输协议HTTP(Hyper Text Transport Protocol),HTTP是WWW的基本协议,它是一个应用层的,面向对象的协议。
WWW 联盟成立后,组织了IETE ( Internet Engineering Task Force)小组进一步完善和发布HTTP 协议。
至今,HTTP协议经历了0.9、1.0、1.1三个阶段。
各阶段特征如下:1)HTTP/0.9特征:①适用于各种数据信息的简洁快速协议;②具有典型的无状态性;③无连接性;④无法使用内容协商;⑤无法显示和处理图片。
2)HTTP/1.0特征:①简单快速;②无状态性;③无连接性;④无法使用内容协商;⑤增加了元信息:在主要数据前加上一块信息,即信息的信息。
它使服务器能够提供传送数据的有关信息。
例如,传送对象是哪种类型,是用哪种语言书写的等等;⑥支持多种内容的形式,如图片、音频等。
3)HTTP /1.1特征:①持续性连接:允许请求一个web页面的浏览器发起一次连接就可从服务器上下载多个文件;②仍无状态性,但可提供状态控制;③新增加了资源请求:在原有GET、HEAD 、POST 几种方法的基础上增加了OPTIONS、PUT 、DELETE 和TRACE;④身份认证:一种简单的“提问-回答”式的基本访问授权方法。
过程是先由服务器向客户发出身份鉴别请求,再由客户发出确认信息;⑤使用内容协商机制;⑥缓存(Cache) 机制:将先前的客户请求以及请求所对应的Web 服务器响应的内容暂时保存在机器的内存或物理存储器中,使得在处理新的客户请求时可以利用。
目前新一代的HTTP协议:HTTP-NG也已经处于研究阶段,它将很有可能取代现有的HTTP,它的最大变化是是客户机可以一次连续发送多个请求,服务器依次响应每个请求。