第二十一章 网络编程

一、网络的相关概念

1. 网络通信

(1)网络通信:将 数据 通过网络从一台设备传输到另一台设备

(2)java.net 包下提供了一系列的类或接口,完成网络通信

2. 网络

  1. 概念:两台或多台设备通过一定物理设备连接起来构成了网络

  2. 根据网络的覆盖范围不同,对网络进行分类:

    1️⃣局域网:覆盖范围最小,仅仅覆盖一个教室或一个机房

    2️⃣城域网:覆盖范围较大,可以覆盖一个城市

    3️⃣广域网:覆盖范围最大,可以覆盖全国,甚至全球,万维网是广域网的代表

3. IP 地址

(1)概念:用于唯一标识网络中的每台计算机/主机

(2)查看 ip 地址: ipconfig

(3)ip 地址的表示形式:点分十进制 XX.XX.XX.XX(4 个字节,32 位)

(4)每一个十进制数的范围:0~255

(5)ip 地址的组成 = 网络地址(192.168.16) + 主机地址(69),比如:192.168.16.69

(6)IPV6 是互联网工程任务组设计的用于替代 IPV4 的下一代 IP 协议,其地址数量号称可为全世界的每一粒沙子编上一个地址

(7)由于 IPV4 最大的问题在于网络地址资源有限,严重制约了互联网的应用和发展。IPv6 的使用,不仅能解决网络地址资源数量的问题,而且也解决了多种接入设备连入互联的障碍

ipv4 地址分类:

4. 域名

域名相对于 IP 方便记忆,将 IP 地址映射成域名。

5. 端口号

(1)概念:用于标识计算机上某个特定的网络程序

(2)表示形式:以整数形式,范围 0~65535

(3)0~1024 已经被占用,比如 ssh 22,ftp 21,smtp 25,http 80

6. 网络通信协议


TCP/IP:Transmission Control Protocol / Internet Protocol,传输控制协议/因特网互联协议,又叫网络通讯协议。

这个协议是 Internet 最基本的协议、Internet 国际互联网络的基础,简单地说,就是由网络层的IP协议和传输层的TCP协议组成的。

7. TCP和UDP

TCP协议:传输控制协议

(1)使用TCP协议前,须先建立 TCP 连接,形成传输数据通道

(2)传输前,采用"三次握手"方式,是可靠的

(3)TCP协议进行通信的两个应用进程:客户端、服务端

(4)在连接中可进行大数据量的传输

(5)传输完毕,需释放已建立的连接,效率低

(6)类似打电话

UDP协议:用户数据协议

(1)将数据、源、目的封装成数据包,不需要建立连接

(2)每个数据报的大小限制在64K内,不适合传输大量数据

(3)因无需连接,故是不可靠的

(4)发送数据结束时无需释放资源(因为不是面向连接的),速度快

(5)类似发短信

二、InetAddress 类

java 复制代码
    public static void main(String[] args) throws Exception {
 
        //1.获取本机InetAddress对象
        InetAddress localHost = InetAddress.getLocalHost();
        System.out.println(localHost); // yiry/192.168.1.5
 
        //2.根据指定主机名获取ip地址对象
        InetAddress host1 = InetAddress.getByName("yiry");
        System.out.println(host1); //  yiry/192.168.1.5
 
        //3.根据指定域名获取ip地址对象
        InetAddress host2 = InetAddress.getByName("www.baidu.com");
        System.out.println(host2); //  www.baidu.com/183.232.231.172
 
        //4.获取 InetAddress对象的主机名
        String hostName = host2.getHostName();
        System.out.println(hostName);//  www.baidu.com
 
        //5.获取 InetAddress对象的地址
        String hostAddress = host2.getHostAddress();
        System.out.println(hostAddress);//  183.232.231.172
        
    }

三、Socket

1. Socket 基本介绍

(1)套接字(Socket)开发网络应用程序被广泛采用,以至于成为事实上的标准

(2)通信的两端都要有 Socket,是两台机器间通信的端点

(3)网络通信其实就是 Socket 的通信。

(4)Socket 允许程序把网络连接当成一个流,数据在两个 Socket 间通过 IO 传输。

(5)一般主动发起通信的应用程序属客户端,等待通信请求的为服务端

四、TCP 网络通信编程

1. 应用案例1-字节流

  1. 编写一个服务器端,和一个客户端
  2. 服务器端在9999端口监听
  3. 客户端连接到服务器端,发送"hello,server",然后退出
  4. 服务器端接收到客户端发送的信息,输出,并退出

服务端

java 复制代码
    public static void main(String[] args) throws IOException {
        // 在本机的 9999 端口监听,等待连接
        ServerSocket serverSocket = new ServerSocket(9999);
        // 没有客户端连接 9999 端口时,程序会阻塞,等待连接
        Socket socket = serverSocket.accept();
        System.out.println("服务端:" + socket.getClass());
        InputStream is = socket.getInputStream();
        byte[] buf = new byte[1024];
        int readLen = 0;
        while ((readLen = is.read(buf)) != -1) {
            System.out.println(new String(buf, 0, readLen));
        }
        is.close();
        socket.close();
        serverSocket.close();
    }

客户端

java 复制代码
    public static void main(String[] args) throws Exception {
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端:" + socket.getClass());
        
        OutputStream os = socket.getOutputStream();
        os.write("hello,server".getBytes());
        
        os.close();
        socket.close();
    }

2. 应用案例2-字节流(互发)

  1. 编写一个服务端,和一个客户端
  2. 服务器端在9999端口监听
  3. 客户端连接到服务器端,发送"hello,server" 并接收服务器端回发的 "hello,client",再退出
  4. 服务器端接收到客户端发送的信息,输出,并发送"hello,client" 再退出

设置写入结束标记: socket.shutdownOutput();

服务端

java 复制代码
    public static void main(String[] args) throws IOException {
        // 在本机的 9999 端口监听,等待连接
        ServerSocket serverSocket = new ServerSocket(9999);
        // 没有客户端连接 9999 端口时,程序会阻塞,等待连接
        Socket socket = serverSocket.accept();
        System.out.println("服务端:" + socket.getClass());
        InputStream is = socket.getInputStream();
        byte[] buf = new byte[1024];
        int readLen = 0;
        while ((readLen = is.read(buf)) != -1) {
            System.out.println(new String(buf, 0, readLen));
        }
 
        OutputStream os = socket.getOutputStream();
        os.write("hello,client".getBytes());
        socket.shutdownOutput();
 
        os.close();
        is.close();
        socket.close();
        serverSocket.close();
    }

客户端

java 复制代码
    public static void main(String[] args) throws Exception {
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端:" + socket.getClass());
        OutputStream os = socket.getOutputStream();
        os.write("hello,server".getBytes());
        socket.shutdownOutput();
 
        InputStream is = socket.getInputStream();
        byte[] buf = new byte[1024];
        int readLen = 0;
        while ((readLen = is.read(buf))!= -1){
            System.out.println(new String(buf,0,readLen));
        }
 
        is.close();
        os.close();
        socket.close();
    }

3. 应用案例3-字符流

设置写入结束标记: Writer.newLine();
readLine() 配合使用

服务端

java 复制代码
    public static void main(String[] args) throws IOException {
        // 在本机的 9999 端口监听,等待连接
        ServerSocket serverSocket = new ServerSocket(9999);
        // 没有客户端连接 9999 端口时,程序会阻塞,等待连接
        Socket socket = serverSocket.accept();
        System.out.println("服务端:" + socket.getClass());
        InputStream is = socket.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String s = br.readLine();
        System.out.println(s);
 
        OutputStream os = socket.getOutputStream();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
        bw.write("hello,client");
        bw.newLine();
        bw.flush();
 
        bw.close();
        br.close();
        socket.close();
        serverSocket.close();
    }

客户端

java 复制代码
    public static void main(String[] args) throws Exception {
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("客户端:" + socket.getClass());
        OutputStream os = socket.getOutputStream();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
        bw.write("hello,server");
        // 插入一个换行符,表示结束标记
        bw.newLine();
        // 字符流需要刷新
        bw.flush();
 
        InputStream is = socket.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        String s = br.readLine();
        System.out.println(s);
 
        br.close();
        bw.close();
        socket.close();
    }

4. 应用案例4

  1. 编写一个服务端,和一个客户端
  2. 服务器端在 8888 端口监听
  3. 客户端连接到服务端,发送一张图片 e:\\gie.png
  4. 服务器端接收到客户端发送的图片,保存到 src 下,发送"收到图片"再退出
  5. 客户端接收到服务端发送的"收到图片",再退出
  6. 该程序要求使用 StreamUtils.java
java 复制代码
public class StreamUtils {
 
    /*
        将输入流转换成byte[],即把文件的内容读入到byte[]
     */
    public static byte[] streamToByteArray(InputStream is) throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        byte[] b = new byte[1024];
        int len;
        while ((len = is.read(b)) != -1) {
            bos.write(b, 0, len);
        }
        byte[] array = bos.toByteArray();
        bos.close();
        return array;
    }
 
    /*
        将InputStream 转换成 String
    */
    public static String streamToString(InputStream is) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder builder = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            builder.append(line + "\r\n");
        }
        return builder.toString();
    }
 
}

服务端

java 复制代码
public class Server_04 {
    public static void main(String[] args) throws IOException {
 
        ServerSocket serverSocket = new ServerSocket(8888);
        // 等待连接
        Socket socket = serverSocket.accept();
 
        InputStream is = socket.getInputStream();
        BufferedInputStream bis = new BufferedInputStream(is);
 
        // 文件对应的字节数组
        byte[] bytes = StreamUtils.streamToByteArray(bis);
        String filepath = "src\\ces1.jpg";
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filepath));
        bos.write(bytes);
        bos.close();
 
        OutputStream os = socket.getOutputStream();
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
        bw.write("服务端收到图片");
        bw.flush();
        socket.shutdownOutput();
 
        bw.close();
        bis.close();
        socket.close();
        serverSocket.close();
 
    }
}

客户端

java 复制代码
public class Client_04 {
    public static void main(String[] args) throws Exception {
 
        String filepath = "d:\\ces.jpg";
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filepath));
        // 文件对应的字节数组
        byte[] bytes = StreamUtils.streamToByteArray(bis);
 
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
        OutputStream os = socket.getOutputStream();
        BufferedOutputStream bos = new BufferedOutputStream(os);
        bos.write(bytes);
        // 结束标记
        socket.shutdownOutput();
 
        InputStream is = socket.getInputStream();
        String s = StreamUtils.streamToString(is);
        System.out.println(s);
 
        is.close();
        bis.close();
        bos.close();
        socket.close();
 
    }
}

5. netstat 指令(P675)

(1)netstat -an 可以查看当前主机网络情况,包括 端口监听 情况和 网络连接 情况

(2)netstat -an more可以分页显示,按下空格翻页

(3)要求在 dos控制台 下执行

① Listening 表示某个端口在监听

② 如果有一个外部程序(客户端)连接到该端口,就会显示一条连接信息

netstat -anb more 权限更高

五、UDP 网络通信编程(了解)(P677)

1. 基本介绍

  1. DatagramSocketDatagramPacket 数据包/数据报 实观了基于 UDP 协议网络程序。
  2. UDP 数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证 UDP 数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
  3. DatagramPacket 对象封装了 UDP 数据报,在数据报中包含了发送端的 IP 地址和端口号以及接收端的 IP 地址和端口号。
  4. UDP 协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接

2. 基本流程

  1. 核心的两个类/对象 DatagramSocketDatagramPacket
  2. 建立发送端,接收端(没有服务端和客户端概念)
  3. 发送数据前,建立数据包/报 DatagramPacket 对象
  4. 调用 DatagramSocket 的发送、接收方法
  5. 关闭 DatagramSocket

UDP说明

  1. 没有明确的服务端和客户端,演变成数据的发送端和接收端
  2. 接收数据和发送数据是通过 DatagramSocket 对象完成
  3. 将数据封装到 DatagramPacket 对象/装包
  4. 当接收到 DatagramPacket 对象,需要进行拆包,取出数据
  5. DatagramSocket 可以指定在哪个端口接收数据

3. 应用案例

  1. 编写一个接收端A,和一个发送端B
  2. 接收端 A 在9999端口等待接收数据(receive
  3. 发送端 B 向接收端 A 发送数据 "hello,明天吃火锅~"
  4. 接收端 A 接收到发送端 B 发送的数据,回复 "好的,明天见" 再退出
  5. 发送端接收 回复的数据,再退出

UDP 接收端

dart 复制代码
public class UDPReceiverA {
    public static void main(String[] args) throws IOException {

        //1. 创建一个 DatagramSocket 对象,准备在 9999 接收数据
        DatagramSocket socket = new DatagramSocket(9999);
        //2. 构建一个 DatagramPacket 对象,准备接收数据
        // 在前面讲解 UDP 协议时,老师说过一个数据包最大 64k
        byte[] buf = new byte[1024];
        DatagramPacket packet = new DatagramPacket(buf, buf.length);

        //3. 调用 接收方法, 将通过网络传输的 DatagramPacket 对象
        // 填充到 packet 对象
        //老师提示: 当有数据包发送到 本机的 9999 端口时,就会接收到数据
        // 如果没有数据包发送到 本机的 9999 端口, 就会阻塞等待.
        System.out.println("接收端 A 等待接收数据..");
        socket.receive(packet);

        //4. 可以把 packet 进行拆包,取出数据,并显示.
        int length = packet.getLength();//实际接收到的数据字节长度
        byte[] data = packet.getData();//接收到数据

        String s = new String(data, 0, length);
        System.out.println(s);

        //===回复信息给 B 端
        //将需要发送的数据,封装到 DatagramPacket 对象
        data = "好的, 明天见".getBytes();
        //说明: 封装的 DatagramPacket 对象 data 内容字节数组 , data.length , 主机(IP) , 端口
        packet =
                new DatagramPacket(data, data.length, InetAddress.getByName("192.168.12.1"), 9998);
        socket.send(packet);//发送

        //5. 关闭资源
        socket.close();
        System.out.println("A 端退出...");
    }
}

UDP 发送端 B

dart 复制代码
public class UDPSenderB {
    public static void main(String[] args) throws IOException {
        //1.创建 DatagramSocket 对象,准备在 9998 端口 接收数据
        DatagramSocket socket = new DatagramSocket(9998);
        //2. 将需要发送的数据,封装到 DatagramPacket 对象
        byte[] data = "hello 明天吃火锅~".getBytes(); //
        //说明: 封装的 DatagramPacket 对象 data 内容字节数组 , data.length , 主机(IP) , 端口
        DatagramPacket packet =
                new DatagramPacket(data, data.length, InetAddress.getByName("192.168.12.1"), 9999);
        socket.send(packet);

        //3.=== 接收从 A 端回复的信息
        //(1) 构建一个 DatagramPacket 对象,准备接收数据
        // 在前面讲解 UDP 协议时,老师说过一个数据包最大 64k
        byte[] buf = new byte[1024];
        packet = new DatagramPacket(buf, buf.length);
        //(2) 调用 接收方法, 将通过网络传输的 DatagramPacket 对象
        // 填充到 packet 对象
        //老师提示: 当有数据包发送到 本机的 9998 端口时,就会接收到数据
        // 如果没有数据包发送到 本机的 9998 端口, 就会阻塞等待. socket.receive(packet);
        //(3) 可以把 packet 进行拆包,取出数据,并显示.
        int length = packet.getLength();//实际接收到的数据字节长度
        data = packet.getData();//接收到数据
        String s = new String(data, 0, length);
        System.out.println(s);

        //关闭资源
        socket.close();
        System.out.println("B 端退出");
    }
}
相关推荐
两个人的幸福4 天前
Windows 桌面应用自研 PHP 队列(下):完整代码与六大工程化优化
php
zzzzzz3104 天前
9K Star 炸裂开源!这个 C 语言写的代码知识图谱,把 Linux 内核索引压缩到了 3 分钟
linux·服务器·sql
BingoGo6 天前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
JaguarJack6 天前
PHP 泛型之殇 泛型 RFC 提案被拒绝
后端·php
用户3074596982077 天前
PHP 扩展——从入门到理解
php
鹏仔先生8 天前
拷贝漫画APP下载页PHP程序,后台带免费AI写作
php
大树888 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
小宇宙Zz8 天前
Maven依赖冲突
java·服务器·maven
网络研究院8 天前
2026年网络安全
网络·安全·法律·法规·趋势·发展
酣大智8 天前
ARP代理--工作原理
运维·网络·arp·arp代理