网络初识

2019-08-23  本文已影响0人  耐得千事烦

前言

之前对于网络这块的知识一直是零零散散的,这次抽空好好的做个总结。

先给出OSI的7层网络模型与TCP/IP四层模型以及对应的网络协议

网络分层以及对应的协议.png

先说OSI七层网络模型:

再以TCP/IP分层模型来说:


TCP与UDP的区别
TCP UDP
面向连接 无连接
可靠,保证顺序,不会丢包 不可靠,不保证顺序,会丢包
需要资源多,效率低,速度慢 需要资源少,效率高,速度快
只支持点对点通信 支持一对一、一对多、多对一、多对多的通信模式
是面向字节流的 UDP是面向报文的
有拥塞控制机制 没有拥塞控制,适合媒体通信
TCP的报文格式
TCP报文结构.png
TCP的三次握手与四次挥手过程,各个状态名称与含义
三次握手.png

第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。

第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。

第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。

第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。

第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。此时TCP链接处于半关闭状态,即客户端已经没有要发送的数据了,但服务端若发送数据,则客户端仍要接收。

第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。

第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手。

为什么TCP链接需要三次握手,两次不可以么,为什么?

为了防止已失效的链接请求报文突然又传送到了服务端,因而产生错误。

客户端发出的连接请求报文并未丢失,而是在某个网络节点长时间滞留了,以致延误到链接释放以后的某个时间才到达Server。这是,Server误以为这是Client发出的一个新的链接请求,于是就向客户端发送确认数据包,同意建立链接。若不采用“三次握手”,那么只要Server发出确认数据包,新的链接就建立了。由于client此时并未发出建立链接的请求,所以其不会理睬Server的确认,也不与Server通信;而这时Server一直在等待Client的请求,这样Server就白白浪费了一定的资源。若采用“三次握手”,在这种情况下,由于Server端没有收到来自客户端的确认,则就会知道Client并没有要求建立请求,就不会建立链接。

TCP协议如何来保证传输的可靠性
TCP的拥塞处理

从输入网址到获得页面的过程

(1). 浏览器查询 DNS,获取域名对应的IP地址:具体过程包括浏览器搜索自身的DNS缓存、搜索操作系统的DNS缓存、读取本地的Host文件和向本地DNS服务器进行查询等。对于向本地DNS服务器进行查询,如果要查询的域名包含在本地配置区域资源中,则返回解析结果给客户机,完成域名解析(此解析具有权威性);如果要查询的域名不由本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个IP地址映射,完成域名解析(此解析不具有权威性)。如果本地域名服务器并未缓存该网址映射关系,那么将根据其设置发起递归查询或者迭代查询;

(2). 浏览器获得域名对应的IP地址以后,浏览器向服务器请求建立链接,发起三次握手;

(3). TCP/IP链接建立起来后,浏览器向服务器发送HTTP请求;

(4). 服务器接收到这个请求,并根据路径参数映射到特定的请求处理器进行处理,并将处理结果及相应的视图返回给浏览器;

(5). 浏览器解析并渲染视图,若遇到对js文件、css文件及图片等静态资源的引用,则重复上述步骤并向服务器请求这些资源;

(6). 浏览器根据其请求到的资源、数据渲染页面,最终向用户呈现一个完整的页面。

Http怎么处理长连接

在HTTP1.0和HTTP1.1协议中都有对长连接的支持。其中HTTP1.0需要在request中增加Connection: keep-alive header才能够支持,而HTTP1.1默认支持。

C/S模式下使用socket通信,几个关键函数

编写一个基于UDP传输协议的网络编程:
先构建服务端

package com.suxin.socket.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Mysever {

    /**
     *  1.创建服务端+端口
     *  2.准备接受容器
     *  3.封装成包
     *  4.接收数据
     *  5.分析数据
     *  6.释放资源
     *
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        //创建服务端以及端口
        DatagramSocket server = new DatagramSocket(8899);
        // 构造接收器
        byte[] container = new byte[1024];
        // 使用构造器打包
        DatagramPacket packet = new DatagramPacket(container,container.length);
        boolean flag = true;
        while(flag) {
            server.receive(packet);//接受数据
            byte[] bytes = packet.getData();
            int len = packet.getLength();
            String s = new String(bytes,0,len);
            System.out.println(s);
            if(s.equals("quit server")) {
                flag = false;
            }
        }
        server.close();
    }
}

继续构建客户端:

package com.suxin.socket.udp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.util.Scanner;

public class Myclient {
    
    public static void main(String[] args) throws IOException {
        //创建服务端以及端口
        DatagramSocket client = new DatagramSocket(6666);
        //准备数据
        Scanner sc = new Scanner(System.in);
        boolean flag = true;
        while(flag) {
            System.out.println("请输入传输数据(以enter结束):");
            String message = sc.nextLine();
            byte[] b = message.getBytes();
            //打包发送
            DatagramPacket packet = new DatagramPacket(b,b.length,new InetSocketAddress("127.0.0.1",8899));
            client.send(packet);
            System.out.println("数据:"+message+"已经发送");
            if(message.equals("close")) {
                flag = false;
            }
        }
        client.close();
    }
}

如果我们关闭服务端,运行客户端,依然可以成功。但是此时并没有消息显示。说明即使在服务端不开启的情况下,基于这种协议的依然可以执行,但是数据会丢失。注意:数据传输的过程中,必须使用字节数组。输入quit server以后还是可以继续发送消息的。

编写一个基于TCP协议的网络编程:
服务端:

package com.suxin.socket.tcp;

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class MyServer {

    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(8899);

        Socket socket = server.accept();//等待接受外部请求
        System.out.println("客户端建立连接");
        String message = "欢迎使用";
        
        DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
        dataOutputStream.writeUTF(message);

        dataOutputStream.flush();
    }
}

客户端:

package com.suxin.socket.tcp;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

public class MyClient {

    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",8899);
        DataInputStream input=new DataInputStream(socket.getInputStream());
        String echo = input.readUTF();
        System.out.println(echo);
        DataOutputStream output = new DataOutputStream(socket.getOutputStream());
        output.writeUTF("i love u");
        System.out.println("[i love u]数据已经发送");
    }
}

以上就是UDP/IP与TCP/IP的基本实现。但是,我们知道,TCP/Ip的实现仅仅是实现了一个客户端的连接,这是不符合实际的,实际情况下服务器一般都是有多个客户端的连接。这也很好解决,我们只需要在服务器端加一个循环,对于每一次来自客户端的请求,服务器端的Accept()方法都会返回一个Socket对象,这样就实现了多个连接。


参考链接
UDP/IP与TCP/IP协议 带编程解读
网络相关的面试题
面试/笔试第一弹 —— 计算机网络面试问题集锦
3分钟看懂什么是三次握手/四次挥手
java socket编程

上一篇下一篇

猜你喜欢

热点阅读