第一部分:网络基础概念

理解IP地址、端口和协议的基本概念及其在Java网络编程中的应用

学习目标

掌握IP地址分类、端口作用、常见网络协议以及InetAddress类的使用

IP地址

  • IPv4地址:32位,点分十进制表示(如192.168.1.1)
  • IPv6地址:128位,冒号分隔十六进制表示
  • 特殊地址:127.0.0.1(本地回环地址)
  • Java中的表示:InetAddress

端口(Port)

  • 范围:0-65535(16位无符号整数)
  • 知名端口:0-1023(如HTTP:80, HTTPS:443)
  • 注册端口:1024-49151
  • 动态端口:49152-65535

网络协议

  • TCP:面向连接、可靠传输
  • UDP:无连接、不可靠但高效
  • HTTP:应用层协议,基于TCP
  • 其他:FTP、SMTP、DNS等
1

InetAddress类使用

Java中表示IP地址的核心类:

import java.net.InetAddress; import java.net.UnknownHostException; public class InetAddressExample { public static void main(String[] args) { try { // 获取本地主机地址 InetAddress localHost = InetAddress.getLocalHost(); System.out.println("Local Host: " + localHost); // 通过主机名获取IP InetAddress googleAddr = InetAddress.getByName("www.google.com"); System.out.println("Google IP: " + googleAddr.getHostAddress()); // 获取所有IP地址 InetAddress[] allGoogleIps = InetAddress.getAllByName("www.google.com"); for (InetAddress ip : allGoogleIps) { System.out.println("Google IP: " + ip.getHostAddress()); } } catch (UnknownHostException e) { e.printStackTrace(); } } }

常见错误

  • 未处理UnknownHostException异常
  • 混淆getHostName()和getHostAddress()方法
  • 在防火墙阻止的环境下无法解析外部主机

学习小贴士

使用InetAddress.getByName()方法时,如果传入的是IP地址字符串(如"192.168.1.1"),不会进行DNS查询,直接返回对应的InetAddress对象;如果传入主机名,则会进行DNS查询。

第二部分:TCP通信

使用Socket和ServerSocket实现可靠的TCP网络通信

学习目标

掌握TCP服务器和客户端的创建、通信流程及异常处理

1

TCP服务器实现

使用ServerSocket创建TCP服务器:

import java.io.*; import java.net.*; public class TCPServer { public static void main(String[] args) { final int PORT = 8888; try (ServerSocket serverSocket = new ServerSocket(PORT)) { System.out.println("TCP Server started on port " + PORT); while (true) { // 等待客户端连接 Socket clientSocket = serverSocket.accept(); System.out.println("Client connected: " + clientSocket.getInetAddress().getHostAddress()); // 获取输入输出流 BufferedReader in = new BufferedReader( new InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter( clientSocket.getOutputStream(), true); // 读取客户端消息 String message = in.readLine(); System.out.println("Received: " + message); // 发送响应 out.println("Echo: " + message); // 关闭连接 clientSocket.close(); } } catch (IOException e) { e.printStackTrace(); } } }
2

TCP客户端实现

使用Socket连接TCP服务器:

import java.io.*; import java.net.*; public class TCPClient { public static void main(String[] args) { final String SERVER_IP = "localhost"; final int PORT = 8888; try (Socket socket = new Socket(SERVER_IP, PORT)) { // 获取输入输出流 PrintWriter out = new PrintWriter( socket.getOutputStream(), true); BufferedReader in = new BufferedReader( new InputStreamReader(socket.getInputStream())); // 发送消息 out.println("Hello TCP Server!"); // 读取响应 String response = in.readLine(); System.out.println("Server response: " + response); } catch (IOException e) { e.printStackTrace(); } } }

TCP通信特点

  • 面向连接(三次握手)
  • 可靠传输(确认、重传机制)
  • 有序的数据传输
  • 流量控制和拥塞控制
  • 适合需要可靠性的场景(文件传输、Web等)

常见错误

  • 未关闭Socket导致资源泄漏
  • 未处理SocketTimeoutException
  • 未正确设置流编码导致乱码
  • 在循环中未创建新Socket处理多个客户端

学习小贴士

使用setSoTimeout(int timeout)方法可以设置Socket操作的超时时间(毫秒),避免网络问题导致的永久阻塞。

第三部分:UDP通信

使用DatagramSocket和DatagramPacket实现高效的UDP通信

学习目标

掌握UDP数据报的发送与接收,理解无连接通信的特点

1

UDP服务器实现

接收UDP数据报:

import java.net.*; public class UDPServer { public static void main(String[] args) { final int PORT = 9999; try (DatagramSocket socket = new DatagramSocket(PORT)) { System.out.println("UDP Server started on port " + PORT); byte[] buffer = new byte[1024]; while (true) { // 准备接收数据包 DatagramPacket packet = new DatagramPacket(buffer, buffer.length); // 接收数据 socket.receive(packet); // 解析数据 String message = new String(packet.getData(), 0, packet.getLength()); System.out.println("Received from " + packet.getAddress() + ": " + message); // 准备响应数据 String response = "UDP Response: " + message; byte[] responseData = response.getBytes(); // 发送响应 DatagramPacket responsePacket = new DatagramPacket( responseData, responseData.length, packet.getAddress(), packet.getPort()); socket.send(responsePacket); } } catch (IOException e) { e.printStackTrace(); } } }
2

UDP客户端实现

发送UDP数据报:

import java.net.*; public class UDPClient { public static void main(String[] args) { final String SERVER_IP = "localhost"; final int PORT = 9999; try (DatagramSocket socket = new DatagramSocket()) { // 准备发送数据 String message = "Hello UDP Server!"; byte[] sendData = message.getBytes(); // 创建发送包 InetAddress serverAddress = InetAddress.getByName(SERVER_IP); DatagramPacket sendPacket = new DatagramPacket( sendData, sendData.length, serverAddress, PORT); // 发送数据 socket.send(sendPacket); System.out.println("Sent: " + message); // 准备接收响应 byte[] receiveData = new byte[1024]; DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); // 设置超时时间(2秒) socket.setSoTimeout(2000); // 接收响应 socket.receive(receivePacket); String response = new String(receivePacket.getData(), 0, receivePacket.getLength()); System.out.println("Server response: " + response); } catch (IOException e) { e.printStackTrace(); } } }

UDP通信特点

  • 无连接,无需建立连接
  • 不可靠传输(可能丢失、乱序)
  • 开销小,传输效率高
  • 支持广播和多播
  • 适合实时性要求高的场景(视频、游戏)

常见错误

  • 未设置合理的DatagramPacket长度
  • 未处理SocketTimeoutException
  • 在接收数据后未正确截取有效数据长度
  • 未考虑MTU限制导致数据包过大

学习小贴士

UDP数据包的最大理论长度是65535字节,但实际受网络MTU(通常1500字节)限制,建议将数据包控制在1472字节以内(1500-20IP头-8UDP头)。

第四部分:HTTP协议与URL类

理解HTTP协议基础,使用URL类处理HTTP请求

学习目标

掌握HTTP请求/响应结构,使用URLConnection发送HTTP请求

HTTP请求

  • 请求方法:GET、POST、PUT、DELETE等
  • 请求头:User-Agent、Content-Type等
  • 请求体:POST/PUT请求携带的数据

HTTP响应

  • 状态码:200 OK、404 Not Found等
  • 响应头:Content-Type、Content-Length等
  • 响应体:实际返回的数据

URL类

  • 创建URL对象:new URL("https://example.com")
  • 获取协议、主机、端口、路径等信息
  • 打开连接:url.openConnection()
1

发送HTTP GET请求

使用HttpURLConnection发送GET请求:

import java.io.*; import java.net.*; public class HttpGetExample { public static void main(String[] args) { try { URL url = new URL("https://jsonplaceholder.typicode.com/posts/1"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 设置请求方法 conn.setRequestMethod("GET"); // 设置请求头 conn.setRequestProperty("User-Agent", "Java HTTP Client"); // 获取响应码 int responseCode = conn.getResponseCode(); System.out.println("Response Code: " + responseCode); // 读取响应内容 if (responseCode == HttpURLConnection.HTTP_OK) { BufferedReader in = new BufferedReader( new InputStreamReader(conn.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); System.out.println("Response: " + response.toString()); } else { System.out.println("GET request failed"); } } catch (IOException e) { e.printStackTrace(); } } }

常见错误

  • 未处理MalformedURLException
  • 未设置超时导致请求永久阻塞
  • 未正确处理HTTP重定向(3xx状态码)
  • 未设置User-Agent等必要请求头

学习小贴士

对于复杂的HTTP请求(如需要处理Cookie、重定向等),建议使用更高级的HTTP客户端库,如Apache HttpClient或OkHttp。

第五部分:NIO基础

使用Buffer和Channel实现非阻塞I/O操作

学习目标

掌握Buffer的核心概念和操作,使用Channel进行文件I/O

Buffer核心属性

  • capacity:缓冲区容量(固定)
  • position:当前位置(下一个读写位置)
  • limit:可读写数据的上限
  • mark:标记位置(用于reset)

Buffer操作流程

  • 写入数据到Buffer(position移动)
  • 调用flip()切换为读模式
  • 从Buffer读取数据(position移动)
  • 调用clear()或compact()清空缓冲区

Channel类型

  • FileChannel:文件读写
  • SocketChannel:TCP网络通信
  • ServerSocketChannel:TCP服务器
  • DatagramChannel:UDP网络通信
1

文件复制示例

使用FileChannel复制文件:

import java.io.*; import java.nio.*; import java.nio.channels.FileChannel; public class FileCopyExample { public static void main(String[] args) { String sourceFile = "source.txt"; String destFile = "destination.txt"; try (FileInputStream fis = new FileInputStream(sourceFile); FileOutputStream fos = new FileOutputStream(destFile); FileChannel sourceChannel = fis.getChannel(); FileChannel destChannel = fos.getChannel()) { // 创建缓冲区 ByteBuffer buffer = ByteBuffer.allocate(1024); while (sourceChannel.read(buffer) != -1) { // 切换为读模式 buffer.flip(); // 写入到目标通道 destChannel.write(buffer); // 清空缓冲区(为下一次读取准备) buffer.clear(); } System.out.println("File copied successfully!"); } catch (IOException e) { e.printStackTrace(); } } }

常见错误

  • 忘记调用flip()切换Buffer模式
  • 未正确处理Buffer的limit和position
  • 在循环中未清除缓冲区导致无限循环
  • 未关闭Channel导致资源泄漏

学习小贴士

使用FileChannel的transferTo()或transferFrom()方法可以实现高效的文件传输(零拷贝),特别适合大文件传输场景。

第六部分:多线程服务器开发

使用多线程技术实现高并发服务器

学习目标

掌握线程池管理客户端连接,实现高性能服务器

1

多线程TCP服务器

使用线程池处理客户端连接:

import java.io.*; import java.net.*; import java.util.concurrent.*; public class MultiThreadedServer { private static final int PORT = 8888; private static final int THREAD_POOL_SIZE = 10; public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(THREAD_POOL_SIZE); try (ServerSocket serverSocket = new ServerSocket(PORT)) { System.out.println("Multi-threaded server started on port " + PORT); while (true) { Socket clientSocket = serverSocket.accept(); System.out.println("New client connected: " + clientSocket.getInetAddress().getHostAddress()); // 为每个客户端连接创建任务 executor.execute(new ClientHandler(clientSocket)); } } catch (IOException e) { e.printStackTrace(); } finally { executor.shutdown(); } } static class ClientHandler implements Runnable { private final Socket clientSocket; public ClientHandler(Socket socket) { this.clientSocket = socket; } @Override public void run() { try (BufferedReader in = new BufferedReader( new InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter( clientSocket.getOutputStream(), true)) { String inputLine; while ((inputLine = in.readLine()) != null) { System.out.println("[" + Thread.currentThread().getName() + "] Received: " + inputLine); // 处理请求并返回响应 String response = "Processed: " + inputLine; out.println(response); } } catch (IOException e) { System.out.println("Error handling client: " + e.getMessage()); } finally { try { clientSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }

常见错误

  • 线程池大小设置不合理(过小或过大)
  • 未正确关闭客户端Socket
  • 共享资源未同步导致线程安全问题
  • 未处理线程中的异常

学习小贴士

对于高并发场景,考虑使用NIO(Selector)实现非阻塞I/O,结合线程池处理,可以大幅提升服务器的并发处理能力。

综合复习测试

检验你对Java网络基础知识的掌握程度

问题1:TCP和UDP的主要区别是什么?

A. TCP是面向连接的,UDP是无连接的
B. TCP保证数据可靠传输,UDP不保证
C. TCP传输速度慢,UDP传输速度快
D. 以上都是

正确答案:D

TCP是面向连接的可靠传输协议,保证数据顺序和完整性,但开销较大;UDP是无连接的不可靠协议,不保证数据送达,但传输效率高。

问题2:在Java中,哪个类用于表示IP地址?

A. IPAddress
B. SocketAddress
C. InetAddress
D. NetworkInterface

正确答案:C

InetAddress类表示IP地址(包括IPv4和IPv6),提供了获取主机名、解析IP等方法。

问题3:使用ServerSocket创建TCP服务器时,哪个方法用于监听客户端连接?

A. listen()
B. connect()
C. accept()
D. receive()

正确答案:C

accept()方法监听客户端连接请求,并在连接建立后返回一个新的Socket对象用于与客户端通信。

问题4:在NIO中,Buffer的哪个方法用于切换为读模式?

A. read()
B. flip()
C. rewind()
D. clear()

正确答案:B

flip()方法将Buffer从写模式切换到读模式,将limit设置为当前位置,position设置为0。