大话计算机网络(上)
一、TCP和UDP的区别:
1. 连接方式
- TCP(Transmission Control Protocol,传输控制协议)
面向连接,传输前必须先建立连接(三次握手),通信结束后要断开连接(四次挥手)。 - UDP(User Datagram Protocol,用户数据报协议)
无连接,直接发数据,不需要建立或断开连接。
2. 可靠性
-
TCP
- 提供可靠传输:有确认机制、重传机制、流量控制、拥塞控制。
- 能保证数据 不丢失、不重复、按顺序到达。
-
UDP
- 不保证可靠性:没有确认和重传机制。
- 可能丢包、乱序。
3. 传输效率
-
TCP
- 开销大(需要建立连接、维护状态、做校验、重传等)。
- 传输效率相对较低。
-
UDP
- 头部开销小(8 字节,对比 TCP 的 20 字节起步)。
- 传输效率高,延迟低。
4. 应用场景
-
TCP 适合可靠传输场景
如:HTTP/HTTPS、FTP、SMTP、数据库连接。
(需要保证数据完整性和顺序性) -
UDP 适合实时场景
如:视频直播、语音通话、在线游戏、DNS 查询。
(容忍少量丢包,但需要低延迟)
一句话:
- TCP = 慢但可靠(适合“文件传输”类)
- UDP = 快但不可靠(适合“实时传输”类)
实例代码:
TCP:
TCP服务端:
import java.io.*;
import java.net.*;public class TcpServer {public static void main(String[] args) throws IOException {ServerSocket serverSocket = new ServerSocket(6666); // 监听端口System.out.println("TCP 服务端启动,等待连接...");Socket socket = serverSocket.accept(); // 阻塞等待客户端连接System.out.println("客户端已连接: " + socket.getInetAddress());BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter out = new PrintWriter(socket.getOutputStream(), true);String msg = in.readLine();System.out.println("收到客户端消息: " + msg);out.println("服务端回复: 已收到 -> " + msg);socket.close();serverSocket.close();}
}
TCP客户端:
import java.io.*;
import java.net.*;public class TcpClient {public static void main(String[] args) throws IOException {Socket socket = new Socket("localhost", 6666); // 连接服务端PrintWriter out = new PrintWriter(socket.getOutputStream(), true);BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));out.println("Hello TCP!"); // 发送消息String reply = in.readLine(); // 接收回复System.out.println("收到服务端回复: " + reply);socket.close();}
}
运行效果:
1、先启动TcpServer,它会阻塞等待连接
2、再运行TcpServer,服务端会打印受到的消息,并回复客户端
UDP示例
UDP服务端:
import java.net.*;public class UdpServer {public static void main(String[] args) throws Exception {DatagramSocket socket = new DatagramSocket(8888); // 监听端口byte[] buf = new byte[1024];System.out.println("UDP 服务端启动,等待数据...");DatagramPacket packet = new DatagramPacket(buf, buf.length);socket.receive(packet); // 阻塞等待数据String msg = new String(packet.getData(), 0, packet.getLength());System.out.println("收到客户端消息: " + msg);// 回复消息String reply = "服务端收到 -> " + msg;byte[] data = reply.getBytes();DatagramPacket replyPacket = new DatagramPacket(data, data.length, packet.getAddress(), packet.getPort());socket.send(replyPacket);socket.close();}
}
UDP客户端:
import java.net.*;public class UdpClient {public static void main(String[] args) throws Exception {DatagramSocket socket = new DatagramSocket();String msg = "Hello UDP!";byte[] data = msg.getBytes();InetAddress address = InetAddress.getByName("localhost");DatagramPacket packet = new DatagramPacket(data, data.length, address, 8888);socket.send(packet); // 发送消息// 接收服务端回复byte[] buf = new byte[1024];DatagramPacket replyPacket = new DatagramPacket(buf, buf.length);socket.receive(replyPacket);String reply = new String(replyPacket.getData(), 0, replyPacket.getLength());System.out.println("收到服务端回复: " + reply);socket.close();}
}
二、TCP三次握手
1. 为什么需要三次握手?
TCP 是面向连接的、可靠的协议,建立连接前要确保 双方都具备收发能力。
- 一次握手:只能确认 客户端 → 服务端 的发送没问题。
- 两次握手:只能确认 双向传输通路,但不能防止 旧连接请求 造成混乱。
- 三次握手:既能确认收发能力,也能避免历史报文影响,最终保证连接可靠。
2. 三次握手过程
假设:客户端 (Client),服务端 (Server)。
第一次握手
- Client → Server
- Client 发送
SYN = 1
,选择一个初始序列号Seq = x
。 - 表示:“我要建立连接,这是我的起始序号。”
第二次握手
- Server → Client
- Server 收到请求后,回复
SYN = 1, ACK = 1
,确认号Ack = x + 1
,并生成自己的初始序列号Seq = y
。 - 表示:“我收到了你的请求,也要建立连接,这是我的起始序号。”
第三次握手
- Client → Server
- Client 收到回复后,再发
ACK = 1
,确认号Ack = y + 1
,序号Seq = x + 1
。 - 表示:“我确认收到你的序号,连接可以正式建立。”
此时,双方连接建立成功,进入 ESTABLISHED 状态,可以开始传输数据。
- 三次握手保证了 双方序列号的同步。
- 避免了 历史连接请求报文 导致的错误连接。
- 握手完成后,通信双方进入 全双工通信(可以同时收发)。
一句话总结:
TCP 三次握手是 确保客户端和服务端都有收发能力、并且序列号同步的过程,是可靠传输的前提。