【Java网络编程】计算机网络概述

本文介绍了计算机网络的基本概念,包括网络的定义、局域网与广域网的区别、互联网的构成以及信息在网络中的传输流程。详细讲解了网络的五层协议模型,重点探讨了运输层的TCP和UDP协议,包括它们的特点、应用场景以及编程实践。
摘要由CSDN通过智能技术生成

计算机网络概述

1.1 网络概述

什么是网络

计算机网络由若干结点和连接这些结点的链路组成,计算机网络中的结点可以是计算机、集线器、交换机和路由器等。

网络有什么作用

信息的传递。当然我们要知道的是仅仅有网络是无法进行信息传递的,我们还需要在计算机上安装相应的软件才可以。

什么是局域网

什么是广域网

又称广域网、外网、公网。是连接不同地区局域网或城域网计算机通信的远程网。通常跨接 很大的物理范围,所覆盖的范围从几十公里到几千公里,它能连接多个地区、城市和国家,或横 跨几个洲并能提供远距离通信,形成国际性的远程网络。广域网并不等同于互联网。

什么叫做互联网

如果把网络再通过路由器连接在一起就形成了互联网。世界上最大的互联网就是因特网。

信息在网络中的传输流程

由于网络是比较抽象的,所以我们在研究信息通过网络的传输过程时通常根据信息传递过程中的不同特点将网络分为若干层,分层去研究将抽象的东西尽可能具体化。常见的网络划分形式有三种,如下图所示:

在这里插入图片描述

这里主要以五层协议进行介绍了解。而其中信息的传输流程为:

在这里插入图片描述

信息的流动过程如上图所示,其中:

  • 发送方:应用层 -> 运输层 -> 网络层 -> 数据链路层 -> 物理层
  • 接收方:物理层 -> 数据链路层 -> 网络层 -> 运输层 -> 应用层

从图上可以看出消息在发送方方这边数据变得越来越大,每层对数据都进行的封装,接收方从下到上又将这些封装去掉。下面我们来看看每层具体所做的事情。

1.2 各层介绍

每一层的工作都会借助于协议完成。

1.2.1 应用层

能够和用户交互,所有能够产生网络流量的程序。

它使得应用程序能够直接运行于传输层之上,直接为用户提供服务。包含的主要协议有文件传输协 议(File Trabsfer Protocol, FTP)、简单邮件传送协议(Simple Mail Transfer Protocol, SMTP)、远 程登陆协议、域名服务协议(DomainNameService, DNS)、网络新闻传送协议(Network NewsTransfer Protocol,NNTP)和超文本传输协议(Hyper Text Transfer Protocol,HTTP)等。

  • 表示层:

    • 信息传输之前如果需要对数据进行处理。
    • 网络的安全和保密管理;文本的压缩与打包; 虚拟终端协议(VTP)。
  • 会话层:

    • ① 将会话地址映射为运输地址。
    • ② 选择需要的运输服务质量参数。
    • ③ 对会话参数进行协商。
    • ④ 识别各个会话连接。
    • ⑤ 传送有限的透明用户数据。

1.2.2 运输层

运输层的任务就是负责向两个主机中进程之间的通信提供服务。由于一个主机可同时运行多个进程,因此 运输层有复用和分用的功能。复用就是多个应用进程可同时使用下面运输层的服务,分用则是运输层把收到的信息分别交付给上面的应用层中相应的进程。 其中进程与进程之间最关键的通信方式就是端口号,其所占用的端口号必须是唯一的,且对于每一个应用来说在它所在的主机上必须是 0~65535

1 ~ 65535 
1~ 1023 之间 系统端口号 别人已经使用的端口号 
1024~65535为用户端口:  
1024-5000: 临时端口,一般的应用程序使用 
1024到4999 来进行通讯;
5001-65535:服务器(非特权)端口,用来给用户自定义端口。 (写代码)

运输层主要使用UDP 和TCP两种协议,主要目的是将数据发送给指定的应用。

  • TCP/IP协议栈:

在这里插入图片描述

1.2.2.1 运输层协议介绍
1.2.2.1.1 UDP协议

UDP是面向无连接的网络传输协议。首先面向无连接是什么意思?A向B发送消息,不需要A与B进行实际连接,只要A知道B的地址(IP 和 port )就可以传输数据,由于不需要连接所以每一个用户数据报的首部会非常的小,所以传递会非常的快速便捷,但是由于面向无连接的擦混熟,A如果向B发数据时,数据丢失,B是不知道的,所以这种传输不安全!主要应用于直播,视频聊天等等。

UDP协议特点:

  • 无连接:A和B之间并没有建立连接其实UDP协议他只是在A和B之间建立了一种关系,让A知道消息是要发给B的。
  • 尽最大努力交付:不保证消息的可靠性。
  • 面向报文。
  • 无拥塞控制:不会因为网络拥塞导发送速率降低,对于某些实时的应用很重要 比如ip通话 视频会议等。
  • 支持一对一、一对多、多对一和多对多的交互通信(因为不需要建立连接 所以在发送的时候其实可以发给任意用户)。
  • 首部开销小(只有四个字段:源端口、目的端口、长度、检验和)。

UDP首部格式:

在这里插入图片描述

用户数据报 UDP 有两个字段:数据字段和首部字段。首部很简单,只有 8 个字节。由四个字段组成,每个字段长度都是两个字节。各字段意义如下:

  • a、源端口 :在需要对方回信时选用。不需要时可用全 0。
  • b、目的端口 : 在终点交付报文时必须使用到。
  • c、长度 :UDP 用户数据报的长度,其最小值为 8(仅包含首部)。
  • d、检验和 :检验 UDP 用户数据报在传输中是否有错,有错就丢弃。
1.2.2.1.2 TCP 协议

TCP是面向连接的,可靠的,数据传输服务的网络传输协议。

TCP协议特点:

  • 面向连接:通信之前必须建立连接,这个和UDP就有所不同(UDP是不需要建立连接的,所以他能1对多、多对一、多对多通信),而TCP就只能建立连接双方进行通信。
  • 每一条TCP连接只能是点对点的(一对一),连接建立好之后只能连接建立的双方之间进行通信。
  • 提供可靠交付的服务:通过TCP连接传输的数据,无差错,不丢失,不重复。保证了数据的安全性。
  • 提供全双工通信:A 可以给B发消息,B也可以给A发消息。
  • 面向字节流。
  • 首部开销较大(占20字节)。

TCP 首部格式:

在这里插入图片描述

各个字段的作用与含义:

  • a、源端口号和目的端口号。

各占两个字节,我们知道端口号就是标识特定主机上的唯一的进程,而 IP 地址是来表示标识网络中的不同主机的,这两个源(source)和目的(dst)端口号和 IP 首部中的源和目的 IP 地址,则标识互联网上的唯一进程,所以套接字的定义说白了就是 IP 地址和端口号共同组成。

  • b、确认序号。

4 个字节,上一个字段的序号是对数据的编号,所以确认序号是下一个期望接收的 TCP 分段号,相当于是对对方所发送的并且已经被本方所正确接受的分段的确认。仅当 ACK 标志为 1 时有效。确认号表示期望收到的下一个字节的序号。

  1. ack 表示期望下次接收到的序号。
  2. 那么 ack 是如何算出来的呢,就是通过收到的序号,和数据长度相加得来。假设 A 收到 B 过来的数据(seq = 5,len = 15)。len 表示数据长度。那么 A 就会回复 B,“刚才的数据我已经收到了,你接下来就发序号为 20 的包给我吧”。这样就保证了数据不会乱序。
  • c、ACK。

当 ACK 标志为 1 时有效。确认号表示期望收到的下一个字节的序号。

  • d、序号。

4 个字节,表示在这个报文段中的第一个数据字节序号。如果将字节流看作在两个应用程序间的单向流动,则 TCP 用序列号对每个字节进行计数。用来保证到达数据顺序的编号,所以这个字段需要比较大的存储。

  • e、位数据偏移。

以 32 位(4 字节)字长为单位,需要这个值是因为任选字段的长度是可变的。跟 IP 头部一样,以 4字节为单位。最大是 60 个字节。不存在任选字段正常的报头长度是 20 字节。其实相当于给出数据在数据段中的开始位置。

  • f、保留位。

6 位,必须为 0。

  • g、标志位。

占有 6 个比特位,他们中可以有多个为置为 1,依次为:URG,ACK,PSH,RST,SYN,FIN。
下面具体分析:

  1. URG:该位为 1 说明表示 TCP 包的紧急指针域有效,用来保证 TCP 连接不被中断,并督促上层应用敢快处理这些数据。
  2. ACK:确认号有效当 ACK 标志为 1 时有效。确认号表示期望收到的下一个字节的序号。
  3. PSH:接收方应尽快将这个报文交给应用层,叫做 push。所谓 Push 操作就是指在数据包到达接收端以后,立即传送给应用程序,而不是在缓冲区中排队。
  4. RST:连接复位,复位因主机奔溃或其他原因而出现的错误连接,也可以用于拒绝非法的分段或拒绝连接请求,这个用处还是比较多的。
  5. SYN:是一个同步序号,通常与 ACK 合用用来建立连接。也就是常说的三次握手。
  6. FIN:既然有建立连接那么必然有拆除连接,这个字段表示发送端已经达到数据末尾,也就是说双方的数据传送完成,没有数据可以传送了,发送 FIN 标志位的 TCP 数据包后,连接将被断开。这个标志的数据包也经常被用于进行端口扫描。
  • h、紧急指针。

只有当 URG 标志置 1 时紧急指针才有效。紧急指针是一个正的偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。TCP 的紧急方式是发送端向另一端发送紧急数据的一种方式。

  • i、窗口大小。

TCP 的流量控制由连接的每一端通过声明的窗口大小来提供。窗口大小为字节数,起始于确认序号字段指明的值,这个值是接收端正期望接收的字节。这是一个 16 bit 字段,因而窗口大小最大为 65535 字节。

  • j、校验和。

用于对分段首部和数据进行校验。正常情况下为一定为 0。

1.2.2.1.3 运输层协议使用场景
  • UDP 的使用场景:

UDP由于不保证消息的可靠性,所以UDP适合发送一些消息不需要保证每条都准确无误到达接收者。例如:视频通信。

  • TCP 的使用场景:

由于 TCP 能够能保证消息的准确性,所有例如游戏信、文字信息等适合用 TCP 通信。

1.2.2.1.4 TCP 和 UDP 的编程实践
  • UDPServer 端:
public class UDPServer {
    //确定绑定的端口号
    private final int port = 5888;
    private DatagramSocket socket; //实现UDP编程的工具类
    private DatagramPacket packet; //对消息的封装类(原因是:UDP是面向报文的)

    public UDPServer() {
        try {
            //初始化socket
            //服务器绑定端口号
            socket = new DatagramSocket(port);
            //初始化packet
            byte[] bytes = new byte[1024]; //为什么采用byte数组进行封装:一般情况下信息的网络传输都是通过字节传输的
            packet = new DatagramPacket(bytes, 0, bytes.length);
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    public void startServer() {
        try {
            while (true) {
                //让服务器先接收数据
                socket.receive(packet); //如果receive方法执行成功,说明packet中已经保存了接收到的数据
                //packet转字符串
                String str = new String(packet.getData(), 0, packet.getLength());
                System.out.println("收到用户发来的信息为:" + str);
                if (str.equals("exit")) {
                    break;
                }

                //向用户回复消息
                String rec = "i receive your msg";
                //封装成packet
                byte[] bytes = rec.getBytes();
                DatagramPacket sendPacket = new DatagramPacket(bytes, 0, bytes.length,
                        packet.getAddress(), packet.getPort()); //发送数据
                //必须要明确是哪个用户发送过来的信息,
                //并获取该用户的IP地址packet.getAddress()和端口号packet.getPort()
                socket.send(sendPacket);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socket != null) {
                socket.close();
            }
        }
    }

    public static void main(String[] args) {
        UDPServer udpServer = new UDPServer();
        udpServer.startServer();
    }
}
  • UDPClient 端:
public class UDPClient {
    //确定服务器IP地址
    private String IP = "localhost"; //与"127.0.0.1"相同
    //确定服务进程端口号
    private int port = 5888;
    private DatagramSocket socket; //实现UDP编程的工具类
    private DatagramPacket packet; //对消息的封装类(原因是:UDP是面向报文的)
    private Scanner scanner;

    public UDPClient() {
        try {
            socket = new DatagramSocket(); //UDP不需要建立连接,因此不需要传递IP地址和端口号
            scanner = new Scanner(System.in);
            //初始化packet
            byte[] bytes = new byte[1024]; //为什么采用byte数组进行封装:一般情况下信息的网络传输都是通过字节传输的
            packet = new DatagramPacket(bytes, 0, bytes.length);
            startClient();
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    public void startClient() {
        try {
            while (true) {
                System.out.println("请输入信息:");
                String s = scanner.nextLine();
                //封装成packet
                byte[] bytes = s.getBytes();
                DatagramPacket sendPacket = new DatagramPacket(bytes, 0, bytes.length,
                        InetAddress.getByName(IP), port); //发送数据
                //必须明确服务器端的IP地址InetAddress.getByName(IP)和端口号port
                socket.send(sendPacket);
                if(s.equals("exit")){
                    break;
                }

                //接收服务器端信息回复
                socket.receive(packet); //如果receive方法执行成功,说明packet中已经保存了接收到的数据
                //packet转字符串
                String str = new String(packet.getData(), 0, packet.getLength());
                System.out.println("收到服务器端发来的信息为:" + str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            socket.close();
        }
    }

    public static void main(String[] args) {
        UDPClient udpClient = new UDPClient(); //必须先启动服务端
    }
}
  • TCPServer 端:
public class TCPServer {
    //自定义端口号
    private int port = 5676; //端口号
    //jdk提供了TCP编程的相关工具类
    private ServerSocket serverSocket; //Socket编程

    public TCPServer(){
        try {
            serverSocket = new ServerSocket(port); //创建Socket对象,让服务端绑定端口号
            //可以使用Socket对象进行网络编程
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //启动服务器端
    public void startServer(){
        try {
            //不停的监听是否有新的用户和服务器进行连接
            while (true) {
                //监听是否有新的用户和服务器进行连接
                Socket clientSocket = serverSocket.accept(); //三次握手的终点
                //clientSocket和与该服务器建立的用户是一一对应的
                //accept方法是一个阻塞的方法
                //如果有连接则返回这个用户唯一对应的Socket
                //如果没有用户和服务器建立连接则一直保持阻塞状态
                //如果拿到了clientSocket,则使用该Socket和客户端进行一对一的通信
                //启动子线程 在子线程中通过clientSocket和对应的用户进行一对一的通信
                new Thread(new ServerHandler(clientSocket)).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        TCPServer tcpServer = new TCPServer();
        tcpServer.startServer();
    }
}
public class ServerHandler implements Runnable {
    private Socket clientSocket;

    public ServerHandler(Socket clientSocket) {
        this.clientSocket = clientSocket;
    }

    @Override
    public void run() {
        //网络通信
        //获取字节流之后,进行网络通信
        InputStream inputStream = null;
        BufferedReader reader = null;
        OutputStream outputStream = null;
        BufferedWriter writer = null;
        try {
            inputStream = clientSocket.getInputStream(); //输入流 获取客户端发送的信息
            //将字节流转化为字符流
            reader = new BufferedReader(new InputStreamReader(inputStream)); //获取字符流
            //获取输出流 用来给客户端恢复消息
            outputStream = clientSocket.getOutputStream();
            //将字节流转化为字符流
            writer = new BufferedWriter(new OutputStreamWriter(outputStream));
            while (true){
                String s = null;
                s = reader.readLine(); //获取客户端传递来的信息
                System.out.println("收到用户发来的信息:"+s);
                if(s.equals("exit")){
                    break;
                }

                //给客户端回复消息
                String str = "i receive your msg\n"; //"\n" 将数据刷新出缓冲区
                writer.write(str);
                writer.flush(); //刷新字符缓冲流的缓冲区
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                inputStream.close();
                reader.close();
                outputStream.close();
                writer.close();
                clientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
  • TCPClient 端:
public class TCPClient {
    //确定服务器所在的IP地址
    private String IP = "127.0.0.1";
    //确定服务端口号
    private int port = 5676;
    private Socket clientSocket;
    private Scanner scanner; //通过控制台输入信息

    public TCPClient(){
        try {
            scanner = new Scanner(System.in);
            clientSocket = new Socket(IP,port); //创建socket对象,进行通信
            //如果socket对象建立成功,说明网络连接建立成功
            startClient();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void startClient() {
        //通信的流程
        InputStream inputStream = null;
        BufferedReader reader = null;
        OutputStream outputStream = null;
        BufferedWriter writer = null;
        try {
            outputStream = clientSocket.getOutputStream();
            //将字节流转化为字符流
            writer = new BufferedWriter(new OutputStreamWriter(outputStream));
            inputStream = clientSocket.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inputStream));
            //通信的流程
            while (true){
                String s = scanner.nextLine();
                writer.write(s); //当客户端发出的信息为exit时,通知服务器端退出
                writer.write("\n"); //刷新输出流缓冲区
                writer.flush();
                if (s.equals("exit")){
                    break; //当客户端发出的信息为exit时通信退出
                }

                String s1 = reader.readLine(); //获取服务器的回复
                System.out.println("收到服务器的回复为:"+s1);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                inputStream.close();
                reader.close();
                outputStream.close();
                writer.close();
                clientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        TCPClient tcpClient = new TCPClient(); //在启动客户端之前启动服务器
    }
}

1.2.3 网络层

网络层负责为分组交换网上的不同主机提供通信服务(确定唯一主机)。在发送数据时,网络层把运输层产生的报文段或用户数据报封装成分组或包进行传送。在TCP/IP体系中,由于网络层使用IP协议,因此分组也叫作IP数据报,或简称为数据报(注意:不要将运输层的“用户数据报UDP”和网络层的“IP数据报”弄混)。

  • 1、负责选择最佳路径和规划 IP 地址 路由表 通过 IP 协议进行地址划分。

  • 2、在不同网络之间尽力转发数据包,基于数据包的 IP 地址转发,如果丢失,不负责丢失重传,也不负责顺序。 负责将数据传给对应的服务器或者计算机。他不管信息应该给哪个进程。

    • (只有 TCP 协议)传输层会负责重传和信息的顺序问题。也可以保证传递给对应进程。
    • UDP 只能负责传递给对应进程,不能保证重传和信息的顺序问题。
  • IP 协议详解【Java网络编程】IP协议详解

1.2.4 数据链路层

数据链路层常简称为链路层。主要是负责局域网通信。我们知道,两个主机之间的数据传输,总是在一段一段的链路上传送的,也就是说,在两个相邻结点之间(主机和路由器之间或两个路由器之间)传送数据是直接传送的(点对点)。这时就需要使用专门的链路层的协议。在两个相邻结点之间传送数据时,数据链路层将网络层交下来的IP数据报组装成帧(framing),在两个相邻结点间的链路上“透明”地传送帧(frame)中地数据。每一帧包括数据和必要地控制信息(如同步信息、地址信息、差错控制等)。典型地帧长是几百字节到一千多字节。

  • 封装成帧:通过特殊的 0101 标识,表示数据的开始和结束 特殊字符 特殊字符可能和数据信息重复。 EOT SOH 转义字符。
  • 差错检测:差错检测仅仅能够检测出哪个是错误的保温然后将错误的数据抛弃。(只检测错误,但是不纠错。)纠错:传输层。(TCP)
  • 透明传输:中间如果插入了转义字符不会引起最终数据读取的差错。
  • 数据链路层常用设备:适配器、转发器、集线器、转发器、以太网交换机等。

1.2.5 物理层

物理层并不是指的我们常见的光纤电缆等具体层面的物质,它的主要任务是负责处理数据链路层传递下来地信息,或者将信息传送给接收方地数据链路层,主要作用是用于承上启下。在物理层上所传数据的单位是比特。它的任务就是透明地传送比特流,从而保证信息能在具体地物理设备上进行传输。

物理层考虑是怎样才能连接各种计算机的传输媒体上传输数据比特流而不是指具体传输媒体。现有的物理设备种类繁多而通信手段又有许多不同的方式。物理层真正的作用正是要尽可能屏蔽掉这些传输媒体和通信手段的差异,是物理层上方的数据链路层感觉不到这些差异,这样就可以使数据链路层只需要考虑如何完成本层的协议和服务。在物理层这里定义了机械特性、电器特性、功能特性、过程特性从而屏蔽了差异。

  • 1、机械特性:指明接口所用的接线器的形状和尺寸、引线数目和排列、固定和锁定装置等等。
  • 2、电气特性:指明在接口电缆的各条线上出现的电压的范围。
  • 3、功能特性:指明某条线上出现的某一电平的电压表示何意。
  • 4、规程特性:指明对于不同功能的各种可能事件的出现顺序。(各个相关部件的工作步骤)

综上所述整个过程可以描述为:

在这里插入图片描述

  • 发送方

应用层产生消息→运输层对消息使用 TCP 或者 UDP 协议进行封装 →网络层使用 IP 协议进行封装→数据链路层对数据进行封装 →物理层将消息转为比特流在物理设备上传输。

  • 接收方

物理层:将比特流转成数据链路层能够解析消息 → 数据链路层:局域网信息传递→网络层:去掉 ip 协议对信息的封装 →运输层:去掉 TCP/UDP 协议的封装→应用层:将信息解析出来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值