网络编程之整体认知

网络编程

注:本博客由 Stormzhang 邪教群内讲课整理而来。

主要指Http和socket

Http 协议跟 Socket 有什么区别?

HTTP 特性

  1. Http 是无状态的协议,每次发出请求第一步都是客户端与服务端建立连接,连接成功之后把数据传过去,服务器收到数据进行响应,然后再回传结果给客户端。这一次请求结束之后连接就断开了,下次再发新的请求就会再重新建立连接。
  2. 假设有 1W 个用户,用 Http 则同时连接服务器用户可能只有1K个。因为其他用户请求完就断开连接了。Http 每次都要重新建立连接,导致效率上没有 Socket 高效
  3. Http 也可以实现长连接
  4. Http 包含请求(request:url、method、参数、header)和响应(response)两大块
  5. Http 请求方法包含get、post、delete、put、head、patch、trace、options,常见的为get和post,后6种为post衍生出来的,需要关注了解 put 和 delete 方法,这四种方法对应 REST 原则,也就是 RESTful 架构,类似于数据库增删改查
  6. get 请求参数可以为 url 问号后的字符拼接(http://www.baidu.com/?key1=value&key2=value2)
  7. post请求参数为键值对形式,不会直接显示,在 form 或者 body params 里传递

SOCKET 特性

  1. socket协议意思就是长连接,言外之意就是发数据之后,连接不会断开,会一直保持连接。
  2. 如果用socket可能同时会有1w个人连接服务器,这个就比较浪费服务器资源,消耗带宽。但是socket的优势也很明显,因为一直保持连接,每次用户发送数据都很快,不用重新建立连接的过程。

http与socket都是基于tcp/ip协议

Http 使用场景

  1. 留言、页面加载

Socket 应用场景

  1. IM(即时通讯)
  2. 长连接

REST架构

Http请求的 get 、post、delete、put这四种方法对应 REST 原则,也就是 RESTful 架构,类似于数据库增删改查

假设我们有如下需求:查询学生数量,创建新学生,修改学生信息,删除学生

原始接口实现(仅使用了 ge t和 post 方法):

get  /api/student/index  查询接口
post  /api/student/   携带一些 params 是创建接口
post  /api/student/update  携带一些参数   修改接口
post  /api/student/delete 携带参数  删除接口

基于REST实现:

get  /api/student/index  查询接口   不变
post  /api/student/   携带一些 params 是创建接口  不变
put  /api/student/ 携带一些参数   修改接口
delete  /api/student/携带参数  删除接口

二者区别:

修改跟删除直接用 http 的 method 来指定,url 哪怕一样,就可以轻松知道你的动作,这就是所谓的 restful 概念最重要的一个理念

header的概念

header的作用有很多,比如客户端告诉服务端,我发起的请求是什么语言,我发起的请求带的参数是什么格式的,是json还是哈希,我发起的请求需不需要带缓存,我发起的请求需要压缩等,这些信息都是通过header 传递的。

服务端在返回结果的时候也有一些信息告诉客户端的,同样在 header 里传递,比如我返回的数据是什么格式的,我这次请求是不支持缓存的,我这次返回的数据没有压缩等。

header 里的信息都是一个个的哈希,即 key value 对。比如大家常见的一些 header 里的信息:

  1. Content-Type: application/json
  2. Cache-Control : true 等

header里默认的有很多字段,这是规定,当然你也可以自定义一些字段在里面传递,只要跟你们服务端约定好就行

这里有个字段叫做 Connection: keep-alive

http如果每次都请求断开未免太没效率了,后来有人就发现 一般我在发起一个请求之后,可能紧接着就发起第二个请求了,于是就有了这个字段这个字段顾名思义,就是声明连接的类型

这个字段有两个值:close 和 keep-live
如果你指定 close,那么每次请求就会立马断开连接
如果你指明了 keep-live,就可以在一段时间内保持长连接,这个时间服务端可以自行配置,但是时间也不会太长,不然服务器会很吃紧,比如设置个30s,意味着这30s的时间内不会重新断开重连
默认值是keep-alive

Response

response 意为服务端返回的值, response也会有header,以及返回值
比如你请求百度,返回的就是一段 html 代码,只不过浏览器渲染成了一个页面而已,网页源代码才是真正的返回结果
对于app中,目前大部分的response都是json格式的数据
Android中有各种各样的json数据解析器,如gson、jackson、FastJson等等

状态码(http status)

一般是 200—500
比如正常的时候返回的 status 就是200,代表成功
大家常见的status code有 404 找不到
500 服务器挂了
一般是200开头的大多是成功
30x代表重定向,其中304是服务端告诉你内容没有改变,意为缓存的内容

http缓存

缓存是开发中最常见的一环,可以算是性能优化的一个大点了。

缓存有两部分,客户端和服务端。

做客户端的会以为缓存只有客户端才有,其实服务端更有,因为假设你每查一个数据,服务端都要到数据库重新查询一遍,那服务器压力得有多大,所以服务器会有一个缓存机制。

缓存有两种机制,第一种最常见的就是时间缓存,比如我查询中国的城市信息,对于这部分假设我就设置7天的缓存时间,意味着客户端每次请求,服务端一次查询数据库,7天之内都不会再查询数据库,直接返回给你上一次的结果,对应的 status code 就是304,这对服务器性能优化是很大的一环。

缓存有没有生效一般用 header里的 cache-control 字段控制。
如果客户端传递 cache-control 字段为 true 那么服务端有缓存的话就会启动缓存,
如果传递 false 那么会强制服务端每次都去数据库里查询,
缓存的时间有一个字段叫做 expired 字段,告诉你缓存过期的时间。

所以一般来说,如果性能优化的话会有这么一个点,客户端发起一个请求,服务端返回数据,并且告诉客户端我这个请求有缓存的,缓存时间是7天,那么客户端就可以把这个请求结果缓存在本地,然后7天之内都不再发起请求,直接读取本地的缓存数据,那么会极大的节省服务器资源。
以时间为缓存的大多为那些请求数据不常变化的。

但大多数场景是数据经常变化,比如我刷个微博,微博变化很快,可能1小时不会变化,但也可能1分钟就有更新,这种缓存就没法用固定的时间来进行衡量了,所以第二种缓存叫做 Etag缓存

Etag 你们可以理解成就是一个唯一的字符串。
这个字符串是服务端根据时间、用户标识、内容索引等生成的一个字符串。
一旦用户的内容变化,这个Etag就会变化,如果用户内容不变化,那么Etag也不会变化

所以刷微博的话机制就是这样的,客户端发起一个请求,服务端返回了一个数据,告诉客户端,我是有缓存的,缓存的 Etag 值也返回给你了,然后我把返回的数据以及 Etag 缓存到本地
这样下次请求的话如果数据没有变化,那么服务端不会返回给你数据了,而只会返回一个 Etag值,拿到这个Etag值之后到本地去找这个Etag缓存对应的数据,直接渲染。

注意: Etag的比较和对应的数据包都是在服务端完成的。

Etag的缓存其实才是目前使用最多的缓存策略
主流网络库都会默认支持这两种缓存,也就说volley或者okhttp都会支持的

以volley为例,他内部实现了缓存机制,每次请求之后如果服务端支持缓存的话,他自己只直接在本地进行缓存的。
也就是说 如果服务端返回了 304 ,并返回了Etag,volley会自动去本地寻找上次缓存过的数据进行渲染。

客户端一般使用文件缓存,如volley

volley的缓存机制是这样的,下次发起请求,服务端返回 304 ,那么volley就默认直接到本地缓存去找,问题是,如果用户没有网,那么发起请求,服务端根本没有响应,这时候volley默认的是不知道去本地去找的,因为他没有接受到304的信号,所以说如果想要没网的时候去本地读取缓存,这样用户体验会更好点,这个时候需要自己去做处理的。

第一次请求肯定没有 Etag 的,第一次也没有缓存,服务端会直接返回给你数据以及Etag。

第二次之后会把Etag请求给服务端,但是把Etag提交给服务端网络库会自动携带的,一般不需要关心。

如果分页做缓存的话最好用数据库了,一般只做了单页缓存,没网的时候起码让用户看到内容,也就是说用户一进来最好能让他看到一些数据做占位符。