当前位置:网站首页>附十七章 网络程序解读限定文章
附十七章 网络程序解读限定文章
2022-06-09 08:50:00 【Maximize+】
前言
这里的话,由于第十七的学习非常抽象,所以一时间很难理解,也无从下手导致一头雾水,这里为了照顾和自己更好掌握和理解,故诞生此文章!
有些程序的东西我也不清楚具体意思,我只能用更抽象更好的理解和记住这个内容的话来讲述,如有不对的地方欢迎指出!
下载网络资源的非断点下载程序解读
我们先看工具类的解读
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
public class DownUtil{
//定义下载资源的路径
private String path;
//指定所下载文件的保存位置
private String targetFile;
//定义需要使用多少个线程来下载资源
private int threadNum;
//定义下载的线程对象
private DownThread[] threads;
//定义下载的文件的总大小
private int fileSize;
public DownUtil(String path,String targetFile,int threadNum){
this.path=path;
this.threadNum=threadNum;
//初始化threads数组
threads = new DownThread[threadNum];
this.targetFile = targetFile;
}
public void download() throws Exception{
var url = new URL(path);
var 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","zn-CN");
conn.setRequestProperty("Charset","UTF-8");
conn.setRequestProperty("Connection","Keep-Alive");
//得到文件的大小
fileSize = conn.getContentLength();
conn.disconnect();
int currentPartSize = fileSize / threadNum + 1;
var file = new RandomAccessFile(targetFile,"rw");
//设置本地文件的小
file.setLength(fileSize);
file.close();
for(var i=0;i<threadNum;i++){
//计算每个线程下载开始的位置
var startPos = i * currentPartSize;
//每个线程使用一个RandomAccessFile进行下载
var currentPart = new RandomAccessFile(targetFile,"rw");
//定位该线程下载的位置
currentPart.seek(startPos);
//创建下载线程
threads[i]=new DownThread(startPos,currentPartSize,currentPart);
threads[i].start();
}
}
//获取下载的完成百分比
public double getCompleteRate(){
//统计多个线程已经下载的总大小
var sumSize = 0;
for(var i =0;i<threadNum;i++){
sumSize += threads[i].length;
}
//返回已经完成的百分比
return sumSize * 1.0/fileSize;
}
private class DownThread extends Thread{
//当前线程下的下载位置
private int startPos;
//定义当前线程负责下载的文件大小
private int currentPartSize;
//当前线程需要下载的文件块
private RandomAccessFile currentPart;
//当前线程下载的字节数
public int length;
public DownThread(int startPos,int currentPartSize,RandomAccessFile currentPart){
this.startPos=startPos;
this.currentPartSize=currentPartSize;
this.currentPart=currentPart;
}
@Override
public void run() {
try{
var url = new URL(path);
var conn = (HttpURLConnection)url.openConnection();
conn.setReadTimeout(5*1000);
conn.setRequestMethod("GET");
conn.setRequestProperty(
"Accept","image/gif,image/jpeg,image/pjpeg,image.pjpeg,"+
"application/x-shockwave-flash,applicaton/xaml+xml,"+
"application/x-ms-application,application/vnd.ms-excel,"+
"application/vnd.ms-powerpoint,application/msword,*/*"
);
conn.setRequestProperty("Accept-Language","zh-CN");
conn.setRequestProperty("Charset","UTF-8");
InputStream inputStream = conn.getInputStream();
//跳过startPos个字节,表明该线程只下载自己负责的那部分文件
inputStream.skip(this.startPos);
var buffer = new byte[5000];
var hasRead = 0;
//读取网络数据,并写入本地文件
while(length<currentPartSize&&(hasRead = inputStream.read(buffer))!=-1){
currentPart.write(buffer,0,hasRead);
//累计该线程下载的总大小
length += hasRead;
}
currentPart.close();
inputStream.close();
}catch (Exception exception){
exception.printStackTrace();
System.out.println("程序遇到异常!");
}
}
}
}
这里我们并不会截图全部程序内部的图片,但是根据复制代码,IDEA工具的行数是不变的,所以根据行数来看我的解读。
解读顺序大部分是按照从上向下来解读,解读内容也都是有关联的。
注:我们本章重点以行数来逐行解读
内容片段都是按照行数解读的,一定要看行数来对照!
程序①解读1

程序①解读2

程序①解读3

程序①解读4

程序①解读5

程序①解读6


其实乍一看这个工具类方法也没有什么复杂的,一拆分看不出什么特别难的,还有这里建议遇到不懂和没见过的类去翻译它的标识符名称或查阅Java API文档,或者去CSDN搜索关键词来有一个大概和详细的认知和学习!
public class MultiThreadDown {
public static void main(String[] args) throws Exception{
//初始化DownUtil对象
final var dowmUtil = new DownUtil("https://pic2.zhimg.com/v2-7e82829cb4ed1598f80c089cd604e292_r.jpg","web.jpg",4);
//开始下载
dowmUtil.download();
new Thread(()->{
while(dowmUtil.getCompleteRate()<1){
//隔隔0.1秒查询依次任务的完成进度
//GUI程序中可根据该进度来绘制进度条
System.out.println("已完成:"+dowmUtil.getCompleteRate());
try{
Thread.sleep(100);
}catch (Exception EX){
}
}
}).start();
}
}
这里是调用工具类的运行类
第一行填入参数 URL,下载本地的路径,和线程数量
然后调用download()方法表明启动线程工具类的核心内容,最后还创建了一个简易的用于获取下载进度的线程。
简单的控制台聊天室
服务器端
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/* 程序核心: 定义了一个线程安全的数组来保存ServerSocket套接字通过 accept()方法接收到的 客户端(Socket)对象 定义一个对应的 Socket s 来接收 accept()方法的返回值 然后直接进入 主机线程类里进行处理 */
public class MyServer {
//定义保存所有Socket的ArrayList,并将其包装为线程安全的
public static List<Socket>socketList = Collections.synchronizedList(new ArrayList<>());
public static void main(String[] args) throws IOException {
var ss = new ServerSocket(30000);
while(true){
//此行代码会阻塞,将一直等待别人的连接
Socket s = ss.accept();
socketList.add(s);
new Thread(new ServerThread(s)).start();//这里我只启动一个客户端 所以就是一次性的线程 只有一个
}
}
}
服务器线程处理
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
/* 程序核心: 导入Runnable函数接口,然后定义了用来接收传进的Socket客户端对象的成员变量 定义了一个输入流 BufferedReader用于读取客户端的消息/信息,构造器进行赋值 br缓冲输入流的赋值为 该 s对象的 getInputStream方法 来获取对象的输入流 run()方法的实现核心逻辑: 定义一个String content变量用来作为读取 s对象输入流的内容 下面while的条件使用了方法的返回值来替代,而非直接是 br.readLine 虽然这样写法意义不大 但是也有专门的实现逻辑 通过 br.readLine()作为判断 返回值为String 如果有内容则返回内容,如果没有则直接返回null while检测到 content为null则直接停止循环 还实现了遍历客户端数组的所有数组并且使用 PrintStream处理流来包装 所有客户端的 OutputStream输出流 来输出 当前content遍历得到的所有内容 也就是说 这个类用于读取客户端发来的消息 并且将该客户端发来的消息全部发到其他客户端里 但是需要其他客户端读取 */
//负责处理每个线程通信的线程类
public class ServerThread implements Runnable{
//定义当前线程所处理的Socket
Socket s = null;
//该线程所处理的Socket对应的输入流 缓冲输入流
BufferedReader br = null;
public ServerThread(Socket s)throws IOException{
this.s=s;
//初始化该Socket对应的输入流
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
}
@Override
public void run() {
try{
String content = null;
/* 这里的 readFromClient()方法的实现逻辑挺有趣的,我也是第一次见到 如果br.readLine有数据就 return 返回值 返回值肯定是一个 String类型的 然后我们的 content再赋值一下 但是如果br.readLine没有数据了 就返回null 而如果 content等于null则停止循环 */
while((content = readFromClient())!=null){
//遍历SocketList中的每个Socket
//将读到的内容向每个Socket发送因此
//这里其实只是单个线程 所以下面的代码实际作用没有什么
/* 这里的实现逻辑也非常简单,content字符串遍历了该Socket的所有OutputStream内容 直接遍历数组的所有 Socket然后获取它们的 OutputStream 然后直接 用一个 PrintStream将我们刚刚的content内容全部输入进去 只要接收到 content数据的Socket使用 BufferedReader方法来读取 OutputStream就会接收到 */
for(var s : MyServer.socketList){
var ps = new PrintStream(s.getOutputStream());
ps.println(content);
}
}
}catch (IOException ex){
ex.printStackTrace();
}
}
public String readFromClient(){
try{
return br.readLine();
}catch (IOException e){
//因为是单独的客户端所以我们不需要专门去数组里删除整个Socket对象
e.printStackTrace();
}
return null;
}
}
客服端
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
/* 程序核心: 客户端类的实现没有什么特别的 创建了一个用于连接服务器的 Socket对象 也是服务器端accept()方法的返回值 启动客户端的处理线程来处理Socket对象 并且创建了一个处理流来进行键盘输出处理 获取了 s的输出流 这里还创建了一个 BufferedReader键盘输入流 用来和服务器交互 */
public class MyClient {
private static String clientName;
public static void main(String[] args) throws Exception{
var s = new Socket("127.0.0.1",30000);//用以连接服务器的 Socket对象 也是 服务器的 accept()方法返回的对象
//客户端启动ClientThread线程不断地读取来自服务器的数据
new Thread(new ClientThread(s)).start();
//获取该Socket对应的输出流
var ps = new PrintStream(s.getOutputStream());
String line = null;
//不断地读取键盘输入
var br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请选择你的阵容:");
System.out.println(" ");
clientName = br.readLine();
while((line = br.readLine())!=null){
ps.println(clientName+" 说: "+line);
}
}
}
客户端线程处理
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
/* 程序核心: 说实话客户端的线程实现类也没有什么特殊的 获取了Socket对象和创建了一个输入流 run()方法体实现逻辑: 读取Socket s对象的Output输出流并将其打印到输出台 */
public class ClientThread implements Runnable{
//该线程负责处理的 Socket
private Socket s;
BufferedReader br = null;
public ClientThread(Socket s) throws IOException {
this.s=s;
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
}
@Override
public void run() {
try{
String content = null;
while((content=br.readLine())!=null){
System.out.println(content);
}
}catch (Exception e){
e.printStackTrace();
}
}
}
如果无法开启多个客户端则去


勾选此选项。
这个程序的实习细节不难,而且也可以用Swing组件包装一下,但是很花费时间。
边栏推荐
- English grammar_ adverb
- 数据库问题MySQL
- RMAN backup concept_ About multiple copies of RMAN backups
- 安装mysql保姆级教程
- Configuring the environment for RMAN backups_ Configure advanced backup options
- Configuring the environment for RMAN backups_ Automatic backup of configuration control files and server parameter files
- In depth analysis: what is the prospect of doing software testing at the age of 25?
- 3D编程模式:依赖隔离模式
- English grammar_ Adverb of place
- RMAN backup concept_ About automatic backup of RMAN control files and server parameter files
猜你喜欢

修改市場活動錶

Hvv蓝队指北

Virtual machine installation and configuration
![[texstudio] [2] general picture and table presentation](/img/1e/bb9488984cb1a3b233978d25f83b6e.png)
[texstudio] [2] general picture and table presentation

RMAN backup concept_ About RMAN incremental backup

Redhat7 cracking (resetting) root password
![[matlab] [digital simulation] [1] linprog solving linear programming, standard type](/img/e2/584ff7809bcad613b157a6a17d53db.png)
[matlab] [digital simulation] [1] linprog solving linear programming, standard type

The energy efficiency management platform of the microgrid of the company promotes the upgrading of the power grid to the energy Internet

修改市场活动表

Implementation of WTM based on NETCORE framework
随机推荐
数据库问题MySQL
Configuring the environment for RMAN backups_ Configure advanced backup options
web知识点123
10 个派上用场的 Flutter 小部件
.NET C#基础(6):命名空间 - 组织代码的利器
NetCore框架WTM的分表分库实现
Document sorting (expansion)
剖析虚幻渲染体系(15)- XR专题
[program life] internet job division; Internet development process; Division of responsibilities
LeetCode 第 295 场周赛
[untitled]
安科瑞Acrel-BUS智能照明控制系统在医院的应用
Configuring the environment for RMAN backups
模拟面试策划书;校园模拟面试策划书;求职模拟面试大赛策划书;经管学院模拟求职大赛策划书;大学生模拟面试大赛策划书
【无标题】
Business judgment logic code if statement
安科瑞综合能效管理系统在数据中心的应用
. Net C # Foundation (6): namespace - a sharp tool for organizing code
Install MySQL nanny tutorial
文件排序 (拓展)