15.Java 网络编程(网络相关概念、InetAddress、NetworkInterface、TCP 网络通信、UDP 网络通信、超时中断)
一、网络相关概念
1、网络通信
-
网络通信指两台设备之间通过网络实现数据传输,将数据通过网络从一台设备传输到另一台设备
-
java.net 包下提供了一系列的类和接口用于完成网络通信
2、网络
- 两台以上设备通过一定物理设备连接构成网络,根据网络的覆盖范围不同,对网络进行分类
网络 | 说明 |
---|---|
局域网 | 覆盖范围最小,仅仅覆盖一个教室 |
城域网 | 覆盖范围较大,可以覆盖一个城市 |
广域网 | 覆盖范围最大,可以覆盖全国,设置全球,万维网是广域网的代表 |
3、IP 地址
-
IP 地址用于唯一标识网络中的每台计算机
-
查看本机 IP 地址:CMD 中输入 ipconfig 命令
-
IP 地址的表示形式为点分十进制(XX.XX.XX.XX),每一个十进制数的范围为 0 - 255
-
IP 地址的组成:网络地址 + 主机地址
-
IPv4 使用 4 个字节(32 位)表示地址,IPv6 使用 16 个字节(128 位)表示地址
-
IPv4 最大的问题在于网络地址资源有限,IPv6 是互联网工程任务组设计的用于替代 IPv4 的下一代 IP 协议,其地址数量号称可以为全世界的每一粒沙子编上一个地址
-
IPv4 地址分为五类,具体分类如下
- 注:其中 127.0.0.1 为本机地址
4、域名
- 域名是 IP 地址的映射,如 www.baidu.com,它是为了方便记忆
5、端口
-
端口用于标识计算机上某个特定的网络程序
-
表示形式:整数形式,范围 0 ~ 65535
-
已被占用的端口号:0 ~ 1024,如 ssh(22)、ftp(21)、smtp(25)、http(80)
-
常见网络程序端口号:Tomcat(8080)、MySQL(3306)
6、网络通信协议
- TCP / IP 协议,Internet 最基本的协议,由网络层的 IP 协议和传输层的 TCP 协议组成
7、TCP 协议与 UDP 协议
(1)TCP 协议
-
使用 TCP 协议前,需建立 TCP 连接,形成传输数据通道
-
传输前,采用三次握手方式(在吗、在的、好的),所以是可靠的
-
TCP 协议进行通信的两个应用程序:客户端,服务端
-
可进行大数据传输
-
传输完毕,需要释放资源,效率低
(2)UDP 协议
-
将数据、源、目的地封装成数据报,不需要建立连接
-
因为无需建立连接,所以是不可靠的
-
每份数据报的大小限制在 64kb 内
-
传输完毕,无需释放资源,速度快
二、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 网络编程中用于表示一个网络接口的类,它封装了关于网络接口的信息(例如,物理网卡、虚拟网卡),使得开发者可以方便地获取和操作这些信息,它有以下特点
-
网络接口表示:NetworkInterface 可以表示一个物理网络接口,例如,以太网卡(常见于防火墙和路由器),也可以表示一个虚拟网络接口,这些虚拟接口通常与机器的其它 IP 地址绑定到同个物理硬件。
-
访问网卡信息:NetworkInterface 类提供了多种方法来访问网卡设备的相关信息,例如,通过 getName 方法,可以获取到网络设备在操作系统中的名称,这些名称多数都以 eth 开头,后面跟着数字序号,例如,eth0、eth1,而 getIndex 方法返回的是网络接口的索引,它是一个大于或等于 0 的整数,当索引未知时,值就是 -1
-
判断接口状态:NetworkInterface 还提供了一些方法来判断网络接口的状态,例如,isUp 方法用于判断网络接口是否已经开启并正常工作,而 isLoopback 方法则用于判断该网络接口是否为 localhost 回调 / 回环接口
-
创建 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
-
Socket 又称套接字,用于开发网络应用程序
-
通信的两端都要有 Socket,这是两台机器间通信的端点
-
Socket 允许把网络连接当成一个流,数据通过 IO 流传输
-
一般主动发起通信的是客户端,等待通信的是服务端
2、TCP 连接
- 开启监听
ServerSocket serverSocket = new ServerSocket(【端口号】);
Socket socket = serverSocket.accept();
- 建立连接
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 指令
- 查看当前主机网络情况(端口监听情况和网络连接情况)
netstat -an
- 分页查看当前主机网络情况
netstat -an | more
(2)TCP 网络通信补充
- 当客户端连接到服务端后,客户端也会通过一个端口和服务端进行通信,这个端口是 TCP / IP 协议分配的
五、UDP 网络通信
1、DatagramSocket 与 DatagramPacket
(1)基本介绍
-
UDP 数据报通过数据报套接字(DatagramSocket)发送和接收
-
系统不保证 UDP 数据报一定能送达,也不确定何时送达
-
DatagramPacket 对象封装数据报,数据报中包含发送端的 IP 地址和端口号,以及接收端的 IP 地址和端口号
-
UDP 协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接
(2)DatagramSocket 常用方法
-
DatagramSocket(int port)
-
close()
-
receive(DatagramPacket p)
-
send(DatagramPacket p)
(3)DatagramPacket 常用方法
-
DatagramPacket(byte[] buf, int length)
-
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)客户端
- 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
- 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、基本介绍
-
ServerSocket.setSoTimeout(int timeout)
:为 ServerSocket 设置的,它指定了服务器套接字接受连接请求的超时时间(毫秒),如果设置为非零值,那么 accept 方法将阻塞,直到有连接到来或者超时为止,如果超时,accept 方法将抛出java.net.SocketTimeoutException
,如果设置为 0,那么 accept 方法将无限期地等待连接 -
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)!