当前位置: 首页 > news >正文

Java网络编程:从基础到实战

Java网络编程详解:从基础到实践

网络通信架构

网络编程中存在两种主流通信架构,它们各自有着不同的应用场景和特点:

1. BS架构(Browser/Server)

BS架构即浏览器/服务器架构,其核心特点是:

  • 客户端无需专门开发,直接使用浏览器作为客户端
  • 服务端负责处理所有业务逻辑和数据存储
  • 通信基于HTTP/HTTPS等应用层协议
  • 优点:维护成本低,跨平台性好,无需安装客户端
  • 缺点:对网络依赖性强,用户体验受浏览器限制

2. CS架构(Client/Server)

CS架构即客户端/服务器架构,其核心特点是:

  • 需要专门开发客户端应用程序
  • 服务端提供数据服务和核心业务逻辑
  • 可以使用自定义协议进行通信
  • 优点:响应速度快,用户体验好,可离线工作
  • 缺点:客户端维护成本高,跨平台性差

网络编程三要素

任何网络通信都离不开三个核心要素:IP地址、端口号和通信协议。

1. IP地址

IP地址是网络中设备的唯一标识,用于在网络中定位设备。

IP地址的分类
  • IPv4:由32位二进制数组成,采用点分十进制表示(如192.168.1.1)
  • IPv6:由128位二进制数组成,采用冒分十六进制表示(如2001:0db8:85a3:0000:0000:8a2e:0370:7334)
IP地址的类型
  • 公网IP:可以直接连接互联网的IP地址,全球唯一
  • 内网IP:仅在局域网内使用的IP地址,不同局域网可以重复
  • 回环地址:127.0.0.1(对应主机名localhost),用于本机内部通信
查看IP地址

在Windows系统中,可通过命令行执行ipconfig命令查看本机IP地址;在Linux/Mac系统中,可使用ifconfigip addr命令。

Java中的InetAddress类

Java提供了InetAddress类来操作IP地址,常用方法如下:

import java.net.InetAddress;
import java.net.UnknownHostException;public class InetAddressDemo {public static void main(String[] args) throws UnknownHostException {// 获取本地主机的IP地址对象InetAddress localHost = InetAddress.getLocalHost();System.out.println("本地主机名: " + localHost.getHostName());System.out.println("本地IP地址: " + localHost.getHostAddress());// 根据主机名获取IP地址对象InetAddress baidu = InetAddress.getByName("www.baidu.com");System.out.println("百度主机名: " + baidu.getHostName());System.out.println("百度IP地址: " + baidu.getHostAddress());// 测试IP地址是否可达try {boolean reachable = baidu.isReachable(3000); // 超时时间3秒System.out.println("百度服务器是否可达: " + (reachable ? "是" : "否"));} catch (Exception e) {e.printStackTrace();}}
}

2. 端口号

端口号是设备上应用程序的唯一标识,用于区分同一设备上的不同应用程序。

端口号的范围
  • 0-1023:系统保留端口,用于知名服务(如80端口用于HTTP,443端口用于HTTPS)
  • 1024-49151:注册端口,用于用户程序或第三方服务
  • 49152-65535:动态端口,用于临时分配
注意事项
  • 端口号必须与IP地址结合使用才能唯一标识网络中的某个应用程序
  • 同一台设备上不能有两个应用程序使用同一个端口号
  • 选择端口号时应避免使用知名端口和已被其他程序占用的端口

3. 通信协议

协议是网络通信的规则和标准,规定了数据的格式、传输方式和交互流程。Java主要支持两种传输层协议:UDP和TCP。

UDP协议(User Datagram Protocol)

UDP是一种无连接的协议,其特点如下:

  • 通信前不需要建立连接
  • 数据传输不可靠,可能丢失或乱序
  • 传输效率高,开销小
  • 适用于实时通信(如视频通话、语音聊天)

Java中使用DatagramSocketDatagramPacket类实现UDP通信:

UDP服务器端

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;public class UDPServer {public static void main(String[] args) throws Exception {// 创建DatagramSocket对象,并绑定到指定端口try (DatagramSocket socket = new DatagramSocket(8888)) {System.out.println("UDP服务器已启动,等待接收数据...");// 创建缓冲区用于接收数据byte[] buffer = new byte[1024];DatagramPacket packet = new DatagramPacket(buffer, buffer.length);// 接收数据socket.receive(packet);// 解析接收的数据String data = new String(packet.getData(), 0, packet.getLength());InetAddress clientAddress = packet.getAddress();int clientPort = packet.getPort();System.out.println("收到来自 " + clientAddress.getHostAddress() + ":" + clientPort + " 的数据: " + data);// 准备响应数据String response = "已收到你的消息: " + data;byte[] responseData = response.getBytes();// 创建发送数据包DatagramPacket responsePacket = new DatagramPacket(responseData, responseData.length, clientAddress, clientPort);// 发送响应socket.send(responsePacket);System.out.println("响应已发送");}}
}

UDP客户端

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;public class UDPClient {public static void main(String[] args) throws Exception {// 创建DatagramSocket对象try (DatagramSocket socket = new DatagramSocket()) {// 准备发送的数据String message = "Hello, UDP Server!";byte[] data = message.getBytes();// 获取服务器地址InetAddress serverAddress = InetAddress.getByName("localhost");int serverPort = 8888;// 创建发送数据包DatagramPacket packet = new DatagramPacket(data, data.length, serverAddress, serverPort);// 发送数据socket.send(packet);System.out.println("数据已发送");// 准备接收响应byte[] buffer = new byte[1024];DatagramPacket responsePacket = new DatagramPacket(buffer, buffer.length);// 接收响应socket.receive(responsePacket);// 解析响应数据String response = new String(responsePacket.getData(), 0, responsePacket.getLength());System.out.println("收到服务器响应: " + response);}}
}
TCP协议(Transmission Control Protocol)

TCP是一种面向连接的协议,其特点如下:

  • 通信前需要通过"三次握手"建立连接
  • 提供可靠的数据传输,保证数据不丢失、不重复、按序到达
  • 传输效率相对较低,开销较大
  • 适用于要求可靠传输的场景(如文件传输、邮件发送)

Java中使用SocketServerSocket类实现TCP通信:

TCP服务器端

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class TCPServer {public static void main(String[] args) throws Exception {// 创建ServerSocket对象,并绑定到指定端口try (ServerSocket serverSocket = new ServerSocket(8888)) {System.out.println("TCP服务器已启动,等待客户端连接...");// 监听并接受客户端连接try (Socket socket = serverSocket.accept()) {System.out.println("客户端已连接: " + socket.getInetAddress().getHostAddress());// 获取输入流,用于接收客户端数据try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {// 获取输出流,用于向客户端发送数据try (PrintWriter writer = new PrintWriter(socket.getOutputStream(), true)) {// 读取客户端发送的数据String message = reader.readLine();System.out.println("收到客户端消息: " + message);// 向客户端发送响应writer.println("服务器已收到消息: " + message);}}}}}
}

TCP客户端

import java.io.*;
import java.net.Socket;public class TCPClient {public static void main(String[] args) throws Exception {// 创建Socket对象,连接到服务器try (Socket socket = new Socket("localhost", 8888)) {System.out.println("已连接到服务器");// 获取输出流,用于向服务器发送数据try (PrintWriter writer = new PrintWriter(socket.getOutputStream(), true)) {// 获取输入流,用于接收服务器数据try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {// 向服务器发送数据String message = "Hello, TCP Server!";writer.println(message);System.out.println("已向服务器发送消息: " + message);// 接收服务器响应String response = reader.readLine();System.out.println("收到服务器响应: " + response);}}}}
}

TCP通信进阶

1. 实现多发多收

在实际应用中,通常需要实现客户端和服务器之间的多次数据交互:

多发多收服务器端

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class TCPMultiServer {public static void main(String[] args) throws Exception {try (ServerSocket serverSocket = new ServerSocket(8888)) {System.out.println("服务器已启动,等待连接...");try (Socket socket = serverSocket.accept()) {System.out.println("客户端已连接");BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);String message;// 使用循环实现多次接收while ((message = reader.readLine()) != null) {System.out.println("收到: " + message);// 如果客户端发送"exit",则结束通信if ("exit".equals(message)) {writer.println("再见!");break;}writer.println("已收到: " + message);}}}}
}

多发多收客户端

import java.io.*;
import java.net.Socket;
import java.util.Scanner;public class TCPMultiClient {public static void main(String[] args) throws Exception {try (Socket socket = new Socket("localhost", 8888)) {System.out.println("已连接到服务器");PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));Scanner scanner = new Scanner(System.in);String message;// 使用循环实现多次发送while (true) {System.out.print("请输入要发送的消息(输入exit退出): ");message = scanner.nextLine();writer.println(message);// 如果输入"exit",则结束通信if ("exit".equals(message)) {break;}// 接收服务器响应String response = reader.readLine();System.out.println("服务器响应: " + response);}}}
}

2. 处理多个客户端连接

单一服务器通常需要同时处理多个客户端的连接,这可以通过多线程实现:

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class MultiClientTCPServer {public static void main(String[] args) throws Exception {try (ServerSocket serverSocket = new ServerSocket(8888)) {System.out.println("服务器已启动,等待客户端连接...");int clientCount = 0;// 循环接受多个客户端连接while (true) {Socket socket = serverSocket.accept();clientCount++;System.out.println("第" + clientCount + "个客户端已连接: " + socket.getInetAddress().getHostAddress());// 为每个客户端创建一个新线程处理请求new Thread(new ClientHandler(socket, clientCount)).start();}}}// 客户端处理器,负责处理单个客户端的通信static class ClientHandler implements Runnable {private Socket socket;private int clientId;public ClientHandler(Socket socket, int clientId) {this.socket = socket;this.clientId = clientId;}@Overridepublic void run() {try (BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter writer = new PrintWriter(socket.getOutputStream(), true)) {String message;while ((message = reader.readLine()) != null) {System.out.println("客户端" + clientId + "发送: " + message);if ("exit".equals(message)) {writer.println("再见!");break;}writer.println("服务器已收到客户端" + clientId + "的消息: " + message);}System.out.println("客户端" + clientId + "已断开连接");} catch (IOException e) {e.printStackTrace();} finally {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}
}

总结

Java网络编程提供了丰富的API来实现各种网络通信需求:

  • IP地址处理:使用InetAddress类操作IP地址和主机名
  • UDP通信:适用于实时性要求高但对可靠性要求不高的场景,使用DatagramSocketDatagramPacket
  • TCP通信:适用于需要可靠传输的场景,使用SocketServerSocket
  • 高级应用:通过循环实现多发多收,通过多线程处理多个客户端连接

选择合适的通信方式和架构取决于具体的应用场景,理解各种技术的特点和适用范围是进行有效网络编程的基础。

常用方法补充

在之前的基础上,补充一些网络编程中常用的方法和技巧,灵活地处理各种网络通信场景。

InetAddress类常用方法补充

除了之前介绍的方法外,InetAddress还有一些实用方法:

import java.net.InetAddress;
import java.net.UnknownHostException;public class InetAddressMoreMethods {public static void main(String[] args) throws UnknownHostException {InetAddress address = InetAddress.getByName("www.example.com");// 检查是否是回环地址boolean isLoopback = address.isLoopbackAddress();System.out.println("是否是回环地址: " + isLoopback);// 检查是否是多播地址boolean isMulticast = address.isMulticastAddress();System.out.println("是否是多播地址: " + isMulticast);// 检查是否是链路本地地址boolean isLinkLocal = address.isLinkLocalAddress();System.out.println("是否是链路本地地址: " + isLinkLocal);// 检查是否是站点本地地址boolean isSiteLocal = address.isSiteLocalAddress();System.out.println("是否是站点本地地址: " + isSiteLocal);// 获取原始IP地址字节数组byte[] rawAddress = address.getAddress();System.out.println("原始IP地址字节数: " + rawAddress.length);}
}

Socket类常用方法补充

Socket类提供了许多方法来获取连接信息和设置连接属性:

import java.net.Socket;
import java.net.InetAddress;public class SocketMoreMethods {public static void main(String[] args) {try (Socket socket = new Socket("www.example.com", 80)) {// 获取远程服务器地址InetAddress remoteAddr = socket.getInetAddress();System.out.println("远程地址: " + remoteAddr);// 获取远程端口int remotePort = socket.getPort();System.out.println("远程端口: " + remotePort);// 获取本地地址InetAddress localAddr = socket.getLocalAddress();System.out.println("本地地址: " + localAddr);// 获取本地端口int localPort = socket.getLocalPort();System.out.println("本地端口: " + localPort);// 检查连接是否还保持着boolean isConnected = socket.isConnected();System.out.println("是否已连接: " + isConnected);// 检查连接是否已关闭boolean isClosed = socket.isClosed();System.out.println("是否已关闭: " + isClosed);// 设置SO_TIMEOUT,读取数据时的超时时间socket.setSoTimeout(5000); // 5秒System.out.println("SO_TIMEOUT: " + socket.getSoTimeout());// 设置是否启用心跳机制socket.setKeepAlive(true);System.out.println("是否启用心跳: " + socket.getKeepAlive());// 设置是否禁用Nagle算法socket.setTcpNoDelay(true);System.out.println("是否禁用Nagle算法: " + socket.getTcpNoDelay());} catch (Exception e) {e.printStackTrace();}}
}

ServerSocket类常用方法补充

ServerSocket类也提供了一些实用方法:

import java.net.ServerSocket;
import java.net.InetAddress;public class ServerSocketMoreMethods {public static void main(String[] args) {try (ServerSocket serverSocket = new ServerSocket(8888)) {// 获取服务器绑定的地址InetAddress inetAddress = serverSocket.getInetAddress();System.out.println("绑定地址: " + inetAddress);// 获取服务器监听的端口int port = serverSocket.getLocalPort();System.out.println("监听端口: " + port);// 设置积压队列大小serverSocket.setBacklog(50);// 检查服务器是否已关闭boolean isClosed = serverSocket.isClosed();System.out.println("是否已关闭: " + isClosed);// 获取服务器的接收缓冲区大小int receiveBufferSize = serverSocket.getReceiveBufferSize();System.out.println("接收缓冲区大小: " + receiveBufferSize);// 设置服务器的接收缓冲区大小serverSocket.setReceiveBufferSize(8192);} catch (Exception e) {e.printStackTrace();}}
}

DatagramSocket常用方法补充

对于UDP通信,DatagramSocket有这些常用方法:

import java.net.DatagramSocket;
import java.net.InetAddress;public class DatagramSocketMoreMethods {public static void main(String[] args) {try (DatagramSocket socket = new DatagramSocket(8888)) {// 获取本地地址InetAddress localAddr = socket.getLocalAddress();System.out.println("本地地址: " + localAddr);// 获取本地端口int localPort = socket.getLocalPort();System.out.println("本地端口: " + localPort);// 设置超时时间socket.setSoTimeout(3000);System.out.println("超时时间: " + socket.getSoTimeout());// 设置是否广播socket.setBroadcast(true);System.out.println("是否允许广播: " + socket.getBroadcast());// 获取接收缓冲区大小int bufferSize = socket.getReceiveBufferSize();System.out.println("接收缓冲区大小: " + bufferSize);// 设置接收缓冲区大小socket.setReceiveBufferSize(8192);} catch (Exception e) {e.printStackTrace();}}
}

网络连接工具类

下面是一个实用的网络工具类,封装了一些常用的网络操作:

import java.net.*;
import java.io.*;public class NetworkUtils {/*** 检查主机是否可达* @param host 主机名或IP地址* @param timeout 超时时间(毫秒)* @return 是否可达*/public static boolean isHostReachable(String host, int timeout) {try {return InetAddress.getByName(host).isReachable(timeout);} catch (Exception e) {return false;}}/*** 检查端口是否开放* @param host 主机名或IP地址* @param port 端口号* @param timeout 超时时间(毫秒)* @return 端口是否开放*/public static boolean isPortOpen(String host, int port, int timeout) {try (Socket socket = new Socket()) {socket.connect(new InetSocketAddress(host, port), timeout);return true;} catch (Exception e) {return false;}}/*** 获取本机所有IP地址*/public static void printAllLocalIPs() {try {Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();while (interfaces.hasMoreElements()) {NetworkInterface iface = interfaces.nextElement();// 过滤回环接口和未启用的接口if (iface.isLoopback() || !iface.isUp()) continue;Enumeration<InetAddress> addresses = iface.getInetAddresses();while (addresses.hasMoreElements()) {InetAddress addr = addresses.nextElement();System.out.println("IP地址: " + addr.getHostAddress() + ", 接口: " + iface.getDisplayName());}}} catch (SocketException e) {throw new RuntimeException(e);}}/*** 简单的HTTP GET请求*/public static String httpGet(String urlString) throws Exception {URL url = new URL(urlString);try (BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()))) {StringBuilder result = new StringBuilder();String line;while ((line = reader.readLine()) != null) {result.append(line);}return result.toString();}}
}

使用示例

public class NetworkUtilsDemo {public static void main(String[] args) {// 检查主机是否可达boolean reachable = NetworkUtils.isHostReachable("www.baidu.com", 3000);System.out.println("百度服务器是否可达: " + reachable);// 检查端口是否开放boolean portOpen = NetworkUtils.isPortOpen("www.baidu.com", 80, 3000);System.out.println("百度服务器80端口是否开放: " + portOpen);// 打印本机所有IP地址System.out.println("\n本机IP地址:");NetworkUtils.printAllLocalIPs();// 简单的HTTP GET请求示例try {System.out.println("\n获取百度首页内容长度: " + NetworkUtils.httpGet("https://www.baidu.com").length());} catch (Exception e) {e.printStackTrace();}}
}

这些常用方法和工具类可以帮助你更高效地进行Java网络编程,处理各种常见的网络操作场景。在实际开发中,根据具体需求选择合适的方法,并注意异常处理和资源释放。

http://www.dtcms.com/a/392965.html

相关文章:

  • 面试MYSQL的索引类型、索引的工作原理、以及索引优化策略
  • 一、Pytorch安装教程-windows环境,利用Anaconda搭建虚拟环境,Pycharm开发工具
  • JWT登录校验
  • 对症下药:电商、B2B、本地服务和内容媒体的GEO定制化策略
  • 分类预测 | Matlab实现GWO-BP灰狼算法优化BP神经网络多特征分类预测
  • pcl封装11 (快速定义)旋转矩阵
  • Windows 系统中如何通过 Docker 调用 CUDA 和 cuDNN 加速大模型推理
  • 从零编写vue3系统--5步教学
  • 嵌入式Linux C语言程序设计三
  • 【记录】初赛复习 Day5 6(2021S第一轮错题,内附深井题目讲解)
  • 【C++】类和对象—(下) 收官之战
  • 人工智能学习:什么是迁移学习
  • 模型进阶与神经网络
  • 微软.NET离线运行库合集 v2025.09.09_Win中文_NET运行库_安装教程
  • Galileo AI-AI驱动的UI界面设计工具
  • 布谷鸟布隆过滤器和计数式布隆过滤器和原始布隆过滤器相比分别解决了什么问题?
  • 大模型介绍
  • 基于Springboot的无人之境智能酒店服务平台
  • ICCV-2025 | 大模型驱动的认知导航框架!CogNav:面向目标导航的大型语言模型驱动的认知过程建模
  • java-异常
  • 网络编程:一个 TCP 服务器的简易实现(epoll 版本)
  • 【MySQL学习】关于MySql语句执行、查询、更新流程原理总结
  • C++语法深度剖析与面试核心详解
  • 【Tomcat】基础总结:类加载机制
  • 127、【OS】【Nuttx】【周边】效果呈现方案解析:比较浮点数(上)
  • 计网协议簇具体协议
  • 电路分析基础笔记
  • 【JVM 常用工具命令大全】
  • 从iload_1 iload_2 iadd字节码角度看jvm字节码执行
  • openssl 启用AES NI加速对AES加密性能影响的测试