目 录CONTENT

文章目录

从0开始学Java——网络编程(16)

Eric
2022-01-23 / 0 评论 / 0 点赞 / 189 阅读 / 4,426 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2023-12-12,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

网络编程

1 软件架构

1.1 C/S架构

  • C/S架构:全称为Client/Server架构,是指客户端和服务器架构。常见的程序有QQ、微信、坚果云等。

img

1.2 B/S架构

  • B/S架构:全称为Browser/Server架构,是指浏览器和服务器架构。常见的浏览器有Chrome、Firefox、Safari等。

img

1.3 总结

  • 两种架构各有千秋,但是无论那种架构,都离不开网络的支持。

  • 网络编程,就是在一定的协议下,实现两台计算机的通信的程序。

2 网络通信协议

2.1 TCP/IP协议参考模型

  • 网络通信协议:通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样。在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。

  • TCP/IP协议: 传输控制协议/因特网互联协议( Transmission Control Protocol/Internet Protocol),是Internet最基本、最广泛的协议。它定义了计算机如何连入因特网,以及数据如何在它们之间传输的标准。它的内部包含一系列的用于处理数据通信的协议,并采用了4层的分层模型,每一层都呼叫它的下一层所提供的协议来完成自己的需求。

img

  • 上图中,OSI参考模型:模型过于理想化,未能在因特网上进行广泛推广。 TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。

  • TCP/IP协议中的四层分别是应用层、传输层、网络层和链路层,每层分别负责不同的通信功能。
    链路层:链路层是用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤、网线提供的驱动。

  • 网络层:网络层是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络。而IP协议是一种非常重要的协议。IP(internet protocal)又称为互联网协议。IP的责任就是把数据从源传送到目的地。它在源地址和目的地址之间传送一种称之为数据包的东西,它还提供对数据大小的重新组装功能,以适应不同网络对包大小的要求。

  • 传输层:主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议。TCP(Transmission Control Protocol)协议,即传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。UDP(User Datagram Protocol,用户数据报协议):是一个无连接的传输层协议、提供面向事务的简单不可靠的信息传送服务。

  • 应用层:主要负责应用程序的协议,例如HTTP协议、FTP协议等。

  • 通常我们说的TCP/IP协议,其实是指TCP/IP协议族,因为该协议家族的两个最核心协议:TCP(传输控制协议)和IP(网际协议),为该家族中最早通过的标准,所以简称为TCP/IP协议。

2.2 TCP和UDP协议

2.2.1 概述

  • 通信的协议还是比较复杂的,java.net 包中包含的类和接口,它们提供低层次的通信细节。我们可以直接使用这些类和接口,来专注于网络程序开发,而不用考虑通信的细节。

  • java.net 包中提供了两种常见的网络协议(TCP和UDP)的支持。

2.2.2 UDP

  • UDP:用户数据报协议(User Datagram Protocol)。

  • 非面向连接的,不可靠的:UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议。

  • 大小限制的:数据被限制在64kb以内,超出这个范围就不能发送了。

  • 数据报(Datagram):网络传输的基本单位。

2.2.3 TCP

  • TCP:传输控制协议 (Transmission Control Protocol)。

  • 面向连接的,可靠的:TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。是一种面向连接的、可靠的、基于字节流的传输层的通信协议,可以连续传输大量的数据。类似于打电话的效果。这是因为它为当一台计算机需要与另一台远程计算机连接时,TCP协议会采用“三次握手”方式让它们建立一个连接,用于发送和接收数据的虚拟链路。数据传输完毕TCP协议会采用“四次挥手”方式断开连接。TCP协议负责收集这些信息包,并将其按适当的次序放好传送,在接收端收到后再将其正确的还原。TCP协议保证了数据包在传送中准确无误。TCP协议使用重发机制,当一个通信实体发送一个消息给另一个通信实体后,需要收到另一个通信实体确认信息,如果没有收到另一个通信实体确认信息,则会再次重复刚才发送的消息。

  • 三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。

    • 第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
    • 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。
    • 第三次握手,客户端再次向服务器端发送确认信息,确认连接。

img

  • 四次挥手:TCP协议中,在发送数据结束后,释放连接时需要经过四次挥手。

    • 第一次挥手:客户端向服务器端提出结束连接,让服务器做最后的准备工作。此时,客户端处于半关闭状态,即表示不再向服务器发送数据了,但是还可以接受数据。
    • 第二次挥手:服务器接收到客户端释放连接的请求后,会将最后的数据发给客户端。并告知上层的应用进程不再接收数据。
    • 第三次挥手:服务器发送完数据后,会给客户端发送一个释放连接的报文。那么客户端接收后就知道可以正式释放连接了。
    • 第四次挥手:客户端接收到服务器最后的释放连接报文后,要回复一个彻底断开的报文。这样服务器收到后才会彻底释放连接。这里客户端,发送完最后的报文后,会等待2MSL,因为有可能服务器没有收到最后的报文,那么服务器迟迟没收到,就会再次给客户端发送释放连接的报文,此时客户端在等待时间范围内接收到,会重新发送最后的报文,并重新计时。如果等待2MSL后,没有收到,那么彻底断开。

img

  • 完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性,TCP协议可以保证传输数据的安全,所以应用十分广泛,例如下载文件、浏览网页等。

3 网络编程三要素

3.1 协议

  • 协议:计算机网络通信必须遵守的规则。

3.2 IP地址

  • IP地址:指互联网协议地址(Internet Protocol Address),俗称IP。IP地址用来给一个网络中的计算机设备做唯一的编号。假如我们把“个人电脑”比作“一台电话”的话,那么“IP地址”就相当于“电话号码”。

  • IP地址的分类:

    • IPv4:是一个32位的二进制数,通常被分为4个字节,表示成a.b.c.d 的形式,例如192.168.65.100 。其中a、b、c、d都是0~255之间的十进制整数,那么最多可以表示42亿个。
    • IPv6:由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张。为了扩大地址空间,拟通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,表示成ABCD:EF01:2345:6789:ABCD:EF01:2345:6789,号称可以为全世界的每一粒沙子编上一个网址,这样就解决了网络地址资源数量不够的问题。
  • 特殊的IP地址:

    • 本地回环地址:127.0.0.1。
    • 主机名:localhost。

3.3 端口

  • 网络的通信,本质上是两个进程(应用程序)的通信。每台计算机都有很多的进程,那么在网络通信时,如何区分这些进程呢?

  • 如果说IP地址可以唯一标识网络中的设备,那么端口号就可以唯一标识设备中的进程(应用程序)了。

  • 端口号:用两个字节表示的整数,它的取值范围是0~65535

    • 公认端口:0~1023。被预先定义的服务通信占用,如:HTTP(80),FTP(21),Telnet(23)
    • 注册端口:1024~49151。分配给用户进程或应用程序。如:Tomcat(8080),MySQL(3306),Oracle(1521)。
    • 动态/ 私有端口:49152~65535。
  • 如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。

3.4 总结

  • 利用协议+IP地址+端口号 三元组合,就可以标识网络中的进程了,那么进程间的通信就可以利用这个标识与其它进程进行交互。

4 InetAddress类

  • 为了方便我们对IP地址的获取和操作,Java提供了一个类InetAddress供我们使用。

  • Internet上的主机有两种表示方式:

    • IP地址(hostAddress):112.80.248.75。
  • InetAddress类没有提供公共的构造器,而是提供了如下的静态方法来获取InetAddress实例:

public static InetAddress getByName(String host)
    throws UnknownHostException {}
public static InetAddress getLocalHost() throws UnknownHostException {}
public static InetAddress getByAddress(byte[] addr)
    throws UnknownHostException {}
  • InetAddress类提供了如下的常用方法:

  • 返回 IP 地址字符串(以文本表现形式):

public String getHostAddress() {}
  • 获取此 IP 地址的主机名:
public String getHostName() {}
  • 示例:
package top.open1024.demo;

import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-06 13:01
 */
public class Test {
    public static void main(String[] args) throws UnknownHostException {
        InetAddress inetAddress = InetAddress.getLocalHost();
        String hostName = inetAddress.getHostName();
        System.out.println("hostName = " + hostName); // hostName = xudaxian
        String hostAddress = inetAddress.getHostAddress();
        System.out.println("hostAddress = " + hostAddress); // hostAddress = 192.168.31.197
    }
}

5 Socket

  • 通信的两端都要有Socket(也可以叫“套接字”),是两台机器间通信的端点。网络通信其实就是Socket间的通信。Socket可以分为:

    • 流套接字(Stream Socket):使用TCP提供可以来的字节流服务。
      • ServerSocket:此类实现TCP服务器套接字。服务器套接字等待请求通过网络传入。
      • Socket:此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。
    • 数据报套接字(datagram socket):使用UDP提供“尽力而为”的数据报服务。
      • DatagramSocket:此类表示用来发送和接收UDP数据报包的套接字。

img

6 TCP网络编程

6.1 TCP发送端

  • TCP发送端发送数据的步骤:

  • ① 创建客户端的Socket对象和指定的服务端连接:

public Socket(String host, int port)
    throws UnknownHostException, IOException {}
  • ② 获取输出流,写数据:
public OutputStream getOutputStream() throws IOException {}
  • ③ 释放资源:
public synchronized void close() throws IOException {}
  • 示例:
package top.open1024.net;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-06 08:56
 */
public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 8000);

        // 发送数据
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("你好".getBytes());
        // 终止字节输出流,终止之前,向服务器发一个TCP的终止序列符号
        socket.shutdownOutput();

        // 获取数据
        InputStream inputStream = socket.getInputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inputStream.read(buffer)) != -1) {
            System.out.println("客户端收到的信息:" + new String(buffer, 0, len));
        }

        // 释放资源
        socket.close();
    }
}

6.2 TCP接收端

  • TCP接收端接收数据的步骤:

  • ① 创建服务器daunt的Socket对象:

public ServerSocket(int port) throws IOException {}
  • ② 监听客户端连接,返回一个Socket对象:
public Socket accept() throws IOException {}
  • ③ 获取输入流,读数据,并将数据显示在控制台:
public InputStream getInputStream() throws IOException {}
  • ④ 释放资源:
public void close() throws IOException {}
  • 示例:
package top.open1024.net;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-06 08:51
 */
public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8000);
        Socket socket = serverSocket.accept();

        // 获取数据
        InputStream inputStream = socket.getInputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inputStream.read(buffer)) != -1) {
            System.out.println("服务器收到的信息:" + new String(buffer, 0, len));
        }

        // 发送数据
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("世界".getBytes());

        // 释放资源
        socket.close();
        serverSocket.close();
    }
}

7 UDP网络编程

7.1 UDP发送端

  • UDP发送端发送数据的步骤:

  • ① 创建发送端的DatagramSocket对象。

  • ② 创建数据,并将数据打包(DatagramPacket)。

  • ③ 调用DatagramSocket对象的方法发送数据。

  • ④ 释放资源。

  • 示例:

package top.open1024.net2;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-06 13:29
 */
public class Client {
    public static void main(String[] args) throws IOException {
        // 创建发送端的DatagramSocket对象。
        DatagramSocket ds = new DatagramSocket();
        // 创建数据,并将数据打包(DatagramPacket)。
        String message = "open1024";
        byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 8000);
        // 调用DatagramSocket对象的方法发送数据
        ds.send(dp);
        // 释放资源
        ds.close();
    }
}

7.2 UDP接收端

  • UDP接收端接收数据的步骤:

  • ① 创建接收端的DatagramSocket对象。

  • ② 创建DatagramPacket对象,用于接收数据。

  • ③ 调用DatagramSocket的接收数据的方法将数据放入到DatagramPacket对象中。

  • ④ 解析DatagramPacket对象,将数据显示在控制台。

  • ⑤ 释放资源。

  • 示例:

package top.open1024.net2;

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

/**
 * @author open1024
 * @version 1.0
 * @since 2021-10-06 13:36
 */
public class Server {
    public static void main(String[] args) throws IOException {
        // 创建接收端的DatagramSocket对象,表示接收端从8000端口接收数据
        DatagramSocket ds = new DatagramSocket(8000);
        // 创建DatagramPacket对象,用于接收数据。
        byte[] buffer = new byte[1024];
        DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
        // 调用DatagramSocket的接收数据的方法将数据放入到DatagramPacket对象中。
        ds.receive(dp);
        // 拆分数据
        byte[] data = dp.getData();
        int length = dp.getLength();
        System.out.println(new String(data, 0, length));
        // 释放资源。
        ds.close();
    }
}
0

评论区