S01-21 JavaSE-网络编程
[TOC]
网络的相关概念
网络通信
- 概念:两台设备通过网络实现数据传输
- Java提供
java.net包用于网络通信
网络分类
| 类型 | 覆盖范围 |
|---|---|
| 局域网(LAN) | 教室、机房等小范围 |
| 城域网(MAN) | 一个城市 |
| 广域网(WAN) | 全国、全球(如万维网) |
IP地址
- 唯一标识网络中的每台主机
- 表示形式:点分十进制(xx.xx.xx.xx),每个十进制数范围0~255
- 组成:网络地址 + 主机地址
- IPv4:地址资源有限,已逐步被IPv6替代
- IPv6:地址数量极多,解决地址短缺问题
- 本机地址:127.0.0.1
IPv4地址分类
| 类型 | 网络号位数 | 主机号位数 | 范围 |
|---|---|---|---|
| A类 | 7位 | 24位 | 0.0.0.0 ~ 127.255.255.255 |
| B类 | 14位 | 16位 | 128.0.0.0 ~ 191.255.255.255 |
| C类 | 21位 | 8位 | 192.0.0.0 ~ 223.255.255.255 |
| D类 | 多播组号 | - | 224.0.0.0 ~ 239.255.255.255 |
| E类 | 保留 | - | 240.0.0.0 ~ 247.255.255.255 |
域名
- 作用:将IP地址映射为易记的名称(如www.baidu.com)
- 好处:避免记忆复杂的IP地址
端口号
- 标识计算机上的某个网络程序
- 范围:0~65535(2个字节)
- 0~1024:已被系统占用(如ssh 22、ftp 21、http 80)
- 常见程序端口:tomcat 8080、mysql 3306、oracle 1521、sqlserver 1433
网络通信协议
| OSI模型 | TCP/IP模型 | TCP/IP模型各层对应协议 |
|---|---|---|
| 应用层 | 应用层 | HTTP、FTP、Telnet、DNS |
| 表示层 | ||
| 会话层 | ||
| 传输层 | 传输层(TCP) | TCP、UDP |
| 网络层 | 网络层(IP) | IP、ICMP、ARP |
| 数据链路层 | 物理+数据链路层 | |
| 物理层 | Link |
TCP 和 UDP 对比
| 特性 | TCP协议(传输控制协议) | UDP协议(用户数据协议) |
|---|---|---|
| 连接要求 | 需建立连接(三次握手) | 无需建立连接 |
| 可靠性 | 可靠传输 | 不可靠传输 |
| 数据量限制 | 无限制,适合大批量数据 | 单个数据包最大64K,不适合大量数据 |
| 效率 | 低(需连接和释放) | 高(无需连接和释放) |
| 应用场景 | 文件传输、聊天等需可靠传输的场景 | 视频直播、短信等对实时性要求高的场景 |
InetAddress 类
常用方法
| 方法名 | 功能说明 |
|---|---|
| static InetAddress getLocalHost() | 获取本机InetAddress对象 |
| static InetAddress getByName(String host) | 根据主机名/域名获取IP地址对象 |
| String getHostName() | 获取主机名 |
| String getHostAddress() | 获取IP地址字符串 |
应用案例
java
package com.hspedu.api;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @author 韩顺平
* @version 1.0
* InetAddress应用
*/
public class API_ {
public static void main(String[] args) throws UnknownHostException {
// 获取本机InetAddress对象
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost); // 主机名/IP地址
// 根据主机名获取
InetAddress host2 = InetAddress.getByName("ThinkPad-PC");
System.out.println(host2);
// 根据域名获取
InetAddress host3 = InetAddress.getByName("www.baidu.com");
System.out.println(host3.getHostName()); // 主机名
System.out.println(host3.getHostAddress()); // IP地址
}
}Socket
基本介绍
- 套接字,是网络通信的端点
- 通信双方都需要Socket
- 网络通信本质是Socket间的通信
- 可将网络连接视为流,通过IO传输数据
- 主动发起通信的为客户端,等待通信的为服务端
TCP 网络通信编程
核心类
- ServerSocket:服务端,用于监听端口,接收客户端连接
- Socket:客户端,用于连接服务端,建立通信通道
应用案例1:客户端发送数据,服务端接收
服务端(SocketTCP01Server.java)
java
package com.hspedu.socket;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
/**
* @author 韩顺平
* @version 1.0
* TCP服务端
*/
public class SocketTCP01Server {
public static void main(String[] args) throws IOException {
// 在9999端口监听
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端,在9999端口监听,等待连接..");
// 等待客户端连接(阻塞)
Socket socket = serverSocket.accept();
System.out.println("服务端socket = " + socket.getClass());
// 读取客户端数据
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(buf)) != -1) {
System.out.println(new String(buf, 0, readLen));
}
// 关闭资源
inputStream.close();
socket.close();
serverSocket.close();
}
}客户端(SocketTCP01Client.java)
java
package com.hspedu.socket;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.io.IOException;
/**
* @author 韩顺平
* @version 1.0
* TCP客户端
*/
public class SocketTCP01Client {
public static void main(String[] args) throws IOException {
// 连接本机9999端口
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("客户端socket返回 = " + socket.getClass());
// 发送数据
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello, server".getBytes());
// 关闭资源
outputStream.close();
socket.close();
System.out.println("客户端退出.....");
}
}应用案例2:客户端与服务端双向通信
服务端(SocketTCP02Server.java)
java
package com.hspedu.socket;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
/**
* @author 韩顺平
* @version 1.0
* TCP服务端(双向通信)
*/
@SuppressWarnings({"all"})
public class SocketTCP02Server {
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[] buf = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(buf)) != -1) {
System.out.println(new String(buf, 0, readLen));
}
// 向客户端回复数据
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello, client".getBytes());
socket.shutdownOutput(); // 设置结束标记
// 关闭资源
outputStream.close();
inputStream.close();
socket.close();
serverSocket.close();
}
}客户端(SocketTCP02Client.java)
java
package com.hspedu.socket;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.io.IOException;
/**
* @author 韩顺平
* @version 1.0
* TCP客户端(双向通信)
*/
@SuppressWarnings({"all"})
public class SocketTCP02Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
// 发送数据
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello, server".getBytes());
socket.shutdownOutput(); // 设置结束标记
// 接收服务端回复
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen = inputStream.read(buf)) != -1) {
System.out.println(new String(buf, 0, readLen));
}
// 关闭资源
inputStream.close();
outputStream.close();
socket.close();
System.out.println("客户端退出.....");
}
}应用案例3:字符流双向通信
服务端(SocketTCP03Server.java)
java
package com.hspedu.socket;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
/**
* @author 韩顺平
* @version 1.0
* TCP服务端(字符流)
*/
@SuppressWarnings({"all"})
public class SocketTCP03Server {
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();
// 字节流转字符流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
// 回复客户端
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello client 字符流");
bufferedWriter.newLine(); // 换行符作为结束标记
bufferedWriter.flush(); // 手动刷新
// 关闭资源
bufferedWriter.close();
bufferedReader.close();
socket.close();
serverSocket.close();
}
}客户端(SocketTCP03Client.java)
java
package com.hspedu.socket;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.io.IOException;
/**
* @author 韩顺平
* @version 1.0
* TCP客户端(字符流)
*/
@SuppressWarnings({"all"})
public class SocketTCP03Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
// 发送数据
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello, server 字符流");
bufferedWriter.newLine(); // 换行符作为结束标记
bufferedWriter.flush(); // 手动刷新
// 接收回复
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
// 关闭资源
bufferedReader.close();
bufferedWriter.close();
socket.close();
System.out.println("客户端退出.....");
}
}应用案例4:文件上传(TCP)
工具类(StreamUtils.java)
java
package com.hspedu.upload;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* 流工具类
*/
public class StreamUtils {
/**
* 输入流转字节数组
*/
public static byte[] streamToByteArray(InputStream is) throws Exception {
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;
}
/**
* 输入流转字符串
*/
public static String streamToString(InputStream is) throws Exception {
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();
}
}服务端(TCPFileUploadServer.java)
java
package com.hspedu.upload;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @author 韩顺平
* @version 1.0
* 文件上传服务端
*/
public class TCPFileUploadServer {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务端在8888端口监听....");
Socket socket = serverSocket.accept();
// 读取客户端上传的文件
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bis);
// 保存文件到src目录
String destFilePath = "src\\abc.mp4";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
bos.write(bytes);
bos.close();
// 回复客户端
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("收到图片");
writer.flush();
socket.shutdownOutput();
// 关闭资源
writer.close();
bis.close();
socket.close();
serverSocket.close();
}
}客户端(TCPFileUploadClient.java)
java
package com.hspedu.upload;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.net.InetAddress;
import java.net.Socket;
/**
* @author 韩顺平
* @version 1.0
* 文件上传客户端
*/
public class TCPFileUploadClient {
public static void main(String[] args) throws Exception {
// 连接服务端8888端口
Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
// 读取本地文件
String filePath = "e:\\abc.mp4";
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
byte[] bytes = StreamUtils.streamToByteArray(bis);
// 发送文件到服务端
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(bytes);
bis.close();
socket.shutdownOutput(); // 设置结束标记
// 接收服务端回复
String s = StreamUtils.streamToString(socket.getInputStream());
System.out.println(s);
// 关闭资源
socket.getInputStream().close();
bos.close();
socket.close();
}
}netstat 指令
netstat -an:查看当前主机网络情况(端口监听、网络连接)netstat -an | more:分页显示- 状态说明:
LISTENING:端口正在监听ESTABLISHED:已建立连接
UDP 网络通信编程
核心类
- DatagramSocket:用于发送和接收数据报
- DatagramPacket:封装UDP数据报(包含发送端/接收端IP和端口)
应用案例:UDP双向通信
接收端A(UDPReceiverA.java)
java
package com.hspedu.udp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.io.IOException;
/**
* @author 韩顺平
* @version 1.0
* UDP接收端
*/
public class UDPReceiverA {
public static void main(String[] args) throws IOException {
// 在9999端口接收数据
DatagramSocket socket = new DatagramSocket(9999);
// 构建接收数据包
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
System.out.println("接收端A等待接收数据..");
// 接收数据(阻塞)
socket.receive(packet);
// 解析数据
int length = packet.getLength();
byte[] data = packet.getData();
String s = new String(data, 0, length);
System.out.println(s);
// 回复发送端B
data = "好的, 明天见".getBytes();
DatagramPacket sendPacket = new DatagramPacket(
data, data.length, InetAddress.getByName("192.168.12.1"), 9998
);
socket.send(sendPacket);
// 关闭资源
socket.close();
System.out.println("A端退出...");
}
}发送端B(UDPSenderB.java)
java
package com.hspedu.udp;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.io.IOException;
/**
* @author 韩顺平
* @version 1.0
* UDP发送端
*/
@SuppressWarnings({"all"})
public class UDPSenderB {
public static void main(String[] args) throws IOException {
// 在9998端口发送数据
DatagramSocket socket = new DatagramSocket(9998);
// 构建发送数据包
byte[] data = "hello 明天吃火锅~".getBytes();
DatagramPacket packet = new DatagramPacket(
data, data.length, InetAddress.getByName("192.168.12.1"), 9999
);
socket.send(packet);
// 接收接收端A的回复
byte[] buf = new byte[1024];
packet = new DatagramPacket(buf, buf.length);
socket.receive(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端退出...");
}
}本章作业
Homework01.java(TCP字符流聊天)
服务端(Homework01Server.java)
java
package com.hspedu.homework;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
/**
* TCP服务端(多轮聊天)
*/
@SuppressWarnings({"all"})
public class Homework01Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端在9999端口监听...");
Socket socket = serverSocket.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String line;
while ((line = br.readLine()) != null) {
// 根据客户端请求回复
String response;
if ("name".equals(line)) {
response = "我是nova";
} else if ("hobby".equals(line)) {
response = "编写java程序";
} else {
response = "你说啥呢";
}
bw.write(response);
bw.newLine();
bw.flush();
}
// 关闭资源
bw.close();
br.close();
socket.close();
serverSocket.close();
}
}客户端(Homework01Client.java)
java
package com.hspedu.homework;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.io.IOException;
import java.util.Scanner;
/**
* TCP客户端(多轮聊天)
*/
@SuppressWarnings({"all"})
public class Homework01Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("请输入请求(输入exit退出):");
String line = scanner.nextLine();
if ("exit".equals(line)) {
break;
}
bw.write(line);
bw.newLine();
bw.flush();
// 接收回复
String response = br.readLine();
System.out.println("服务端回复:" + response);
}
// 关闭资源
scanner.close();
bw.close();
br.close();
socket.close();
}
}Homework02.java(UDP问答)
接收端A(Homework02ReceiverA.java)
java
package com.hspedu.homework;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.io.IOException;
/**
* UDP接收端(问答)
*/
public class Homework02ReceiverA {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(8888);
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
System.out.println("接收端A等待接收数据...");
socket.receive(packet);
// 解析问题
String question = new String(packet.getData(), 0, packet.getLength());
System.out.println("收到问题:" + question);
// 准备回答
String answer;
if ("四大名著是哪些".equals(question)) {
answer = "四大名著是《红楼梦》《西游记》《水浒传》《三国演义》";
} else {
answer = "what?";
}
// 发送回答
byte[] data = answer.getBytes();
DatagramPacket sendPacket = new DatagramPacket(
data, data.length, packet.getAddress(), packet.getPort()
);
socket.send(sendPacket);
// 关闭资源
socket.close();
}
}发送端B(Homework02SenderB.java)
java
package com.hspedu.homework;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.io.IOException;
/**
* UDP发送端(问答)
*/
public class Homework02SenderB {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(8889);
// 发送问题
String question = "四大名著是哪些";
byte[] data = question.getBytes();
DatagramPacket packet = new DatagramPacket(
data, data.length, InetAddress.getByName("127.0.0.1"), 8888
);
socket.send(packet);
// 接收回答
byte[] buf = new byte[1024];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
String answer = new String(packet.getData(), 0, packet.getLength());
System.out.println("收到回答:" + answer);
// 关闭资源
socket.close();
}
}Homework03.java(文件下载)
服务端(Homework03Server.java)
java
package com.hspedu.homework;
import com.hspedu.upload.StreamUtils;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
/**
* 文件下载服务端
*/
public class Homework03Server {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务端在9999端口监听...");
Socket socket = serverSocket.accept();
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
String fileName = StreamUtils.streamToString(bis).trim();
// 准备文件(存在则发送,不存在则发送默认文件)
String filePath;
if ("高山流水".equals(fileName)) {
filePath = "e:\\高山流水.mp3";
} else {
filePath = "e:\\默认音乐.mp3"; // 默认文件
}
// 读取文件并发送
BufferedInputStream fileBis = new BufferedInputStream(new FileInputStream(filePath));
byte[] fileBytes = StreamUtils.streamToByteArray(fileBis);
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(fileBytes);
fileBis.close();
socket.shutdownOutput();
// 关闭资源
bos.close();
bis.close();
socket.close();
serverSocket.close();
}
}客户端(Homework03Client.java)
java
package com.hspedu.homework;
import com.hspedu.upload.StreamUtils;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.io.IOException;
import java.util.Scanner;
/**
* 文件下载客户端
*/
public class Homework03Client {
public static void main(String[] args) throws Exception {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
// 输入要下载的音乐名
Scanner scanner = new Scanner(System.in);
System.out.print("请输入要下载的音乐名:");
String fileName = scanner.nextLine();
// 发送音乐名给服务端
OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream());
osw.write(fileName);
osw.flush();
socket.shutdownOutput();
// 接收文件并保存到e盘
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] fileBytes = StreamUtils.streamToByteArray(bis);
String destFilePath = "e:\\" + fileName + ".mp3";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
bos.write(fileBytes);
// 关闭资源
bos.close();
bis.close();
osw.close();
scanner.close();
socket.close();
System.out.println("文件下载完成,保存路径:" + destFilePath);
}
}