本部分计算机网络笔记用于学习和应用。

TCP和UDP的区别

特性 TCP (传输控制协议) UDP (用户数据报协议)
连接方式 面向连接 无连接
可靠性 提供可靠的数据传输,保证数据完整性 不保证数据的可靠性
流量控制 支持流量控制和拥塞控制 不支持流量控制
数据顺序 保证数据的顺序 不保证数据的顺序
速度 较慢,由于需要建立连接和确认 较快,没有建立连接的延迟
适用场景 适合需要可靠传输的应用,如网页、文件传输 适合实时应用,如视频会议、在线游戏
  • TCP数据包的结构

    • 头部:通常为20字节,包含以下字段:

      • 源端口(16位):发送端的端口号。
      • 目的端口(16位):接收端的端口号。
      • 序列号(32位):用于数据重组和控制。
      • 确认号(32位):期望收到的下一个字节的序列号。
      • 数据偏移(4位):头部长度。
      • 保留位(6位):保留用于未来使用。
      • 控制位(6位):包括URG、ACK、PSH、RST、SYN、FIN等,用于控制连接。
      • 窗口大小(16位):流量控制中的窗口大小。
      • 校验和(16位):用于检测传输中的错误。
      • 紧急指针(16位):指示紧急数据的偏移量(如果URG标志设置)。
      • 选项:可选字段,长度可变。

      数据部分:包含实际传输的数据。

  • UDP数据包结构

    • 头部: 固定为8字节,包含以下字段:
      • 源端口(16位):发送端的端口号。
      • 目的端口(16位):接收端的端口号。
      • 长度(16位):UDP头部和数据部分的总长度。
      • 校验和(16位):用于检测传输中的错误。
    • 数据部分:包含实际传输的数据。

TCP的三次握手和四次挥手机制

一、TCP 三次握手(连接建立)

三次握手的目的是为了保证客户端和服务器双方都确认对方收到了自己的请求,成功建立可靠的连接。过程如下:

  1. 第一次握手

    • 客户端向服务器发送一个 SYN(同步)报文,表示要建立连接。此时客户端进入 SYN_SENT 状态。
  2. 第二次握手

    • 服务器收到客户端的 SYN 报文后,确认收到,回复一个 SYN-ACK 报文,表示同意建立连接并确认 SYN。此时服务器进入 SYN_RCVD 状态。
  3. 第三次握手

    • 客户端收到服务器的 SYN-ACK 报文后,发送一个 ACK(确认)报文,确认服务器的响应。此时,客户端进入 ESTABLISHED(连接已建立)状态,服务器收到 ACK 后也进入 ESTABLISHED 状态。

这三次握手的主要目的是确认双方的发送、接收能力和初始化序列号的同步。

二、TCP 四次挥手(连接关闭)

四次挥手的目的是保证双方都确认连接已经正常关闭。其步骤如下:

  1. 第一次挥手

    • 当客户端想要关闭连接时,发送一个 FIN(结束)报文,表示不再发送数据。此时客户端进入 FIN_WAIT_1 状态。
  2. 第二次挥手

    • 服务器收到 FIN 报文后,确认收到,回复一个 ACK 报文。此时服务器进入 CLOSE_WAIT 状态,客户端收到 ACK 后进入 FIN_WAIT_2 状态。
  3. 第三次挥手

    • 服务器在确认客户端不再发送数据后,也发送一个 FIN 报文,表示自己也不再发送数据。此时服务器进入 LAST_ACK 状态。
  4. 第四次挥手

    • 客户端收到服务器的 FIN 报文后,发送 ACK 报文确认。此时客户端进入 TIME_WAIT 状态,等待一段时间(通常为 2 倍的报文最大生存时间,即 2MSL)以确保服务器接收到了 ACK,之后客户端进入 CLOSED 状态,连接关闭。

服务器收到 ACK 后,也进入 CLOSED 状态,至此连接完全关闭。

使用TCP/IP协议进行通信(基于python)

服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import socket

# 创建TCP服务器的socket对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定IP地址和端口号
server_socket.bind(('localhost', 12345))

# 开始监听
server_socket.listen(5)
print("TCP服务器启动,等待客户端连接...")

# 等待客户端连接
client_socket, addr = server_socket.accept()
print(f"连接建立,客户端地址: {addr}")

# 接收数据
data = client_socket.recv(1024)
print(f"收到的数据: {data.decode()}")

# 发送响应
client_socket.send("你好,客户端!".encode())

# 关闭连接
client_socket.close()
server_socket.close()

TCP客户端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import socket

# 创建TCP客户端的socket对象
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接服务器
client_socket.connect(('localhost', 12345))

# 发送数据
client_socket.send("你好,服务器!".encode())

# 接收服务器的响应
data = client_socket.recv(1024)
print(f"从服务器收到的响应: {data.decode()}")

# 关闭连接
client_socket.close()

使用TCP/IP协议进行网络聊天(基于python)

服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import socket
import threading

clients = []
usernames = []

def handle_client(client_socket):
while True:
try:
# 接收客户端发送的数据
message = client_socket.recv(1024)
if message:
broadcast(message, client_socket)
else:
remove_client(client_socket)
break
except:
continue

def broadcast(message, client_socket):
for client in clients:
if client != client_socket:
try:
client.send(message)
except:
remove_client(client)

def remove_client(client_socket):
index = clients.index(client_socket)
clients.remove(client_socket)
username = usernames[index]
usernames.remove(username)
broadcast(f"{username} 退出了聊天!".encode(), client_socket) # 传递 client_socket

def start_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 12345))
server_socket.listen(5)
print("聊天服务器启动,等待连接...")

while True:
client_socket, addr = server_socket.accept()
print(f"客户端 {addr} 连接。")

# 让客户端输入用户名
client_socket.send("请输入用户名:".encode())
username = client_socket.recv(1024).decode()
usernames.append(username)
clients.append(client_socket)
broadcast(f"{username} 加入了聊天!".encode(), client_socket) # 传递 client_socket

thread = threading.Thread(target=handle_client, args=(client_socket,))
thread.start()

if __name__ == "__main__":
start_server()

TCP客户端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import socket
import threading

def receive_messages(client_socket):
while True:
try:
message = client_socket.recv(1024)
if message:
print(message.decode())
else:
break
except:
print("连接到服务器失败。")
break

def start_client():
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('localhost', 12345))

# 输入用户名
username = input("请输入用户名:")
client_socket.send(username.encode())

thread = threading.Thread(target=receive_messages, args=(client_socket,))
thread.start()

while True:
message = input()
if message.lower() == 'exit':
break
client_socket.send(f"{username}: {message}".encode())

client_socket.close()

if __name__ == "__main__":
start_client()