1.环境准备
go语言准备一个server和一个client
1.1 server
go
package main
import (
"bufio"
"fmt"
"net"
"strings"
)
func handleConnection(conn net.Conn) {
defer conn.Close()
fmt.Printf("客户端已连接: %s\n", conn.RemoteAddr())
reader := bufio.NewReader(conn)
for {
// 读取客户端消息
message, err := reader.ReadString('\n')
if err != nil {
fmt.Println("连接断开:", err)
return
}
// 处理消息
message = strings.TrimSpace(message)
fmt.Printf("收到来自 %s 的消息: %s\n", conn.RemoteAddr(), message)
// 发送响应
response := fmt.Sprintf("已收到你的消息(%d字节)\n", len(message))
_, err = conn.Write([]byte(response))
if err != nil {
fmt.Println("发送响应失败:", err)
return
}
}
}
func main() {
// 监听8080端口
listener, err := net.Listen("tcp", ":8080")
if err != nil {
fmt.Println("监听失败:", err)
return
}
defer listener.Close()
fmt.Println("服务器已启动,正在监听 :8080 端口...")
for {
// 等待客户端连接
conn, err := listener.Accept()
if err != nil {
fmt.Println("接受连接失败:", err)
continue
}
// 为每个连接创建goroutine
go handleConnection(conn)
}
}
client
go
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
// 连接服务器
conn, err := net.Dial("tcp", "localhost:8080")
if err != nil {
fmt.Println("连接服务器失败:", err)
return
}
defer conn.Close()
fmt.Println("已连接到服务器")
// 创建读写器
reader := bufio.NewReader(os.Stdin)
connReader := bufio.NewReader(conn)
for {
// 读取用户输入
fmt.Print("请输入消息(输入exit退出): ")
message, _ := reader.ReadString('\n')
message = strings.TrimSpace(message)
if message == "exit" {
fmt.Println("退出客户端")
return
}
// 发送消息到服务器
_, err := conn.Write([]byte(message + "\n"))
if err != nil {
fmt.Println("发送消息失败:", err)
return
}
// 接收服务器响应
response, err := connReader.ReadString('\n')
if err != nil {
fmt.Println("读取响应失败:", err)
return
}
fmt.Printf("服务器响应: %s", response)
}
}
2.记一点简单的理论
2.1 三次握手
2.2 标识符
3.wireshark实践
双击打开第一个tcp 使用本地的adapter loop
1.字节和图像是对应的
一个字节=8bit=两个十六位数=255
65个字节


1. 标识源端口

2. 标识目标端口

3.标识序列号(以及显示一个相对序列号)

4. 标识确认号

5.标识flags

6.8+24bit构成两个字节

1.tcp头部长度 4bit
-
官方名称 :
Data Offset
(数据偏移量)。 -
作用 :指示TCP头部的总长度(单位:4字节),以便接收方知道头部结束、数据部分开始的位置。
- 例如:
Data Offset=5
→ 头部长度 =5 × 4 = 20字节
(标准TCP头部的最小长度)。头部一定是4字节的倍数
- 例如:
后面的是保留字段
2.flags 12bit

7.窗口大小

8.校验和

- 计算范围 :覆盖 TCP伪头部 + TCP头部 + TCP数据(校验和字段本身除外)。
- 验证方式 :接收方重新计算校验和,若与包中的
Checksum
值不匹配,则丢弃该包。
校验和覆盖以下三部分数据(按顺序拼接):
- IPv6伪头部(Pseudo-Header):增强校验强度,包含IP层关键信息。
- TCP头部 :包括所有字段(但校验和字段本身需置为
0x0000
)。 - TCP数据:即有效载荷(Payload)。
计算反码和
- 按16位分组:将所有数据(伪头部 + TCP头部 + 数据)按16位(2字节)分割。
- 累加所有16位字:若累加结果超过16位(溢出),将溢出部分(进位)加到低位。
- 取反码:对最终累加结果按位取反(1→0,0→1)。
9.紧急指针
紧急指针的作用
- 定义 :当 TCP 标志位中的 URG (Urgent) 被置为
1
时,Urgent Pointer
表示紧急数据的位置(偏移量)。 - 目的 :允许接收方优先处理某些关键数据(如终端命令
Ctrl+C
中断操作),即使正常数据未被全部接收
flags有一个Urgent的标志位
10 应用层数据
