Java基础系列:计算机网络基础概念

俗世游子:专注技术研究的程序猿

网络

大部分情况下,做开发的程序猿是是不需要和网络打交道的,就比如本人:工作这么多年,去年年初做过一次系统架构,做负载均衡的时候顺带了解了一下这方面的基础知识,其他时候根本用不到。

我们现在就来简单聊一聊,简单到什么程度:

  • 开发涉及到网络IO方面的问题能知道该怎么解决,
  • 面试能说个七七八八就够了

基本知识

首先我们先要明白什么是网络

不负责任的说,网络网络是由若干节点和连接这些节点的链路构成,而这些物理链路将多台计算机连接在一起,组成了我们现在的互联网

促进网络产生的先决条件:

  • 芯片技术

要知道,世界上第一台计算机有一个教室那么大,直到集成电路的产生,将电路做到一块完整的半导体硅板上,计算机的体积才下降下来

  • 网络理论本身

第二个条件就是网络理论本身,我们现在知道,网络本身分为很多节点,各个节点之间相互关联,我们从起点A发送数据到终点B,发送的数据在网络中会拆分成小包,由于光电传输是非常快的,所以在数据包在网络中传输的时候会通过不同的路线到达终点B,然后在终点B中进行合并

在这个理论中,两个人的贡献非常大:

  1. Paul Baran 提出的分布式可适应信息块交换集成电路
  2. Donald Davies 提出的封包交换

两者说的是一个问题,就是封包交换算法,解决数据如何从一个点通过复杂网络到达另一个点的问题

  • 材料的发展

在1858年的跨大西洋同轴电缆,每分钟传输120个字,而我们现在采用的双绞线电缆,通过导线两两缠绕,抵消掉信号的干扰,而不同材料传输速度也不同。目前我们市面上的传输速度已经能到达到100Mbps,还有比这个更快的,能够快10倍

光纤采用的是光传输,能量在用光传输的时候损耗较低,所以速度最快,能够达到10Gbps

  • 软件应用行业的发展

应用的不断发展也造成了网络的发展,包括现在的5G,卫星上网

网络模型

随着网络的出现,再加上当时商业力量的介入,网络得到的大力的发展,出现了OSI网络模型,即开放式系统互联模型,它是国际标准组织的一次伟大尝试,也是世界上第一个试图在世界范围内规范网络标准的框架

七层模型

模型从上向下分别为:

  • 应用层

也就是我们平常使用的客户端,比如微信发送消息,浏览器请求地址等等,这里只负责将请求数据发送出去

  • 表示层

负责协商用于传输的数据格式,并转换数据格式。比如现在说的HTTP协议,数据量太大的话,数据压缩在这一层,HTTPS数据加密也在这一层完成

  • 会话层

负责管理两个联网实体间的网络,比如客户端和服务器端产生的连接,这条连接维持客户端和服务器端的通信,然后等到连接断开的时候释放链接

  • 传输层

从传输层开始,将负责数据的拆成一个个小包,然后将小包进行封包,并将数据从一个实体(服务器或者应用)发送到另一个实体,但是并不负责数据的传输方式

同时在传输层还有以下功能:

  1. 当数据在传输过程中出现问题后采取方式进行纠正,重发或者其他方式
  2. 控制传输数据的速率
  3. 端口寻址,标明参与传输的实体的端口号
  • 网络层

负责把封包从一个IP地址传输到另一个IP地址,这里的核心就是路由算法。需要通过路由算法得到下一个节点的地址

  • 数据链路层

在这一层确保两个临近设备间数据的传输,并隐藏底层实现,同时还需要协调传输时速率问题

  • 物理层

真正需要发送数据的实际手段,比如:网线,光纤等等的物理方式

看下面的图,用实际例子来理解一下:
网络传输过程

需要注意的是,OSI模型是没有实际可行的方案

TCPIP协议

实际上,OSI模型还是存在一些问题比如说:

我们在命令行通过ping来测试一个网络,根据我们对7层网络模型的认识,这种程序对于会话层和表示层并不是必须的,

而且由于OSI模型在当时并没有实际可行的方案,所以罗伯特.卡恩文顿.顿瑟夫提出了TCP协议,对比OSI模型只有5层,而且在1975年做了成功的实验,所以从这一点上TCP协议OSI模型更容易让大家接受

它只有5层:

  • 应用层

这里不变,也是将数据发送出去的过程

  • 传输控制层

解决主机到主机之间的传输,在这里常用的也就是我们耳熟能详的TCP协议UDP协议

  • 网络层

在这一层提供了路由和寻址,通过路由判定和下一跳机制得到下一个要发送出去的节点

  • 数据链路层

两个节点之间的物理连接,在这里对数据再次封包发送,常用的就是ARP协议

  • 物理层

物理层和OSI模型不变

深入理解

下面我们来聊一聊在各个层面上我们经常使用的协议

应用层协议:HTTP协议

基本概念

HTTP协议,也叫超文本传输协议,是处理客户端和服务器端之间通信的一种协议,在HTTP协议中的的请求头和返回体都包含相同的数据格式:

  • Request
GET / HTTP/1.1
Host: http://www.baidu.com
...

<消息请求body>
  • Response
GET HTTP/1.1 200 ok
...

<返回体>

在Request和Response中包含很多的属性

只要我们能够按照HTTP指定的协议返回,那么我们也可以自己实现一个Http服务器,比如:

public class RawHttpSocket {

    private ServerSocket serverSocket;
    Function<String, String> handler;

    public RawHttpSocket(Function<String, String> handler) {
        this.handler = handler;
    }

    public static void main(String[] args) throws IOException {
        String body = "<html><head></head><body><pre style=\"word-wrap: break-word; white-space: pre-wrap;\"><h1>Hello world!</h1>\n" +
                "</pre></body></html>";

        RawHttpSocket rawHttpSocket = new RawHttpSocket((str) -> {
            System.out.println(str);
            // 第一个 \n 是header结尾 第二个 \n 是header和body的分段
            return "HTTP/1.1 200 ok\n\n"+body+"\n";
        });
        rawHttpSocket.listener(9000);
    }

    private void listener(int port) throws IOException {
        // 建立ServerSocket,绑定端口
        serverSocket = new ServerSocket(port);
        while (true) {
            // 等待Socket建立连接
            Socket socket = serverSocket.accept();
            new Thread(() -> {
                try {
                    // 处理请求
                    this.accpet(socket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    private void accpet(Socket socket) throws IOException {

        System.out.println("a socket created");

        // 读取到请求数据
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line = "";
        StringBuffer requestBuffer = new StringBuffer();
        // line有可能出现null common-lang3下的工具类:StringUtil
        while (StringUtil.isNotBlank((line = reader.readLine()))) {
            requestBuffer.append(line).append("\n");
        }
        String request = requestBuffer.toString();

        // 返回数据
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        String response = handler.apply(request);
        writer.write(response);
        writer.flush();
        socket.close();
    }

}

HTTP服务

URL

我们通常通过URL来访问一个网站,URL也就是我们所说的统一资源定位符,其中由以下部分构成:

URL分类

像80端口,443端口,URL中的端口号是可以省略的

DNS解析

也就是域名解析系统,通常当我们通过URL访问某一个网站的的时候,通过DNS查询得到当前域名所对应的IP地址,然后浏览器再通过返回的IP来定位到服务器资源并返回给浏览器,这也就是DNS解析的工作原理

但是我们要想一个问题,到目前为止,存在了几十亿的网站,而且有时候一个域名下会解析N多个IP地址,这种情况下,快速解析到IP地址就成为了一个问题,于是出现了分级缓存策略,其实介绍下来就是这样的:

  1. 当用户访问一个网站的时候,首先会从本地缓存中查找是否存在DNS条目,如果有的话就根据该条目直接访问;如果没有的话,回去系统的hosts文件下查找,匹配到就访问,否则会请求到DNS本地服务商。

这一步的存在会屏蔽掉80%的流量请求出去

  1. 在DNS本地服务商中也会存在缓存,如果这里也没有会请求到根服务器中
  2. 根服务器在分布在全球,而且在其服务器上只存目录,请求过来之后通过网站域名后缀请求到顶级域名服务器中匹配
  3. 和根服务器一样,顶级域名服务器上也只存目录,最终通过顶级域名服务器的匹配将请求转发到了权威服务器
  4. 在权威服务器中得到指定的DNS条目,最终返回给客户端

DNS解析

和CDN技术一样,根据最优规划,DNS解析会给出最适合当前客户端的IP

CDN

CDN技术也是目前架构上使用市场广泛的一种技术,主要可以用来做:

  • 流量分发

鸡蛋不放在同一个篮子里,同样的,我们的应用也不会部署在一起,当我们的应用分散在各地机房,应用的请求也需要做相应的调整,可以让用户请求离他们最近的服务器,也可以提升访问的效率

  • 数据缓存,包括静态资源和一致性要求低的动态数据

CDN

  • 不同服务器之间存储的内容都是一样的(镜像文件),这样在访问的时候才能保证一致性

传输控制层常用协议

TCP协议

TCP协议面向连接的,安全可靠的传输协议,并且能够保证数据在传输过程中的完整性

TCP协议如果需要建立连接,需要进行三次握手操作:

三次握手

  1. 客户端发送SYN(同步消息)给服务端,通知服务端准备好进行连接,
  2. 服务端接收到客户端发送的SYN后会把ACK和服务端的SYN消息同时发送给客户端
  3. 客户端接收到SYN消息之后再次给服务端发送一个ACK响应消息

三次握手操作,在客户端的角度上来讲:

  1. 验证了自身的输入流和输出流是没有问题的,
  2. 最后给服务端的响应消息也是明确告知服务端自己收到了响应消息

等到三次握手全部完成之后,应用层才会开辟线程,开辟对象,开辟文件描述符等等的系统资源

同时,如果客户端想要和服务端断开连接的话,那么要经历四次分手操作:

四次分手

  1. 客户端发送断开请求FIN,服务端接收到FIN请求之后会给客户端返回ACK响应
  2. 服务端经过等待,确定可以断开当前连接的时候会给客户端发送FIN
  3. 客户端接收到服务端返回的FIN请求,当客户端处理完之后,就会给服务端发送ACK响应,这时这次的连接全部断开

有商有量,才是和平分手

在TCP协议中,三次握手,数据传输,四次分手三者是不可被分割的最小粒度

UDP协议

相对比TCP协议来讲,UDP比TCP简单了很多,UDP不需要连接,这也就造成了它不是安全可靠的连接,而且会出现数据包丢失的情况,但是UDP协议的传输速度比TCP快了很多

这种协议适用的场景包括:

  • 音视频
  • 广播
  • ...

最后的话

好了,不聊了,这里欠个债:

网络层的下一跳机制数据链路层的ARP协议,在后面再跟大家聊

骇,感觉有点水啊

猜你喜欢

转载自blog.51cto.com/14948012/2630383