前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >网络相关知识

网络相关知识

作者头像
六月的雨
发布2020-04-08 17:45:04
6220
发布2020-04-08 17:45:04
举报
文章被收录于专栏:Android开发指南

HTTP

一次http网络请求的过程 浏览器发起请求-> 解析域名得到ip进行TCP连接 ->浏览器发送HTTP请求和头信息发送->服务器对浏览器进行应答,响应头信息和浏览器所需的内容-> 关闭TCP连接或保持-> 浏览器得到数据数据进行操作。 先找到对方ip地址,然后用指定的传输协议传送到指定的端口。

HTTP分层

  • Application Layer 应用层:HTTP、FTP、DNS
  • Transport Layer 传输层(通讯规则、传输协议):TCP、UDP(负责传输,找到端口)
  • Internet Layer 网络层:IP(负责连接,找到IP)
  • Link Layer 数据链路层:以太网、Wi-Fi(以太网:网线,为网络提供现实世界(物理设备的支持))

为什么要分层? 因为网络的不稳定性,所以要url分块传输

常见通讯规则、传输协议:TCP/UDP

  • UDP(面向无连接)-->聊天、网络视频会议、步话机 DatagramSocket 将数据及源和目的封装成数据包中,不需要建立连接 每个数据包的大小限制在64k内 因无连接,是不可靠的协议 不需要建立连接,速度快
  • TCP(面向连接)-->下载,打电话 ServiceSocket 建立连接,形成传输数据的通道 在连接中进行大数据量的传输 通过三次握手完成连接,是可靠的协议 必须建立连接,效率会稍低

什么是iP地址 Internet上的主机有两种方式表示地址: 域名:www.baidu.com, IP 地址:202.108.35.210 ,域名容易记忆,当在连接网络时输入一个主机的域名后,域名服务器(DNS)负责将域名转化成IP地址,这样才能和主机建立连接。

什么是端口 用于标识进程的逻辑地址,不同进程的标识,有效地址065535,其中01024系统使用或保留端口。

HTTP协议版本 HTTP/1.0

  • 链接后,只能获取一个web资源。
  • 链接后,发送请求,服务器做出响应,链接立即断开。

HTTP/1.1

  • 链接后,可以获取多个web资源。
  • 链接后,发送请求,服务器做出响应,链接不会立即断开。再次发送请求,直接有一段时间没操作,自动断开。(服务端可以配置)

三次握手 SYN,SYN/ACK,ACK

syn 客户端发送syn包给服务器,进入服务状态 syn-ack 服务器收到,客户端确实并发送给syn.这时进去接受状态 ack 客户端收到服务端的syn-ack,并向服务器确认,此时链接成功!

第一次本方发送请求,第二次对方确认连接,第三次本方再次发送确认信息告诉对方,这样双方就都知道了,从而才能建立连接。

三次握手的目的,两次行不行? 为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误的问题,网络不好的话不知道双方的状态。

四次挥手

fin 发送请求连接 ack 同意断开连接 fin+ack 服务端断开连接 ack 同意断开

四次关闭,我要把你忘掉 1.我不要消息了 2.我知道了 3.我没有消息给你发了 4.我知道了

为什么 TCP 连接在断开时是四次挥手而不是三次? 因为在客户端停止向服务器发送消息时,也许服务器还有消息需要向客户端发送,因此在它对客户端的「Fin」(即「我不再给你发送消息」)消息进行回应时,不需要立即附加上「我也不再向你发送消息」。在稍后服务器的消息发送完毕之后,才需要向客户端发送通知。

Keep-Alive 从HTTP/1.1起,默认都开启了Keep-Alive,保持连接特性,简单地说,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。虽然这里使用TCP连接保持了一段时间,但是这个时间是有限范围的,到了时间点依然是会关闭的,所以我们还把其看做是每次连接完成后就会关闭。

Socket Socket就是为网络服务提供的一种机制,通讯的两端都必须有Socket(套接字,就是接口的意思),网络通讯其实就是Socket间的通讯,数据在两个Socket间通过IO传输,IP 地址标识 Internet 上的计算机,端口号标识正在计算机上运行的进程(程序)。 端口号与IP地址的组合得出一个网络套接字。 创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。

Socket则是对TCP/IP协议的封装和应用 1)创建客户端对象: Socket(String host,int port),指定要接收的IP地址和端口号 2)创建服务端对象:ServerSocket(int port):指定接收的客户端的端口 3)Socket accept():侦听并接受到此套接字的连接,服务器用于接收客户端socket对象的方法 主要通过S.getOutputstream和S.getInputSteram 注:服务器没有socket流,也就没有读写操作的流,服务器是通过获取到客户端的socket流(accept)然后获取到其中的读写方法,对数据进行操作的,也正是因为这样服务器与客户端的数据操作才不会错乱

HTTP的缺点 通信使用明文,内容可能被窃听 不验证通信方身份,因此有可能遭遇伪装

http缓存

Pragma和Cache-control共存时,Pragma的优先级是比Cache-Control高的。

only-if-cached表示不进行网络请求,完全只使用缓存,若缓存不命中,则返回503错误

  • max-age:告知缓存多长时间,在没有超过缓存时间的情况下,请求会返回缓存内的数据,在超出max-age的情况下向服务端发起新的请求,请求失败的情况下返回缓存数据(测试中已验证),否则向服务端重新发起请求。
  • max-stale:指示客户机可以接收超出max-age时间的响应消息,max-stale在请求设置中有效,在响应设置中无效。因此max-age和max-stale在请求中同时使用的情况下,缓存的时间可以为max-age和max-stale的和。
OKHTTP一般控制缓存有两种方式

1、在request里面去设置cacheControl()策略 2、在header里面去添加cache-control Android okhttp缓存真正正确的实现方式 有网时不缓存,没网时设置缓存,通过Cache-Control和max-age

代码语言:javascript
复制
public class HttpCacheInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    if (!NetWorkHelper.isNetConnected(MainApplication.getContext())) {
        request = request.newBuilder()
                .cacheControl(CacheControl.FORCE_CACHE)
                .build();
    }

    Response response = chain.proceed(request);

    if (NetWorkHelper.isNetConnected(MainApplication.getContext())) {
        int maxAge = 60 * 60; // 如果想要不缓存,直接时间设置为0,但是需要保存下来吧
        response.newBuilder()
                .removeHeader("Pragma")
                .header("Cache-Control", "public, max-age=" + maxAge)
                .build();
    } else {
        int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale
        response.newBuilder()
                .removeHeader("Pragma")
                .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                .build();
    }
    return response;
  }}

  //设置缓存100M
        Cache cache = new Cache(new File(MainApplication.getContext().getCacheDir(),"httpCache"),1024 * 1024 * 100);
        return new OkHttpClient.Builder()
            .cache(cache)
            .addNetworkInterceptor(new HttpCacheInterceptor())
            .build();

HTTPS

  • HTTPS并不是一个单独的协议,对于一些隐秘性比较高的数据可以用https协议。( 它是在TCP层与http层之间加了个SSl/TLS。TLS是SSL v3.0的升级版,而SSL协议,是一种安全传输协议。)
  • SSL/TLS层负责客户端和服务器之间的加解密算法协商、密钥交换、通信连接的建立。 主要用到对称加密、非对称加密、证书,等技术进行客户端与服务器的数据加密传输,最终达到保证整个通信的安全性。
  • 说白了就是加密通信的 HTTP

SSL/TLS防止的安全风险:

  1. 窃听风险
  2. 篡改风险
  3. 冒充风险

SSL/TLS防止的安全风险原理:

  1. 加密:非对称加密+对称加密,主要解决的是窃听风险
  2. 校验:数字签名,主要解决的是篡改风险
  3. 证书:数字证书,主要解决的是冒充风险

非对称加密

  • 对称加密的问题:秘钥如何保存和传输(非对称加密算法)
  • “非对称加密”加密算法,特点是私钥加密后的密文,只要是公钥,都可以解密,但是公钥加密后的密文,只有私钥可以解密。私钥只有一个人有,而公钥可以发给所有的人。
  • 非对称加密一般不会单独拿来使用,他并不是为了取代对称加密而出现的,非对称加密速度比对称加密慢 很多,极端情况下会慢 1000 倍,所以一般不会用来加密大量数据,通常我们经常会将对称加密和非对称 加密两种技术联合起来使用,例如用非对称加密来给称加密里的秘钥进行加密(即秘钥交换)。

数字签名

数字签名技术结合Hash算法和加密算法,来防止消息被篡改和进行身份认证。 数字签名就是:发送方使用自己的私钥对信息摘要加密产生

  1. 发送方使用Hash算法对原文产生信息摘要,原文不变则信息摘要不变。
  2. 发送方使用自己的私钥对信息摘要加密产生数字签名,并和加密的原文一起发送。
  3. 接收方使用发送方的公钥解密获取数字签名
  4. 接收方使用Hash算法对原文计算信息摘要与解密的信息摘要比对,成功表示未篡改、未成功表示篡改。

数字证书

数字签名一般不单独使用,基本都是用在数字证书里实现 SSL 通信协议。

第三步:请求网址后返回证书的公钥和数字证书,客户端验证数字证书的有效性,是ca的,怎么验证的?数字签名,都有标准的,x509 第四步:通过后,使用公钥加密内容,非对称加密加密分别对公钥和内容信息摘要(hash,数字签名),发送 第六步:非对称加密解密对称加密的key,然后通过对称加密的key解密内容

在 Android 中使用 HTTPS

正常情况:直接使用 okhttp中就能验证自己的签名,就是为了让己的签名通过验证。 如果是ca机构的证书,OKHTTP不需要配置直接就可以访问,如果是自定义的证书,OKHTTP就不行了,但是可以信任指定证书或者所有证书来访问。

需要自⼰写证书验证过程的场景

  • 用的是自签名证书(例如只用于内网的 https)
  • 信息不全,缺乏中间证书机构(可能性不大)
  • 手机操作系统较旧,没有安装最新加入的根证书

其他

get和post的区别 get提交:提交的信息都显示在地址栏中,对于敏感数据不安全,传送的数据量较小,不能大于2KB,因为地址栏存储体积有限。将信息封装到了请求的请求行中。 post提交:提交的信息不显示在地址栏中,对于敏感数据安全,可以提交大体积数据。将信息封装到了请求体中

Cookie Session和Cookie是一种记录客户端状态的机制的话是由服务器发给客户端特殊信息,而这些信息以文本文件的方式存放在客户端,然后客户端每次向服务器发送请求的时候都会在headers里带上这些特殊的信息

Cookie 的作⽤ 会话管理:登录状态、购物⻋ 个性化:⽤户偏好、主题 Tracking:分析⽤户⾏为

Session 不同于Cookie保存在客户端中,他是保存在服务器上。 session 的工作原理 1.第一步创建Session 2.在创建了Session的同时,服务器会为该Session生成唯一的Session id 3.在Session被创建之后,就可以调用Session相关的方法往Session中增加内容 4.当客户端再次发送请求的时候,会将这个Session id带上,服务器接受到请求之后就会依据Session id找到相应的Session

cookie和session 的区别 1.存放位置不同 2.存取方式的不同 3.安全性(隐私策略)的不同 4.有效期上的不同 5.对服务器造成的压力不同

URI和 URL 统一资源标识符(URI)用于标识某一互联网资源,而统一资源定位符(URL)表示资源的地点(互联网上所处的位置)。所以 URL 是 URI 的子集。URI:http:,https:,ftp:,本地文件系统(file:),和Jar文件(jar:)。

如何上传 用post,通过表单,不过结构单一,比较繁琐,还可以通过将数据转换成jsonstring、文件、string(base64)来上传,如果是多个图片可以写个循环上传。在上传的时候可以在head添加content-type告诉服务器这是什么数据

多线程断点下载 单线程的话从输入流的第0个字节读取

原理:服务器CPU分配给每条线程的时间片相同,服务器带宽平均分配给每条线程,所以客户端开启的线程越多,就能抢占到更多的服务器资源。所以要用多线程去读取。

请求网络时首先获取资源长度设置被进度条,然后除以要开启的线程数,计算出每个线程应该下载多少字节。然后每个线程去请求网络读取数据。

代码语言:javascript
复制
    //设置本次http请求所请求的数据的区间
                conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
                
                //请求部分数据,相应码是206
                if(conn.getResponseCode() == 206){
                    //流里此时只有1/3原文件的数据
                    InputStream is = conn.getInputStream();
int length = conn.getContentLength();

特别注意: 对于移动端来说,如果不是比较大的文件,不建议使用这种方式上传,因为断点续传是通过分片上传实现的,上传单个文件需要进行多次网络请求,效率不高。

WWW HTTP协议同时具备极强的扩展性,虽然浏览器请求的是http://www.sina.com.cn/的首页,但是新浪在HTML中可以链入其他服务器的资源,比如

,从而将请求压力分散到各个服务器上,并且,一个站点可以链接到其他站点,无数个站点互相链接起来,就形成了World Wide Web,简称WWW。

常见状态码 200 :请求成功处理,一切OK 302 :请求重定向 304 :服务器端资源没有改动,通知客户端查找本地缓存 404 :客户端访问资源不存在 500 :服务器内部出错

乱码的处理 乱码的出现是因为服务器和客户端码表不一致导致 //手动指定码表 text = new String(bos.toByteArray(), "UTF-8");

什么是内网外网 私有网段地址, 内网IP有3种:第一种10.0.0.0~10.255.255.255,第二种172.16.0.0~172.31.255.255,第三种192.168.0.0~192.168.255.255 运营商给你的100.64.* . * 也是私有地址,以前大家大家共享一个地址池,有随机的公网地址,现在公网地址更加紧张,运营商只给客户分配私网地址,然后nat后大家共享一个公网地址 172.31.40.210内网 192.168.17.207外网

TCP和UDP

UDP传输的流程

创建 UDPSocket发送服务对象:DatagramSocket(),可不指定端口 创建 UDPSocket接收服务对象:DatagramSocket(int port), 发送:void send(DatagramPacket p) 接收:void receive(DatagramPacket p)

TCP传输流程

Socket(客户端)和ServiceSocket服务端() 建立客户端和服务端 建立连接后,通过socket中的IO流进行数据的传输 关闭socket 1)创建客户端对象: Socket(String host,int port),指定要接收的IP地址和端口号 2)创建服务端对象:ServerSocket(int port):指定接收的客户端的端口 3)Socket accept():侦听并接受到此套接字的连接,服务器用于接收客户端socket对象的方法 主要通过S.getOutputstream和S.getInputSteram 注:服务器没有socket流,也就没有读写操作的流,服务器是通过获取到客户端的socket流(accept)然后获取到其中的读写方法,对数据进行操作的,也正是因为这样服务器与客户端的数据操作才不会错乱

代码语言:javascript
复制
定义tcp的服务端  
建立服务端的socket服务,ServerSocket,并监听一个端口  
获取连接过来的客服端对象,通过ServerSokcet的 accept方法。没有连接就会等,所以这个方法阻塞式的。  
客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。  
关闭服务端(可选)  
public class TCPServerDemo {
    public static void main(String[] args) throws IOException {
        // 建立服务端的socket服务,并监听一个端口
        ServerSocket ss = new ServerSocket(10003);
        // 通过accept方法获取连接过来的客户端对象
        Socket socket = ss.accept();
        String ip = socket.getInetAddress().getHostAddress();
        System.out.println(ip + "......connected");
        // 获取客户端发过来的数据,那么要使用客户端对象的读取流来获取数据
        InputStream in = socket.getInputStream();
        byte[] buf = new byte[1024];
        int len = in.read(buf);
        System.out.println(new String(buf, 0, len));
        socket.close();// 关闭客户端
        ss.close();// 关闭服务端,可选的操作
    }
}


tcp分为客户端和服务端,客服端对象的对象是socket,服务端对应的是serversoceket  
客户端,在建立的时候就可以去连接指定的主机  
因为tcp是面向连接的,所以在建立socket时就需要有服务端存在 
并连接成功,形成通路,才能在该通道上传输数据  
public class TCPClientDemo {  
    public static void main(String[] args) throws Exception {  
        //1、创建客户端的socket服务,指定目的主机和端口  
        Socket socket = new Socket("192.168.229.1", 10003);  
        //2、获取socket的输出流,用于发送数据  
        OutputStream out = socket.getOutputStream();  
        //3、发送数据  
        out.write("tcp client send message come on".getBytes());  
          
        socket.close();  
    }  
}  

在Android上发送HTTP请求的方式

原生有两种,HttpURLConnection和HttpClient,两种方式都支持HTTPS协议、以流的形式进行上传和下载、配置超时时间、IPv6、以及连接池等功能。HttpURLConnection的API提供的比较简单,可以更加容易地去使用和扩展它,而且速度快、还能节省电量。

HttpURLConnection用法:

代码语言:javascript
复制
发送GET请求
  URL url = new URL(path);
  //获取连接对象
  HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  //设置连接属性
  conn.setRequestMethod("GET");
  conn.setConnectTimeout(5000);
  conn.setReadTimeout(5000);
  //建立连接,获取响应吗
  if(conn.getResponseCode() == 200){
//获取服务器响应头中的流,流里的数据就是客户端请求的数据
    InputStream is = conn.getInputStream()
  }
获取服务器返回的流,从流中把html源码读取出来
流转换成string的方法第一种:
byte[] b = new byte[1024];
  int len = 0;
  ByteArrayOutputStream bos = new ByteArrayOutputStream();
  while((len = is.read(b)) != -1){
      //把读到的字节先写入字节数组输出流中存起来
      bos.write(b, 0, len);
  }
  //把字节数组输出流中的内容转换成字符串
  //默认使用utf-8
  text = new String(bos.toByteArray());    
//第二种:
BufferedReader reader = new  BufferedReader(new InputStreamReader(is));
        StringBuilder builder = new StringBuilder();
        String line;
        while ((line=reader.readLine())!=null) {
            builder.append(line);
        }
        String text=builder.toString();

//第三种    
Reader reader = null;
    reader = new InputStreamReader(stream, "UTF-8");
    char[] buffer = new char[len];
    reader.read(buffer);
    return new String(buffer);

//图片的流
InputStream is = null;
...
Bitmap bitmap = BitmapFactory.decodeStream(is);
ImageView imageView = (ImageView) findViewById(R.id.image_view);
imageView.setImageBitmap(bitmap);

post

代码语言:javascript
复制
connection.setRequestMethod("POST");
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.writeBytes("username=admin&password=123456");

简单封装

代码语言:javascript
复制
public class HttpUtil {
    public static void sendHttpRequest(final String address,
            final HttpCallbackListener listener) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                try {
                    URL url = new URL(address);
                    connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    connection.setDoInput(true);
                    connection.setDoOutput(true);


                    InputStream in = connection.getInputStream();
                    BufferedReader reader = new BufferedReader(
                            new InputStreamReader(in));
                    StringBuilder response = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        response.append(line);
                    }
                    if (listener != null) {
                        // 回调onFinish()方法
                        listener.onFinish(response.toString());
                    }
                } catch (Exception e) {
                    if (listener != null) {
                        // 回调onError()方法
                        listener.onError(e);
                    }
                } finally {
                    if (connection != null) {
                        connection.disconnect();
                    }
                }
            }
        }).start();
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-04-02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • HTTP
  • http缓存
  • HTTPS
    • 非对称加密
      • 数字签名
        • 数字证书
        • 其他
        • TCP和UDP
          • UDP传输的流程
            • TCP传输流程
            • 在Android上发送HTTP请求的方式
            相关产品与服务
            数据脱敏
            数据脱敏(Data Masking,DMask)是一款敏感数据脱敏与水印标记工具,可对数据系统中的敏感信息进行脱敏处理并在泄漏时提供追溯依据,为企业数据共享、迁移、分发提供安全保护措施。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档