Socket 编程是网络通信的核心,下面阐述TCP 协议下服务端和客户端的编程步骤。
服务端:
服务端的任务是等待并处理客户端的连接请求。其核心是使用 ServerSocket 类。
步骤详解:
- 创建 ServerSocket
- 在指定的端口上监听客户端的连接请求。
- ServerSocket serverSocket = new ServerSocket(port); (例如端口号:8888)
- 等待客户端连接 (阻塞)
- 调用 accept() 方法。该方法会一直阻塞,直到有客户端连接上来。
- 一旦有客户端连接成功,accept() 方法会返回一个 Socket 对象。这个 Socket 对象就是与这个特定客户端通信的通道。
- Socket clientSocket = serverSocket.accept();
- 获取输入输出流
- 通过步骤2得到的 clientSocket 来获取输入流和输出流。
- 输入流 (InputStream):用于读取从客户端发送过来的数据。
- 输出流 (OutputStream):用于向客户端发送数据。
- 通常我们会将它们包装成更方便操作的字符流或数据流。
InputStream is = clientSocket.getInputStream();
OutputStream os = clientSocket.getOutputStream();
// 常用包装流
BufferedReader in = new BufferedReader(new InputStreamReader(is));
PrintWriter out = new PrintWriter(new OutputStreamWriter(os));
- 通信 (读写数据)
- 使用获取到的流,与客户端进行数据的读写交互。
- 读取客户端数据:String clientMessage = in.readLine();
- 向客户端发送数据:out.println(“Hello, Client!”); out.flush(); (flush() 很重要!)
- 关闭资源 (非常重要!)
- 通信结束后,按顺序关闭所有打开的流和 Socket。
- 顺序:后开的先关。
- in.close(); -> out.close(); -> clientSocket.close(); -> serverSocket.close();
- 通常会在 finally 块或使用 try-with-resources 语句来确保资源被关闭。
客户端:
客户端的任务是主动向服务端发起连接请求。其核心是使用 Socket 类。
步骤详解:
- 创建 Socket 并连接服务器
- 指定服务端的 IP 地址(或主机名) 和 端口号,直接创建 Socket 对象。创建过程就是发起连接的过程。
- Socket socket = new Socket(serverIp, port); (例如:“127.0.0.1” 或 “localhost” 表示本机,端口号必须与服务端一致)
- 获取输入输出流
- 与服务端第3步类似,通过 socket 对象获取流。
- 注意方向:
- 输出流 (OutputStream):用于向服务端发送数据。
- 输入流 (InputStream):用于读取从服务端返回的数据。
OutputStream os = socket.getOutputStream(); // 用来发
InputStream is = socket.getInputStream(); // 用来收
// 同样进行包装
PrintWriter out = new PrintWriter(new OutputStreamWriter(os));
BufferedReader in = new BufferedReader(new InputStreamReader(is));
- 通信 (读写数据)
- 使用流与服务端进行交互。
- 向服务端发送数据:out.println(“Hello, Server!”); out.flush();
- 读取服务端返回的数据:String serverResponse = in.readLine();
- 关闭资源
- 同样,按顺序关闭所有资源。
- out.close(); -> in.close(); -> socket.close();
代码示例 (Java)
服务端代码
// Server.java
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] args) {
int port = 8888;
// 使用 try-with-resources 自动关闭资源
try (ServerSocket serverSocket = new ServerSocket(port)) {
System.out.println("服务器启动,等待客户端连接...");
// 等待一个客户端连接
Socket clientSocket = serverSocket.accept();
System.out.println("客户端已连接: " + clientSocket.getInetAddress());
// 获取流
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true); // autoFlush
// 读取客户端消息
String clientMessage = in.readLine();
System.out.println("收到客户端消息: " + clientMessage);
// 向客户端发送响应
out.println("你好,客户端!我已收到你的消息:'" + clientMessage + "'");
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端代码
// Client.java
import java.io.*;
import java.net.*;
public class Client {
public static void main(String[] args) {
String hostname = "localhost";
int port = 8888;
try (Socket socket = new Socket(hostname, port)) {
System.out.println("已连接到服务器...");
// 获取流
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 向服务器发送消息
out.println("Hello, Server!");
// 读取服务器响应
String serverResponse = in.readLine();
System.out.println("服务器响应: " + serverResponse);
} catch (UnknownHostException e) {
System.err.println("无法找到主机: " + hostname);
} catch (IOException e) {
System.err.println("I/O 错误: " + e.getMessage());
}
}
}
执行流程
- 先启动 Server,它会阻塞在 accept() 方法等待。
- 再启动 Client,它会连接服务器。
- 服务端 accept() 返回,建立连接。
- 客户端发送消息 “Hello, Server!” 给服务端。
- 服务端收到消息并打印,然后发送一个响应回客户端。
- 客户端收到响应并打印。
- 两者关闭连接。
三次握手
TCP的三次握手是TCP连接建立的过程,其核心目的是双方确认彼此的发送和接收能力正常,并同步初始序列号(Sequence Number, SN),为可靠传输做准备。
整个过程由客户端主动发起,下图清晰地展示了从发起请求到建立连接的完整流程:

- 第一次握手 (SYN):Client 发送连接请求。证明了Client的发送能力正常。
- 第二次握手 (SYN+ACK):Server 收到请求并回复确认。这一步同时证明了:1. Server的接收能力正常;2. Server的发送能力正常。
- 第三次握手 (ACK):Client 收到Server的回复后,再次发送确认。这一步证明了:Client的接收能力正常。
此时,Server收到第三次握手后,才能最终确认Client的接收能力是正常的。
四次挥手
四次挥手是TCP连接正常、优雅断开的过程。其核心目的是双方确认彼此都没有数据需要发送了,然后安全地关闭连接。
整个过程由一端(通常是客户端,但服务器也可以主动发起)先发起断开请求,下图清晰地展示了从发起断开到完全关闭的完整流程:

因为TCP连接是全双工的,即数据在两个方向上可以同时独立传输。因此,每个方向都必须单独进行关闭。
- 第一次挥手:关闭A到B的数据通道。(A说:“我这边没数据发给你了。”)
- 第二次挥手:B确认收到A的关闭请求。(B说:“好的,我知道你不发了。”)此时,A到B的方向连接关闭,但B到A的方向仍然可以继续发送数据。
- 第三次挥手:B也处理完所有数据,准备关闭。(B说:“我这边也没数据发给你了。”)
- 第四次挥手:A确认收到B的关闭请求。(A说:“好的,我知道你也不发了。”)至此,连接安全关闭。
746

被折叠的 条评论
为什么被折叠?



