Java网络编程初步入门
网络的重要概念
基本概念涉及很多计网知识, 这里不过多赘述
一. IP地址
用于唯一的标识网络中的每台计算机
- IP地址通常使用点分十进制来表示. xx.xx.xx.xx, 每一个十进制数的范围是[0, 255]
- 一个IP地址分为两个部分, IP地址=网络地址+主机地址
- IPv6是互联网工程任务组设计的用于替代IPv4的下一代IP协议, 地址长度为128位, 是IPv4的四倍, 采用的是冒分十六进制
- IPv4分为
A, B, C, D, E
五类地址
二. 域名和端口
- 域名其实是将IP地址映射成为的一段信息, 解决了记忆ip地址的困难(怎么映射涉及到HTTP协议)
- 端口号用于标识计算机上运行的某一个特定的网络程序, 通常以整数形式表示, 端口范围是0-65535
- 0-1024已经被占用, 例如ssh: 22, smtp: 25, http: 80
常见的一些服务默认端口:
Tomcat: 8080
MySQL: 3306
Oracle: 1521
SqlServer: 1433
三. 网络通信协议
TCP/IP协议
- TCP协议, 是一种传输控制协议, 需要建立TCP连接, 形成传输数据通道, 采用"三次握手", 是可靠的, 进行通信的两个应用进程是客户端和服务端, 在连接中可以进行大数据量的传输, 传输完毕之后需要释放已经建立的连接, 效率低
- UDP协议, 是用户数据协议, 将数据, 源, 目的封装成数据报, 不需要建立连接, 每个数据报的大小限制在64K内, 因为无需链接, 故不可靠, 发送数据结束时无需释放资源, 速度快
网络编程
Java中专门提供了java.net包, 里面包含了Java网络编程所需要的类和接口
一. InetAddress
- 获取本机的
InetAddress
对象, 然后获取本地localHost
对象, 前半部分是主机名, 后半部分是地址, 中间使用"/"分割
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);
- 根据指定的主机名获取 InetAddress对象
InetAddress inetaddress = InetAddress.getByName("xxx");
System.out.println(inetaddress);
- 根据域名返回, 比如
www.baidu.com
InetAddress baidu = InetAddress.getByName("www.baidu.com");
System.out.println(baidu);
- 通过InetAddress对象, 获取对应地址
System.out.println(baidu.getHostAddress());
- 通过InetAddress对象, 获取对应的域名/主机名
System.out.println(baidu.getHostName());
二. Socket
套接字(Socket)在开发网络应用程序中被广泛采用, 以至于成为事实上的标准, 通信的两端都要有Socket, 是两台机器间通信的端点, 网络通信其实就是Socket之间的通信
1. 介绍
Socket允许程序把网络连接当成一个流, 数据在两个Socket间通过IO传输. 一般主动发起通信的应用程序属于客户端, 等待通信请求的为服务端
2. 使用
可以使用Socket来获取输入输出流, 从而达到读写的目的
使用Socket可以进行TCP编程和UDP编程
三. TCP编程
1. 传输数据
要求: 利用端口9999, 在本机设立客户端和服务端, 客户端向服务端写入"hello, server", 服务端读取之后输出出来
服务端:
public class TCPStreamServer {
public static void main(String[] args) throws IOException {
// 1. 在本机9999端口监听, 等待连接, 要求本机没有其他服务在监听9999
ServerSocket serverSocket = new ServerSocket(9999);
// 2. 当没有客户端连接9999端口时, 程序会阻塞, 等待连接
// 如果有, 则会返回Socket对象, 程序继续
// 这个serverSocket可以通过accept()方法返回多个Socket -> 多并发
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = 0;
while ((len = inputStream.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len));
}
inputStream.close();
socket.close();
System.out.println("服务端退出");
}
}
客户端
public class TCPStreamClient {
public static void main(String[] args) throws IOException {
// 1. 连接服务器(ip, 端口)
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
// 2. 得到和socket对象关联的输出流对象
OutputStream outputStream = socket.getOutputStream();
// 3. 通过输出流写数据, 在数据末尾一定要加入结束标记, 表示后面已经没有内容
outputStream.write("hello, server".getBytes());
socket.shutdownOutput();
// 4. 关闭流对象和客户端
outputStream.close();
socket.close();
System.out.println("客户端退出");
}
}
注意:
- socket只能获取字节流, 如果想使用字符流, 需要使用转换流
- 字符流中结束标记为
writer.newLine()
, 但是这里注意, 如果想要读取到结束标记, 必须使用writer.readLine()
, 否则会读取不到 - 写入完之后要记得
flush()
2. 传输文件
要求: 将客户端的图片, 通过网络上传到服务端, 服务端回复消息
客户端
public class TCPStreamClient {
public static void main(String[] args) throws IOException {
//1. 客户端连接服务端
Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
// 2. 将本地的图片读取出来
String path = "D:\\mypile\\acm\\qie.jpg";
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(path));
// 3. 这里面就是文件对应的字节数组
byte[] bytes = streamToByteArray(bufferedInputStream);
// 4. 通过socket获取到输出流, 将数据发送到服务端
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
bufferedOutputStream.write(bytes);
socket.shutdownOutput();
// 5. 获取服务端传来的信息
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = "";
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
// 5. 关闭流和socket
bufferedOutputStream.close();
bufferedInputStream.close();
socket.close();
bufferedReader.close();
}
public static byte[] streamToByteArray(InputStream is) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len = 0;
while ((len = is.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}
byte[] arrays = bos.toByteArray();
bos.close();
return arrays;
}
}
服务端
public class TCPStreamServer {
public static void main(String[] args) throws IOException {
//1. 服务端在本机监听8888端口
ServerSocket serverSocket = new ServerSocket(8888);
// 2. 等待连接
Socket socket = serverSocket.accept();
// 3. 读取客户端发送的数据, 通过Socket得到输入流
BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());
byte[] bytes = streamToByteArray(bufferedInputStream);
// 4. 将bytes数组写入指定的路径
String path = "src\\qie.jpg";
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(path));
bufferedOutputStream.write(bytes);
// 5. 向客户端回复收到图片
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferedWriter.write("收到图片");
bufferedWriter.flush();
socket.shutdownOutput();
// 关闭资源
bufferedOutputStream.close();
bufferedInputStream.close();
bufferedWriter.close();
socket.close();
serverSocket.close();
}
public static byte[] streamToByteArray(InputStream is) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int len = 0;
while ((len = is.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}
byte[] arrays = bos.toByteArray();
bos.close();
return arrays;
}
}
四. UDP编程
基本介绍
- 类
DatagramSocket
和DatagramPacket
实现了基于UDP 协议网络程序。 - UDP数据报通过数据报套接字
DatagramSocket
发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。 DatagramPacket
对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。- UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接
具体例子
发送端
public class UDPSender {
public static void main(String[] args) throws IOException {
// 1. 创建一个DatagramSocket 对象, 在指定端口发送数据,
// 注意, 如果是同一台设备发送和接受, 不要使用一样的端口
DatagramSocket datagramSocket = new DatagramSocket(9998);
// 2. 将需要发送的数据封装到数据报中
byte[] bytes = "hello".getBytes();
DatagramPacket datagramPacket =
new DatagramPacket(bytes, bytes.length, InetAddress.getByName("Ethereal"), 9999);
// 3. 发送数据报
datagramSocket.send(datagramPacket);
// 4. 关闭资源
datagramSocket.close();
System.out.println("发送完成");
}
}
接收端
public class UDPReceiver {
public static void main(String[] args) throws IOException {
// 1. 创建一个DatagramSocket 对象, 在指定端口接收数据
DatagramSocket datagramSocket = new DatagramSocket(9999);
// 2. 构建一个DatagramPacket 对象, 用来接受数据, 在UDP中一个数据报最大64K
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes, 1024);
// 3. 调用方法, 将通过网络传输的DatagramPacket对象填充到本地
// 注意: 当有数据报发送到9999端口时会接收到, 但是如果没有的话就会阻塞, 等待数据报
datagramSocket.receive(datagramPacket);
// 4. 可以把收到的数据报进行拆包, 从而获得数据
int length = datagramPacket.getLength(); // 数据的长度
byte[] data = datagramPacket.getData(); // 数据的内容
String s = new String(data, 0, length);
System.out.println(s);
// 5. 关闭资源
datagramSocket.close();
System.out.println("接收完成");
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)