网络编程-协议
2022-05-17 10:39:15 7 举报
AI智能生成
网络编程相关知识
作者其他创作
大纲/内容
Fiddler是位于客户端和服务器端的HTTP代理,也是目前最常用的http抓包工具之一 。 它能够记录客户端和服务器之间的所有 HTTP请求,可以针对特定的HTTP请求,分析请求数据、设置断点、调试web应用、修改请求的数据,甚至可以修改服务器返回的数据,功能非常强大,是web调试的利器。
1.Fiddler是一个独立的应用,可以调试PC、Mac或Linux系统和移动设备的之间的通信,支持大部分框架如java、.net、java、Ruby,需要设置代理。
2.能够暂停Http通讯,并且允许修改请求和响应方便进行安全测试,也可以设置检查点做功能测试。
3.通过暴露HTTP头,用户可以看见哪些页面被允许在客户端或者是代理端进行缓存。如果要是一个响应没有包含Cache-Control头,那么他就不会被缓存在客户端。
4.可以通过Composer进行接口测试。
特点
Fiddler
2. Firebug是开源工具,能够将页面中的CSS、javascript以及网页中引用的图片载入所消耗的时间以矩状图呈现出来,方便我们对网页进行调优。
3.Firebug编辑、删改任何网站的CSS、HTML、DOM以及JavaScript代码,可以通过小箭头定位页面元素。
Firebug
Charles是mac os和windows下的另外一个抓包软件(均收费,可破解),功能与fiddler类似
可以自定义上下行网速、External Proxy、反向代理配置简单、可解析AMF协议数据
优点
Charles树状结构呈现于屏幕,清晰易区分
Fiddler默认按时间倒叙呈现所有接口数据,不易区分
1.接口数据呈现方式对比:
Charles对于https无法直接获取到,可获取的呈现出来也都是乱码,需要安装ssl证书,后面会写具体设置方法。
Fiddler可以直接抓取所有接口数据,无需设置。
2.针对项目App抓取的接口数据全面性对比:
与Firebug相比
Charles
实时分级时间展示图能够展示一个http/https请求的处理过程;通过不同的颜色展示网络请求计时,如DNS查询,tcp连接;以瀑布形式展示浏览器事件,例如从浏览器渲染和页面加载计时就开始了,可以自动检查性能问题。
安装简单,不需要设置代理和证书;提供接口API可以被大部分编程语言自动化调用、录制、保存结果。
只能看不能修改
httpwatch
抓包工具
网络爬虫是按照一定的规则,自动的抓取万维网信息的程序或者脚本
PHP:PHP是世界是最好的语言,但他天生不是做这个的,而且对多线程、异步支持不是很好,并发处理能力弱。爬虫是工具性程序,对速度和效率要求比较高。
Java:生态圈很完善,是Python爬虫最大的竞争对手。但是Java语言本身很笨重,代码量很大。重构成本比较高,任何修改会导致代码大量改动。爬虫经常要修改采集代码
C/C++:运行效率是无敌的。但是学习和开发成本高。写个小爬虫程序可能要大半天时间
Python:语法优美、代码简洁、开发效率高、支持的模块多。相关的HTTP请求模块和HTML解析模块非常丰富。还有Scrapy和Scrapy-redis框架让我们开发爬虫变得异常简单
编程语言分类爬虫
通用爬虫:通用爬虫是搜索引擎抓取系统的重要组成部分,主要是将互联网上的网页下载到本地,形成一个互联网内容的镜像备份。
1,确定爬取的url,模拟浏览器向服务器发起请求;
2,获取响应数据并进行数据解析;
3,将目标数据持久化到本地;
聚焦爬虫设计思路
1,请求方法:request method
2,请求网址:request URL
3,请求头:request headers
4,请求体:request
请求
聚焦爬虫:聚焦爬虫指针对某一领域根据特定要求实现的爬虫程序,抓取需要的数据(垂直领域爬取)
功能分类
搜索引擎(百度, 谷歌)
例子
网络爬虫
内存模型
内存交换
CAS
happen-before
as-if-serial
顺序一致性模型
双重检查锁定的问题
实践
AQS
非阻塞数据结构
原子变量类
JUC包的实现基石
volatile内存语义
synchronized锁的优化
内存屏障
volatile的实现原理
多线程概念问题
进程是资源分配的最小单位,线程是CPU调度的最小单位
线程和进程
并行性是指同一时刻内发生两个或多个事件。
并行
并发性是指同一时间间隔内发生两个或多个事件。
并发
并行和并发
线程的生命周期
线程不安全
同步代码块
同步方法
静态同步方法
Lock锁
同步方式使用互斥锁机制
线程同步
线程通信指线程之间以什么机制交换信息
有共享内存和消息传递两种方式
线程通信概念
共享变量volatile(共享内存)
synchronized(共享内存)
等待/通知机制(消息传递)
管道输入/输出流(消息传递)
线程通信方式
线程通信
线程基础问题
继承Thread,重写run方法
实现Runnable接口,重写run方法
一般我们使用实现Runnable接口,可以避免java中的单继承的限制,并发运行任务和运行机制解耦
Java使用Thread类来表示线程,有两种方式创建线程
主线程叫做main,其他线程是Thread-x
线程名
守护线程作为一个服务线程,没有服务对象就没有必要继续运行了
在线程启动前设置为守护线程,方法是setDaemon(boolean on)
使用守护线程不要访问共享资源(数据库、文件等),因为它可能会在任何时候就挂掉了。
守护线程中产生的新线程也是守护线程
使用守护线程需要注意的地方
守护线程
线程优先级高仅仅表示线程获取的CPU时间片的几率高,但这不是一个确定的因素!
线程的优先级是高度依赖于操作系统的
优先级线程
调用sleep方法会进入计时等待状态,等时间到了,进入的是就绪状态而并非是运行状态!不会释放锁
sleep方法
调用yield方法会先让别的线程执行,但是不确保真正让出不会释放锁
yield方法
调用join方法,会等待该线程执行完毕后才执行别的线程~会释放锁,底层调用wait()方法
join方法
interrupt不会真正停止一个线程,它仅仅是给这个线程发了一个信号告诉它,它应该要结束了。是否中断,由被通知线程决定interrupt方法压根是不会对线程的状态造成影响的,它仅仅设置一个标志位罢了
静态方法interrupted()-->会清除中断标志位
实例方法isInterrupted()-->不会清除中断标志位
interrupt线程中断还有另外两个方法(检查该线程是否被中断):
interrupt方法
Thread类
synchronized是Java的一个关键字,它能够将代码块(方法)锁起来
JVM基于 进入和退出Monitor对象来实现方法同步和代码块同步
每个对象有自己的对象头,存储了很多信息,其中有一个标志位指向 Monitor。当一个monitor被某一个线程持有后,其标志位 Owner被赋值为该线程唯一标志
简介
原子性
可见性
性质
锁的持有者是“线程\",而不是”调用“
可重入锁
公平锁:线程将按照它们发出请求的顺序来获取锁
非公平锁:线程发出的请求时可以插队获取锁
Lock和synchronized都是默认使用非公平锁的,公平锁会带来一些性能的损耗
公平锁与非公平锁
静态方法获取的是类锁(类的字节码文件对象)
synchronized修饰普通方法或代码块获取的是对象锁
获取了类锁的线程和获取了对象锁的线程是不冲突的
类锁与对象锁
JDK1.6开始synchronized锁就做了各种优化
优化操作:适应自旋锁,锁消除,锁粗化,轻量级锁,偏向锁
synchronized锁升级
synchronized锁
Lock方式来获取锁支持中断、超时不获取、是非阻塞的
支持Condition条件对象
Lock显式锁可以给我们带来很好的灵活性,但同时我们必须手动释放锁
允许多个读线程同时访问共享资源(读写锁)
AQS(队列同步器)是一个用来构建锁和其他同步组件的基础框架
内部实现的关键是: volatile int 的成员变量state表示同步状态FIFO队列完成线程获取资源的排队工作一个指向获取当前锁的 线程变量
独占模式
共享模式
拥有两种线程模式
在LOCK包中的相关锁(常用的有ReentrantLock、 ReadWriteLock)都是基于AQS来构建
修改state状态值时使用CAS算法来实现
等待列被称为:CLH队列(三个名字组成),是一个双向队列
定义了框架,具体实现由子类来做(模板模式)!
细节
Lock锁底层原理(AbstractQueuedSynchronizer简称为AQS)
比synchronized更有伸缩性(灵活)
使用时最标准用法是在try之前调用lock方法,在finally代码块释放锁
ReentrantLock锁
在读的时候可以共享,在写的时候是互斥的
读锁不能升级为写锁,写锁可以降级为读锁
在内部定义了两个内部类来代表读锁和写锁,本质上还是AQS实现
它使用state的变量高16位是读锁,低16位是写锁
ReentrantReadWriteLock锁
在死锁时,线程/进程间相互等待资源,而又不释放自身资源,导致无穷无尽的等待,其结果是任务永远无法执行完成。
1. 互斥条件: 一个资源每次只能被一个线程/进程使用
2. 请求与保持条件: 一个线程/进程因请求资源而在阻塞时,对已获得的资源保持不放
3. 不可剥夺条件:线程/进程已获得的资源,在未使用完之前,不能强行剥夺
4. 循环等待条件:若干线程/进程之间形成一种头尾相接的循环等待资源关系
产生死锁的四个必要条件
避免死锁
死锁检测和解除
死锁
Java锁机制
某个线程等待其他线程执行完毕后,它才执行(其他线程等待某个线程执行完毕后,它才执行)
CountDownLatch(闭锁)
一组线程互相等待至某个状态,这组线程再同时执行。
CyclicBarrier
控制同时访问的线程个数
Semaphore
同步工具类
ThreadLocal的作用是提供线程内的局部变量,每个线程都可以通过set()和get()来对这个局部变量进行操作,但不会和其他线程的局部变量进行冲突,实现了线程的数据隔离
减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。 比如将Connection与当前线程绑定。保证了能进行事务控制。
常见的应用
Thread为每个线程维护了ThreadLocalMap这么一个Map,而ThreadLocalMap的key是ThreadLocal对象本身,value则是要存储的对象
想要避免内存泄露就要手动remove()掉!
ThreadLocal设计的目的就是为了能够在当前线程中有属于自己的变量,并不是为了解决并发或者共享变量的问题
实现原理
ThreadLocal
原子类可分为4种类型:基本数据类型、数组、引用类型、对象的属性
Atomic包里的类基本都是使用Unsafe实现的包装类 (CAS)
解决ABA问题可以使用AtomicStampedReference类(加上了版本号)
分段CAS
自动迁移
LongAdder性能比AtomicLong要好
Atomic原子类
多线程
通过重复利用已创建的线程降低线程的创建和销毁造成的消耗
降低资源消耗
当任务到达时,任务可以不需要等到线程创建就立即执行
提高响应速度
线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性。使用线程池可以进行统一分配,调优和监控。
提高线程的可管理性
线程池的好处
线程池框架
线程池生命周期
执行流程
高3位表示线程池状态,低29位表示任务线程的数量
变量ctl定义为AtomicInteger,记录了“线程池中的线程数量”和“线程池的状态”两个信息。
RUNNING:线程池能够接受新任务,以及对新添加的任务进行处理。
SHUTDOWN:线程池不可以接受新任务,但是可以对已添加的任务进行处理。
STOP:线程池不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。
TIDYING:当所有的任务已终止,ctl记录的\"任务数量\"为0,线程池会变为TIDYING状态。
TERMINATED:线程池彻底终止的状态。
线程状态就定义了好几种:
构造函数成员变量详解
ThreadPoolExecutor详解
如果运行线程的数量少于核心线程数量,则创建新的线程处理请求 如果运行线程的数量大于核心线程数量,小于最大线程数量,则当队列满的时候才创建新的线程 如果核心线程数量等于最大线程数量,那么将创建固定大小的连接池 如果设置了最大线程数量为无穷,那么允许线程池适合任意的并发数量
线程数量策略
当前线程数大于核心线程数,如果空闲时间已经超过了,那该线程会销毁。
线程空闲时间
同步移交:不会放到队列中,而是等待线程执行它。如果当前线程没有执行,很可能会新开一个线程执行。 无界限策略:如果核心线程都在工作,该线程会放到队列中。所以线程数不会超过核心线程数 有界限策略:可以避免资源耗尽,但是一定程度上减低了吞吐量
跟阻塞队列相关
排队策略
拒绝任务策略
线程池有各种的策略:
它将返回一个corePoolSize和maximumPoolSize相等的线程池
newFixedThreadPool
非常有弹性的线程池,对于新的任务,如果此时线程池里没有空闲线程,线程池会毫不犹豫的创建一条新的线程去处理这个任务。
newCachedThreadPool
单个worker线程的Executor
SingleThreadExecutor
提供了“延迟”和“周期执行”任务的功能
ScheduledThreadPoolExecutor
Executors中已默认实现的池
如果线程池中运行的线程数量<corePoolSize,则创建新线程来处理请求,即使其他辅助线程是空闲的。
1.如果线程池不是RUNNING状态,且成功从阻塞队列中删除任务,则该任务由当前 RejectedExecutionHandler 处理。
如果线程池中运行的线程数量>=corePoolSize,且线程池处于RUNNING状态,且把提交的任务成功放入阻塞队列中,就再次检查线程池的状态因为将任务放入阻塞队列过程中线程池可能关闭了,或者说某个线程被回收了。
如果以上两种case不成立,即没能将任务成功放入阻塞队列中,且addWoker新建线程失败,说明线程池关闭了,或者队列饱和了 则该任务由当前 RejectedExecutionHandler 处理。
execute执行方法
调用shutdown()后,线程池状态立刻变为SHUTDOWN,而调用shutdownNow(),线程池状态立刻变为STOP。
shutdown()等待任务执行完才中断线程,而shutdownNow()不等任务执行完就中断了线程
线程池关闭
IO密集
CPU密集
如何合理地配置线程池大小
线程数合理配置
线程池
主要是多个线程对同一变量进行操作时,程序没有按照预期情况执行
在java语言中,不可变的对象一定是线程安全的,无论是对象的方法实现还是方法的调用者,都不需要再采取任何的线程安全保障措施。final关键字修饰的类或数据不可修改,可靠性最高。如 String类,Integer类。
不可变
Ad-hoc线程封闭是指维护线程封闭性的职责完全由程序实现来承担。Ad-hoc线程封闭是非常脆弱的,因为没有任何一种语言特性,例如可见性修饰符或局部变量,能将对象封闭到目标线程上。事实上,对线程封闭对象(例如,GUI应用程序中的可视化组件或数据模型等)的引用通常保存在公有变量中。
Ad-hoc 线程封闭
ThreadLocal线程封闭
堆栈封闭其实就是方法中定义局部变量。不存在并发问题。多个线程访问一个方法的时候,方法中的局部变量都会被拷贝一份到线程的栈中(Java内存模型),所以局部变量是不会被多个线程所共享的。
堆栈封闭
线程封闭
同步的最常用的方法是使用锁(Lock),它是一种非强制机制,每个线程在访问数据或资源之前首先试图获取锁,并在访问结束之后释放锁;在锁已经被占用的时候试图获取锁时,线程会等待,直到锁重新可用。
synchronized
Lock.lock()/Lock.unLock()
实现方式
悲观锁
先进行操作,如果没有其他线程争用共享数据,那操作就成功了;如果共享数据有争用,产生了冲突,那就再采用其他的补偿措施。这种乐观的并发策略的许多实现都不需要把线程挂起,因此这种同步操作称为非阻塞同步
为了避免ABA问题,一般增加个版本号进行对比控制
非阻塞的实现CAS(Compare-and-Swap)
乐观锁
同步
同步容器的工具有Vector、HashTable、Collections.synchroniedXXX()
ConcurrentHashMap
CopyOnWriteArrayList
并发容器(JUC)
AQS是一个同步器,设计模式是模板模式
aqs全称为AbstractQueuedSynchronizer,它提供了一个FIFO队列,可以看成是一个用来实现同步锁以及其他涉及到同步功能的核心组件,常见的有:ReentrantLock、CountDownLatch等。
独占锁,每次只能有一个线程持有锁
共享锁,允许多个线程同时获取锁,并发访问共享资源
AQS功能
AQS的内部实现
JUC同步器 AQS
工具类
解决办法
线程安全
get与post为http请求的两种方式
GET 请求可被缓存
GET 请求保留在浏览器历史记录中
GET 请求可被收藏为书签
GET 请求不应在处理敏感数据时使用
GET 请求有长度限制
GET 请求只应当用于取回数据
从指定的资源请求数据。
get
POST 请求不会被缓存
POST 请求不会保留在浏览器历史记录中
POST 不能被收藏为书签
POST 请求对数据长度没有要求
向指定的资源提交要被处理的数据。
post
GET在浏览器回退时是无害的,而POST会再次提交请求。
GET产生的URL地址可以被Bookmark,而POST不可以。
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
GET请求只能进行url编码,而POST支持多种编码方式。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
GET请求在URL中传送的参数是有长度限制的,而POST么有。
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
GET参数通过URL传递,POST放在Request body中。
区别
GET和POST
当网络通信时采用TCP协议时,在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接,连接的建立是需要三次握手的,而释放则需要4次挥手,所以说每个连接的建立都是需要资源消耗和时间消耗的
长连接,指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接,一般需要自己做在线维持(不发生RST包和四次挥手)。
长连接
短连接是指通信双方有数据交互时,就建立一个TCP连接,数据发送完成后,则断开此TCP连接(管理起来比较简单,存在的连接都是有用的连接,不需要额外的控制手段);
短连接
长连接多用于操作频繁(读写),点对点的通讯,而且连接数不能太多情况,。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费
而像WEB网站的http服务一般都用短链接(http1.0只支持短连接,1.1keep alive 带时间,操作次数限制的长连接),因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好;
应用场景
长连接跟短连接
把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
在网络上传送对象的字节序列。
主要用途
序列化:把Java对象转换为字节序列的过程。
反序列化:把字节序列恢复为Java对象的过程。
JSON中的元素都是键值对——key:value形式,键值对之间以\":\"分隔,每个键需用双引号引起来,值的类型为String时也需要双引号。其中value的类型包括:对象,数组,值,每种类型具有不同的语法表示。
语法
json数据中地值(value)可以是双引号括起来的字符串(string)、数值(number)、true、false、 null、对象(object)或者数组(array)。这些结构可以嵌套。
字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。
数值(number)也与C或者Java的数值非常相似。除去未曾使用的八进制与十六进制格式。除去一些编码细节。
基础类型
对象是一个无序的键值对集合。以\"{\"开始,以\"}\"结束, 每个成员以\
对象
数组是一个有序的集合,以\"[\"开始,以\"]\"结束,成员之间以\
数组
Json
Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,它是 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
Protobuf
可扩展标记语言(英语:Extensible Markup Language,简称:XML),是一种标记语言。标记指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种信息的文章等
XML
常见的序列化格式
技术层面,序列化协议是否支持跨平台、跨语言。如果不支持,在技术层面上的通用性就大大降低了。
流行程度,序列化和反序列化需要多方参与,很少人使用的协议往往意味着昂贵的学习成本;另一方面,流行度低的协议,往往缺乏稳定而成熟的跨语言、跨平台的公共包。
通用性
成熟度不够,一个协议从制定到实施,到最后成熟往往是一个漫长的阶段。协议的强健性依赖于大量而全面的测试,对于致力于提供高质量服务的系统,采用处于测试阶段的序列化协议会带来很高的风险。
语言 / 平台的不公平性。为了支持跨语言、跨平台的功能,序列化协议的制定者需要做大量的工作;但是,当所支持的语言或者平台之间存在难以调和的特性的时候,协议制定者需要做一个艰难的决定 -- 支持更多人使用的语言 / 平台,亦或支持更多的语言 / 平台而放弃某个特性。当协议的制定者决定为某种语言或平台提供更多支持的时候,对于使用者而言,协议的强健性就被牺牲了。
强健性 / 鲁棒性
支持不到位,跨公司调试在问题出现后可能得不到及时的支持,这大大延长了调试周期
访问限制,调试阶段的查询平台未必对外公开,这增加了读取方的验证难度。
可调试性 / 可读性
可扩展性 / 兼容性
因为访问限制而降低服务可用性;
被迫重新实现安全协议而导致实施成本大大提高;
开放更多的防火墙端口和协议访问,而牺牲安全性。
如果使用的序列化协议没有兼容而成熟的 HTTP 传输层框架支持,可能会导致以下三种结果之一
安全性 / 访问限制
空间开销(Verbosity), 序列化需要在原有的数据上加上描述字段,以为反序列化解析之用。如果序列化过程引入的额外开销过高,可能会导致过大的网络,磁盘等各方面的压力。对于海量分布式存储系统,数据量往往以 TB 为单位,巨大的的额外空间开销意味着高昂的成本。
时间开销(Complexity),复杂的序列化协议会导致较长的解析时间,这可能会使得序列化和反序列化阶段成为整个系统的瓶颈。
性能
序列化协议的特性
可调式性/可读性
稳定性
可扩展性
序列化和反序列化协议选择原则
序列化跟反序列化
网络编程
0 条评论
回复 删除
下一页