自学内容网 自学内容网

15.Java 网络编程(网络相关概念、InetAddress、NetworkInterface、TCP 网络通信、UDP 网络通信、超时中断)

一、网络相关概念

1、网络通信
  • 网络通信指两台设备之间通过网络实现数据传输,将数据通过网络从一台设备传输到另一台设备

  • java.net 包下提供了一系列的类和接口用于完成网络通信

2、网络
  • 两台以上设备通过一定物理设备连接构成网络,根据网络的覆盖范围不同,对网络进行分类
网络说明
局域网覆盖范围最小,仅仅覆盖一个教室
城域网覆盖范围较大,可以覆盖一个城市
广域网覆盖范围最大,可以覆盖全国,设置全球,万维网是广域网的代表
3、IP 地址
  1. IP 地址用于唯一标识网络中的每台计算机

  2. 查看本机 IP 地址:CMD 中输入 ipconfig 命令

  3. IP 地址的表示形式为点分十进制(XX.XX.XX.XX),每一个十进制数的范围为 0 - 255

  4. IP 地址的组成:网络地址 + 主机地址

  5. IPv4 使用 4 个字节(32 位)表示地址,IPv6 使用 16 个字节(128 位)表示地址

  6. IPv4 最大的问题在于网络地址资源有限,IPv6 是互联网工程任务组设计的用于替代 IPv4 的下一代 IP 协议,其地址数量号称可以为全世界的每一粒沙子编上一个地址

  7. IPv4 地址分为五类,具体分类如下

  • 注:其中 127.0.0.1 为本机地址
4、域名
  • 域名是 IP 地址的映射,如 www.baidu.com,它是为了方便记忆
5、端口
  1. 端口用于标识计算机上某个特定的网络程序

  2. 表示形式:整数形式,范围 0 ~ 65535

  3. 已被占用的端口号:0 ~ 1024,如 ssh(22)、ftp(21)、smtp(25)、http(80)

  4. 常见网络程序端口号:Tomcat(8080)、MySQL(3306)

6、网络通信协议
  • TCP / IP 协议,Internet 最基本的协议,由网络层的 IP 协议和传输层的 TCP 协议组成
7、TCP 协议与 UDP 协议
(1)TCP 协议
  1. 使用 TCP 协议前,需建立 TCP 连接,形成传输数据通道

  2. 传输前,采用三次握手方式(在吗、在的、好的),所以是可靠的

  1. TCP 协议进行通信的两个应用程序:客户端,服务端

  2. 可进行大数据传输

  3. 传输完毕,需要释放资源,效率低

(2)UDP 协议
  1. 将数据、源、目的地封装成数据报,不需要建立连接

  2. 因为无需建立连接,所以是不可靠的

  3. 每份数据报的大小限制在 64kb 内

  4. 传输完毕,无需释放资源,速度快


二、InetAddress 类

1、常用方法
方法说明
InetAddress.getByAddress(byte[] addr)根据指定 IP 地址字节数组获取 InetAddress 对象
InetAddress.getByAddress(String host, byte[] addr)根据指定主机名和 IP 地址字节数组获取 InetAddress 对象
InetAddress.getLocalHost()获取本机的 InetAddress 对象
InetAddress.getByName(String host)根据指定主机名 / 域名获取 InetAddress 对象
【InetAddress 对象】.getHostName()获取 InetAddress 对象的主机名
【InetAddress 对象】.getHostAddress()获取 InetAddress 对象的 IP 地址
2、基本使用
  • InetAddressTest.java
package com.sunke.net;

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

public class InetAddressTest {
    public static void main(String[] args) throws UnknownHostException {
        byte[] ipAddressBytes = {(byte) 192, (byte) 168, 1, 1};
        InetAddress inetAddress1 = InetAddress.getByAddress(ipAddressBytes);
        System.out.println(inetAddress1);

        InetAddress inetAddress2 = InetAddress.getByAddress("Hello", ipAddressBytes);
        System.out.println(inetAddress2);

        InetAddress inetAddress3 = InetAddress.getLocalHost();
        System.out.println(inetAddress3);

        InetAddress inetAddress4 = InetAddress.getByName("www.baidu.com");
        System.out.println(inetAddress4);

        System.out.println(inetAddress2.getHostAddress());

        System.out.println(inetAddress2.getHostName());
    }
}
  • 输出结果
/192.168.1.1
Hello/192.168.1.1
LAPTOP-9OEPOBVO/192.168.200.1
www.baidu.com/180.101.50.242
192.168.1.1
Hello

三、NetworkInterface

1、基本介绍
  • NetworkInterface 是 Java 网络编程中用于表示一个网络接口的类,它封装了关于网络接口的信息(例如,物理网卡、虚拟网卡),使得开发者可以方便地获取和操作这些信息,它有以下特点
  1. 网络接口表示:NetworkInterface 可以表示一个物理网络接口,例如,以太网卡(常见于防火墙和路由器),也可以表示一个虚拟网络接口,这些虚拟接口通常与机器的其它 IP 地址绑定到同个物理硬件。

  2. 访问网卡信息:NetworkInterface 类提供了多种方法来访问网卡设备的相关信息,例如,通过 getName 方法,可以获取到网络设备在操作系统中的名称,这些名称多数都以 eth 开头,后面跟着数字序号,例如,eth0、eth1,而 getIndex 方法返回的是网络接口的索引,它是一个大于或等于 0 的整数,当索引未知时,值就是 -1

  3. 判断接口状态:NetworkInterface 还提供了一些方法来判断网络接口的状态,例如,isUp 方法用于判断网络接口是否已经开启并正常工作,而 isLoopback 方法则用于判断该网络接口是否为 localhost 回调 / 回环接口

  4. 创建 NetworkInterface 对象:由于 NetworkInterface 对象表示物理硬件和虚拟地址,因此不能任意构造,Java 提供了一些静态方法,可以通过名称、IP 地址或枚举的方式返回与某个网络接口关联的 NetworkInterface 对象

2、常用方法
方法说明
getNetworkInterfaces返回一个 Enumeration 对象,它包含了当前主机上所有的网络接口
这些网络接口可以是物理的(例如,以太网卡)或虚拟的(例如,虚拟专用网络适配器)
getName返回网络接口的名称,这个名称通常是操作系统分配的,用于唯一标识网络接口
例如,在类 Unix 系统上,物理网络接口的名称可能是 eth0、wlan0 等
isUp返回一个布尔值,表示网络接口是否处于活动状态
如果网络接口已经启动并可以发送和接收数据,那么这个方法将返回 true
isLoopback返回一个布尔值,用于判断网络接口是否是回环接口
回环接口是一个虚拟的网络接口,用于主机与自身的通信,大多数情况下它的地址是 127.0.0.1
getInetAddresses返回一个 Enumeration 对象,包含了绑定到网络接口的所有 InetAddress 对象
这些地址可能包括 IPv4 和 IPv6 地址,通过该方法,可以获取网络接口的所有 IP 地址信息
getSubInterfaces返回一个 Enumeration 对象,包含了当前网络接口的所有子接口
子接口是附加到主接口上的逻辑接口,它们可以有自己的配置和地址
3、基本使用
try {
    Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
    while (networkInterfaces.hasMoreElements()) {
        NetworkInterface ni = networkInterfaces.nextElement();

        // 打印网络接口名称
        System.out.println("Intface Nameer: " + ni.getName());

        // 打印网络接口是否启用
        System.out.println("Is Interface Up: " + ni.isUp());

        // 打印网络接口是否为回环接口
        System.out.println("Is Loopback Interface: " + ni.isLoopback());

        // 获取并打印网络接口的所有 IP 地址
        Enumeration<InetAddress> addresses = ni.getInetAddresses();
        while (addresses.hasMoreElements()) {
            InetAddress address = addresses.nextElement();
            System.out.println("Interface Address: " + address.getHostAddress());
        }

        // 打印网络接口的子接口(如果有)
        if (ni.getSubInterfaces().hasMoreElements()) {
            for (NetworkInterface subNi : Collections.list(ni.getSubInterfaces())) {
                System.out.println("Sub-interface Name: " + subNi.getName());
            }
        }

        System.out.println("------------------------------");
    }
} catch (SocketException e) {
    throw new RuntimeException(e);
}
  • 输出结果
Intface Nameer: lo
Is Interface Up: true
Is Loopback Interface: true
Interface Address: 127.0.0.1
Interface Address: 0:0:0:0:0:0:0:1
------------------------------
Intface Nameer: net0
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: wlan0
Is Interface Up: false
Is Loopback Interface: false
Interface Address: fe80:0:0:0:dbf4:3572:4b4e:e227%wlan0
------------------------------
Intface Nameer: ppp0
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: wlan1
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: net1
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth0
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: net2
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth1
Is Interface Up: true
Is Loopback Interface: false
Interface Address: 192.168.40.1
Interface Address: fe80:0:0:0:ce62:8aae:4aed:1b13%eth1
------------------------------
Intface Nameer: eth2
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: wlan2
Is Interface Up: true
Is Loopback Interface: false
Interface Address: 192.168.0.5
Interface Address: fe80:0:0:0:d22f:cfeb:5940:3a9f%wlan2
------------------------------
Intface Nameer: wlan3
Is Interface Up: false
Is Loopback Interface: false
Interface Address: fe80:0:0:0:1d73:1a4c:fc1f:85b8%wlan3
------------------------------
Intface Nameer: wlan4
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth3
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: net3
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth4
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: net4
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: net5
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: net6
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth5
Is Interface Up: false
Is Loopback Interface: false
Interface Address: fe80:0:0:0:405d:de8:75b4:7fc%eth5
------------------------------
Intface Nameer: eth6
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth7
Is Interface Up: false
Is Loopback Interface: false
Interface Address: fe80:0:0:0:76db:ea67:ac52:4fb1%eth7
------------------------------
Intface Nameer: eth8
Is Interface Up: true
Is Loopback Interface: false
Interface Address: 192.168.200.1
Interface Address: fe80:0:0:0:6e5b:2ea2:2ec8:6c8a%eth8
------------------------------
Intface Nameer: eth9
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth10
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth11
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth12
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth13
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth14
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: wlan5
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: wlan6
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: wlan7
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: wlan8
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: wlan9
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: wlan10
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: wlan11
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: wlan12
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: wlan13
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth15
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth16
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth17
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth18
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth19
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: eth20
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: wlan14
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: wlan15
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: wlan16
Is Interface Up: false
Is Loopback Interface: false
------------------------------
Intface Nameer: wlan17
Is Interface Up: false
Is Loopback Interface: false
------------------------------
4、补充
  • InetAddress.getLocalHost().getHostAddress() 通常用于获取运行 Java 程序的主机的本地 IP 地址,然而,它并不总是返回期望的特定网络接口的地址(例如,无线局域网 WLAN 接口),而是根据 Java 虚拟机和底层操作系统的网络配置和解析逻辑来确定,如果需要获取特定网络接口的地址(例如,WLAN),应该使用 NetworkInterface 类来枚举所有网络接口,并查找需要的接口
try {
    Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
    while (networkInterfaces.hasMoreElements()) {
        NetworkInterface networkInterface = networkInterfaces.nextElement();
        if (networkInterface.getName().startsWith("wlan") ||
                networkInterface.isUp() && !networkInterface.isLoopback() && !networkInterface.isVirtual()) {
            Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
            while (inetAddresses.hasMoreElements()) {
                InetAddress inetAddress = inetAddresses.nextElement();
                if (!inetAddress.isLoopbackAddress()) {
                    System.out.println("WLAN Address: " + inetAddress.getHostAddress());
                }
            }
        }
    }
} catch (SocketException e) {
    throw new RuntimeException(e);
}
  • 输出结果
WLAN Address: fe80:0:0:0:dbf4:3572:4b4e:e227%wlan0
WLAN Address: 192.168.40.1
WLAN Address: fe80:0:0:0:ce62:8aae:4aed:1b13%eth1
WLAN Address: 192.168.0.5
WLAN Address: fe80:0:0:0:d22f:cfeb:5940:3a9f%wlan2
WLAN Address: fe80:0:0:0:1d73:1a4c:fc1f:85b8%wlan3
WLAN Address: 192.168.200.1
WLAN Address: fe80:0:0:0:6e5b:2ea2:2ec8:6c8a%eth8

四、TCP 网络通信

1、Socket
  1. Socket 又称套接字,用于开发网络应用程序

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

  3. Socket 允许把网络连接当成一个流,数据通过 IO 流传输

  4. 一般主动发起通信的是客户端,等待通信的是服务端

2、TCP 连接
  1. 开启监听
ServerSocket serverSocket = new ServerSocket(【端口号】);
Socket socket = serverSocket.accept();
  1. 建立连接
Socket socket = new Socket("【IP 地址】", 【端口号】);
  • 设置写入结束标记
socket.shutdownOutput();
3、TCP 字节流编程
(1)服务端
  • TCPServerTest.java
package com.sunke.tcp;

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

public class TCPServerTest {
    public static void main(String[] args) throws IOException {
        // 服务端

        // 在本机 9999 端口监听,等待连接
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端在 9999 端口监听,等待连接...");
        Socket socket = serverSocket.accept();

        // 得到 Socket 对象的输入流对象并打印数据
        InputStream inputStream = socket.getInputStream();
        byte[] dataArr = new byte[10];
        int length;
        while ((length = inputStream.read(dataArr)) != -1) {
            System.out.print(new String(dataArr, 0, length));
        }
        System.out.println();
        System.out.println("接收传输信息完成");

        // 回送消息
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello, client".getBytes());
        System.out.println("回送信息完成");

        // 设置结束标记
        socket.shutdownOutput();

        // 释放资源
        inputStream.close();
        socket.close();
        serverSocket.close();
    }
}
  • 输出结果
服务端在 9999 端口监听,等待连接...
hello, server
接收传输信息完成
回送信息完成
(2)客户端
  • TCPClientTest.java
package com.sunke.tcp;

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

public class TCPClientTest {
    public static void main(String[] args) throws IOException {
        // 客户端

        // 连接服务端:IP 地址 + 端口号
        Socket socket = new Socket(InetAddress.getLocalHost().getHostAddress(), 9999);

        // 得到 Socket 对象的输出流对象并写入数据
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("hello, server".getBytes());
        System.out.println("传输信息完成");

        // 设置结束标记
        socket.shutdownOutput();

        // 接受回送信息
        InputStream inputStream = socket.getInputStream();
        byte[] dataArr = new byte[10];
        int length;
        while ((length = inputStream.read(dataArr)) != -1) {
            System.out.print(new String(dataArr, 0, length));
        }
        System.out.println();
        System.out.println("接收回送信息完成");

        // 释放资源
        outputStream.close();
        socket.close();
    }
}
  • 输出结果
传输信息完成
hello, client
接收回送信息完成
4、TCP 字符流编程
(1)服务端
  • NewTCPServerTest.java
package com.sunke.tcp;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class NewTCPServerTest {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8888);
        System.out.println("服务端在 8888 端口监听,等待连接...");
        Socket socket = serverSocket.accept();

        InputStream inputStream = socket.getInputStream();
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        System.out.println(bufferedReader.readLine());
        System.out.println("接收传输信息完成");

        OutputStream outputStream = socket.getOutputStream();
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
        BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
        bufferedWriter.write("hello, client");
        bufferedWriter.flush();
        System.out.println("回送信息完成");
        socket.shutdownOutput();

        bufferedWriter.close();
        bufferedReader.close();
        socket.close();
        serverSocket.close();
    }
}
  • 输出结果
服务端在 8888 端口监听,等待连接...
hello, server
接收传输信息完成
回送信息完成
(2)客户端
  • NewTCPClientTest.java
package com.sunke.tcp;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

public class NewTCPClientTest {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket(InetAddress.getLocalHost().getHostAddress(), 8888);

        OutputStream outputStream = socket.getOutputStream();
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
        BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
        bufferedWriter.write("hello, server");
        bufferedWriter.flush();
        System.out.println("传输信息完成");
        socket.shutdownOutput();

        InputStream inputStream = socket.getInputStream();
        InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        System.out.println(bufferedReader.readLine());
        System.out.println("接收回送信息完成");

        bufferedReader.close();
        bufferedWriter.close();
        socket.close();
    }
}
  • 输出结果
传输信息完成
hello, client
接收回送信息完成
5、文件上传
(1)服务端
  • ImgCopyTCPServerTest.java
package com.sunke.tcp;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class ImgCopyTCPServerTest {
    public static void main(String[] args) throws IOException {

        // 服务端在 7777 端口监听,等待连接
        ServerSocket serverSocket = new ServerSocket(7777);
        System.out.println("服务端在 7777 端口监听,等待连接...");
        Socket socket = serverSocket.accept();

        // 包装 Socket 对象的字节输入流
        InputStream inputStream = socket.getInputStream();
        BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);

        // 包装图片的字节输出流
        FileOutputStream fileOutputStream = new FileOutputStream("d:\\newSpider.jpg");
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);

        // 保存图片
        byte[] imgArr = new byte[1024];
        int imgLength;
        while ((imgLength = bufferedInputStream.read(imgArr)) != -1) {
            bufferedOutputStream.write(imgArr, 0, imgLength);
        }
        System.out.println("接收图片完成");

        // 回送消息
        BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bufferedWriter.write("收到图片");

        // 必要刷新
        bufferedWriter.flush();

        // 设置结束标记
        socket.shutdownOutput();

        // 释放资源
        bufferedWriter.close();
        bufferedOutputStream.close();
        bufferedInputStream.close();
        socket.close();
        serverSocket.close();
    }
}
  • 输出结果
服务端在 7777 端口监听,等待连接...
接收图片完成
(2)客户端
  • ImgCopyTCPClientTest.java
package com.sunke.tcp;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

public class ImgCopyTCPClientTest {
    public static void main(String[] args) throws IOException {

        // 建立连接
        Socket socket = new Socket(InetAddress.getLocalHost().getHostAddress(), 7777);

        // 包装 Socket 对象的字节输出流
        OutputStream outputStream = socket.getOutputStream();
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);

        // 包装图片的字节输入流
        FileInputStream fileInputStream = new FileInputStream("d:\\spider.jpg");
        BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);

        // 传输图片
        byte[] imgArr = new byte[1024];
        int imgLength;
        while ((imgLength = bufferedInputStream.read(imgArr)) != -1) {
            bufferedOutputStream.write(imgArr, 0, imgLength);
        }
        System.out.println("传输图片完成");

        // 必要刷新
        bufferedOutputStream.flush();

        // 设置结束标记
        socket.shutdownOutput();

        // 接受回送消息
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        System.out.println(bufferedReader.readLine());

        // 释放资源
        bufferedReader.close();
        bufferedInputStream.close();
        bufferedOutputStream.close();
        socket.close();
    }
}
  • 输出结果
传输图片完成
收到图片
6、TCP 连续传输
(1)服务端
  • MyTCPServer.java
package com.sunke.tcpmoretest;

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

public class MyTCPServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("服务端在 9999 端口监听,等待连接...");

        Socket socket = serverSocket.accept();
        InputStream inputStream = socket.getInputStream();

        byte[] dataArr = new byte[100];
        int length;

        while ((length = inputStream.read(dataArr)) != -1) {
            String res = new String(dataArr, 0, length);
            System.out.println(res);
            if (res.equals("end")) {
                inputStream.close();
                socket.close();
                serverSocket.close();
                System.out.println("断开连接");
                return;
            }
        }
    }
}
  • 输出结果
服务端在 9999 端口监听,等待连接...
123
456
end
断开连接
(2)客户端
  • MyTCPClient.java
package com.sunke.tcpmoretest;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class MyTCPClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket(InetAddress.getLocalHost().getHostAddress(), 9999);
        System.out.println("连接已建立,请输入传输的内容");
        Scanner scanner = new Scanner(System.in);
        OutputStream outputStream = socket.getOutputStream();

        while (true) {
            String str = scanner.next();
            outputStream.write(str.getBytes());
            if (str.equals("end")) {
                outputStream.close();
                socket.close();
                System.out.println("断开连接");
                return;
            }
        }
    }
}
  • 输出结果
连接已建立,请输入传输的内容
123
456
end
断开连接
7、TCP 一对多
(1)服务端
  • MyTCPFather.java
package com.sunke.tcpmoretest;

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

public class MyTCPFather {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("MyTCPFather 服务端在 9999 端口监听,等待连接...");

        Socket socket = serverSocket.accept();
        InputStream inputStream = socket.getInputStream();

        byte[] dataArr = new byte[100];
        int length;

        while ((length = inputStream.read(dataArr)) != -1) {
            System.out.println(new String(dataArr, 0, length));
        }
    }
}
  • 输出结果
MyTCPFather 服务端在 9999 端口监听,等待连接...
MyTCPSon1: 123
(2)客户端
  • MyTCPSon1.java
package com.sunke.tcpmoretest;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class MyTCPSon1 {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket(InetAddress.getLocalHost().getHostAddress(), 9999);
        System.out.println("MyTCPSon1 连接已建立,请输入传输的内容");
        Scanner scanner = new Scanner(System.in);
        OutputStream outputStream = socket.getOutputStream();

        while (true) {
            String str = "MyTCPSon1: " + scanner.next();
            outputStream.write(str.getBytes());
        }
    }
}
  • 输出结果
MyTCPSon1 连接已建立,请输入传输的内容
123
  • MyTCPSon2.java
package com.sunke.tcpmoretest;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class MyTCPSon2 {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket(InetAddress.getLocalHost().getHostAddress(), 9999);
        System.out.println("MyTCPSon2 连接已建立,请输入传输的内容");
        Scanner scanner = new Scanner(System.in);
        OutputStream outputStream = socket.getOutputStream();

        while (true) {
            String str = "MyTCPSon2: "+ scanner.next();
            outputStream.write(str.getBytes());
        }
    }
}
  • 输出结果
MyTCPSon2 连接已建立,请输入传输的内容
123
8、补充
(1)netstat 指令
  1. 查看当前主机网络情况(端口监听情况和网络连接情况)
netstat -an
  1. 分页查看当前主机网络情况
netstat -an | more
(2)TCP 网络通信补充
  • 当客户端连接到服务端后,客户端也会通过一个端口和服务端进行通信,这个端口是 TCP / IP 协议分配的

五、UDP 网络通信

1、DatagramSocket 与 DatagramPacket
(1)基本介绍
  1. UDP 数据报通过数据报套接字(DatagramSocket)发送和接收

  2. 系统不保证 UDP 数据报一定能送达,也不确定何时送达

  3. DatagramPacket 对象封装数据报,数据报中包含发送端的 IP 地址和端口号,以及接收端的 IP 地址和端口号

  4. UDP 协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接

(2)DatagramSocket 常用方法
  1. DatagramSocket(int port)

  2. close()

  3. receive(DatagramPacket p)

  4. send(DatagramPacket p)

(3)DatagramPacket 常用方法
  1. DatagramPacket(byte[] buf, int length)

  2. DatagramPacket(byte[] buf, int length, InetAddress address, int port)

2、UDP 基本使用
(1)服务端
  • UDPServer.java
package com.sunke.udp;

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

public class UDPServer {
    public static void main(String[] args) throws IOException {

        // 构建一个 DatagramSocket 对象,在 9999 端口接收数据
        DatagramSocket datagramSocket = new DatagramSocket(9999);

        // 准备接受数据报
        byte[] buf = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);

        // 调用接收方法,通过网络传输的 DatagramPacket 对象会填充到此
        System.out.println("Server 在 9999 端口等待接受数据报...");
        datagramSocket.receive(datagramPacket);

        // 拆包
        int length = datagramPacket.getLength();
        byte[] data = datagramPacket.getData();
        String s = new String(data, 0, length);
        System.out.println(s);

        // 释放资源
        datagramSocket.close();
    }
}
  • 输出结果
Server 在 9999 端口等待接受数据报...
Hello Server
(2)客户端
  • UDPClient.java
package com.sunke.udp;

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

public class UDPClient {
    public static void main(String[] args) throws IOException {
        // 创建 DatagramSocket 对象,准备发送数据
        DatagramSocket datagramSocket = new DatagramSocket(8888);

        // 准备发送数据报
        byte[] bytes = "Hello Server".getBytes();
        DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 9999);

        // 发送数据报
        datagramSocket.send(datagramPacket);
        System.out.println("数据报发送完毕");

        // 释放资源
        datagramSocket.close();
    }
}
  • 输出结果
数据报发送完毕
3、UDP 连续传输
(1)服务端
  • MyUDPServer.java
package com.sunke.udpmoretest;

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

public class MyUDPServer {
    public static void main(String[] args) throws IOException {
        DatagramSocket datagramSocket = new DatagramSocket(9999);
        System.out.println("Server 在 9999 端口等待接收数据报...");

        byte[] buf = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);

        while (true) {
            datagramSocket.receive(datagramPacket);
            int length = datagramPacket.getLength();
            byte[] data = datagramPacket.getData();
            String s = new String(data, 0, length);
            System.out.println(s);
            if (s.equals("end")) {
                datagramSocket.close();
                System.out.println("Server 关闭");
                return;
            }
        }
    }
}
  • 输出结果
Server 在 9999 端口等待接收数据报...
123
123
end
Server 关闭
(2)客户端
  • MyUDPClient.java
package com.sunke.udpmoretest;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;

public class MyUDPClient {
    public static void main(String[] args) throws IOException {
        DatagramSocket datagramSocket = new DatagramSocket(8888);
        Scanner scanner = new Scanner(System.in);

        System.out.println("请输入传输内容");

        while (true) {
            String str = scanner.next();
            byte[] bytes = str.getBytes();
            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 9999);
            datagramSocket.send(datagramPacket);
            if (str.equals("end")) {
                datagramSocket.close();
                System.out.println("Client 关闭");
                return;
            }
        }
    }
}
  • 输出结果
请输入传输内容
123
123
end
Client 关闭
4、UDP 一对多
(1)服务端
  • MyUDPFather.java
package com.sunke.udpmoretest;

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

public class MyUDPFather {
    public static void main(String[] args) throws IOException {
        DatagramSocket datagramSocket = new DatagramSocket(9999);
        System.out.println("Server 在 9999 端口等待接收数据报...");

        byte[] buf = new byte[1024];
        DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);

        while (true) {
            datagramSocket.receive(datagramPacket);
            int length = datagramPacket.getLength();
            byte[] data = datagramPacket.getData();
            String s = new String(data, 0, length);
            System.out.println(s);
        }
    }
}
  • 输出结果
Server 在 9999 端口等待接收数据报...
MyUDPSon1: 123
MyUDPSon2: 123
(2)客户端
  1. MyUDPSon1.java
package com.sunke.udpmoretest;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;

public class MyUDPSon1 {
    public static void main(String[] args) throws IOException {
        DatagramSocket datagramSocket = new DatagramSocket(8888);
        Scanner scanner = new Scanner(System.in);

        System.out.println("MyUDPSon1 请输入传输内容");

        while (true) {
            String str = "MyUDPSon1: " + scanner.next();
            byte[] bytes = str.getBytes();
            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 9999);
            datagramSocket.send(datagramPacket);
        }
    }
}
  • 输出结果
MyUDPSon1 请输入传输内容
123
  1. MyUDPSon2.java
package com.sunke.udpmoretest;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;

public class MyUDPSon2 {
    public static void main(String[] args) throws IOException {
        DatagramSocket datagramSocket = new DatagramSocket(8889);
        Scanner scanner = new Scanner(System.in);

        System.out.println("MyUDPSon2 请输入传输内容");

        while (true) {
            String str = "MyUDPSon2: " + scanner.next();
            byte[] bytes = str.getBytes();
            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 9999);
            datagramSocket.send(datagramPacket);
        }
    }
}
  • 输出结果
MyUDPSon2 请输入传输内容
123

六、超时中断

1、基本介绍
  1. ServerSocket.setSoTimeout(int timeout):为 ServerSocket 设置的,它指定了服务器套接字接受连接请求的超时时间(毫秒),如果设置为非零值,那么 accept 方法将阻塞,直到有连接到来或者超时为止,如果超时,accept 方法将抛出 java.net.SocketTimeoutException,如果设置为 0,那么 accept 方法将无限期地等待连接

  2. DatagramSocket.setSoTimeout(int timeout):为 DatagramSocket 设置的,它指定了数据报套接字发送或接收数据报的超时时间(毫秒),如果设置为非零值,那么 receive 方法将阻塞,直到有数据报到来或者超时为止,如果超时,receive 方法将抛出 java.net.SocketTimeoutException,如果设置为 0,那么 receive() 方法将无限期地等待数据报

2、演示
(1)TCP 超时中断
try {
    ServerSocket serverSocket = new ServerSocket(7777);
    serverSocket.setSoTimeout(2 * 1000);
    Socket accept = serverSocket.accept();
} catch (SocketTimeoutException e) {
    System.out.println("TCP 等待连接超时了");
} catch (IOException e) {
    e.printStackTrace();
}
try {
    ServerSocket serverSocket = new ServerSocket(7777);
    serverSocket.setSoTimeout(2 * 1000);
    Socket accept = serverSocket.accept();
} catch (IOException e) {
    if (e instanceof SocketTimeoutException) {
        System.out.println("TCP 等待连接超时了");
    } else {
        e.printStackTrace();
    }
}
  • 输出结果
TCP 等待连接超时了
(2)UDP 超时中断
try {
    DatagramSocket datagramSocket = new DatagramSocket(8888);
    byte[] receiveBytes = new byte[1024];
    DatagramPacket datagramPacket = new DatagramPacket(receiveBytes, receiveBytes.length);
    datagramSocket.setSoTimeout(2 * 1000);
    datagramSocket.receive(datagramPacket);
} catch (SocketTimeoutException e) {
    System.out.println("UDP 接收数据超时了");
} catch (Exception e) {
    e.printStackTrace();
}
  • 输出结果
UDP 接收数据超时了

原文地址:https://blog.csdn.net/weixin_52173250/article/details/144407056

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!