目录
- HTTP请求在网络中传输的完整路径
- 完整流程
- 完整流程详解
- 1. 客户端点击 → 发送HTTP包
- 2. Socket连接发送给服务器
- 3. 服务器网卡收到
- 4. 系统底层sock等处理
- 5. 到达服务器的Socket连接
HTTP请求在网络中传输的完整路径
完整流程
客户端点击↓
构造HTTP请求(GET /index.html HTTP/1.1...)↓ # 发送给服务端:socket.writeAndFlush()
用户空间 → 内核空间(send()系统调用)↓
传输层:添加TCP头(源端口、目标端口80、序列号等)↓
网络层:添加IP头(源IP、目标IP、TTL等)↓
数据链路层:添加以太网帧头(源MAC、目标MAC)↓
物理层:网卡将数字信号转为电信号/光信号↓
--- 通过网络传输 ---↓
服务器网卡收到电信号/光信号↓
物理层:网卡将信号转为数字数据↓
数据链路层:检查MAC地址,剥去帧头↓
网络层:检查IP地址,判断是本地交付↓
传输层:TCP处理,根据端口号找到对应sock结构↓
将数据放入sock接收队列,唤醒等待进程↓ # 接收:socket.getInputStream()
服务器应用程序从Socket读取数据↓
解析HTTP请求,处理业务逻辑↓
返回HTTP响应(逆向重复上述过程)↓ # 发送给客户端:socket.writeAndFlush()...
完整流程详解
1. 客户端点击 → 发送HTTP包
// 浏览器/客户端应用代码层面
public class Browser {public void onClick() {// 构造HTTP请求String httpRequest = "GET /index.html HTTP/1.1\r\n" +"Host: www.example.com\r\n" +"User-Agent: Mozilla/5.0\r\n" +"\r\n";// 通过Socket发送Socket socket = new Socket("www.example.com", 80);OutputStream out = socket.getOutputStream();out.write(httpRequest.getBytes());out.flush();}
}
2. Socket连接发送给服务器
操作系统内核处理:
// Linux内核大致流程(简化)
int socket_send(struct socket *sock, const char *buf, size_t len) {// 传输层:添加TCP头struct tcphdr *tcp_header = build_tcp_header(sock->src_port, sock->dst_port);// 网络层:添加IP头 struct iphdr *ip_header = build_ip_header(sock->src_ip, sock->dst_ip);// 数据链路层:添加以太网头struct ethhdr *eth_header = build_eth_header(sock->src_mac, sock->dst_mac);// 通过网卡驱动发送netdevice_transmit(complete_packet);
}
3. 服务器网卡收到
网卡驱动处理:
// 网卡中断处理函数
irqreturn_t nic_interrupt_handler(int irq, void *dev_id) {// 1. DMA将数据包从网卡内存拷贝到内核内存struct sk_buff *skb = alloc_skb(packet_size);nic_dma_to_ram(skb->data, packet_size);// 2. 触发软中断,交给网络协议栈处理raise_softirq(NET_RX_SOFTIRQ);
}
4. 系统底层sock等处理
Linux网络协议栈处理:
// 网络协议栈处理流程
int netif_receive_skb(struct sk_buff *skb) {// 1. 数据链路层:检查MAC地址,剥去以太网头if (!is_my_mac_address(skb->eth_hdr->dest)) return DROP;skb_pull(skb, sizeof(struct ethhdr));// 2. 网络层:检查IP头,路由判断if (skb->ip_hdr->daddr != my_ip) {ip_forward(skb); // 需要转发} else {ip_local_deliver(skb); // 本地处理}// 3. 传输层:TCP/UDP处理if (skb->ip_hdr->protocol == IPPROTO_TCP) {tcp_v4_rcv(skb); // 交给TCP处理}
}// TCP层处理
int tcp_v4_rcv(struct sk_buff *skb) {// 根据IP+端口找到对应的sock结构struct sock *sk = __inet_lookup_skb(&tcp_hashinfo, skb);if (sk != NULL) {// 将数据包放入sock的接收队列__skb_queue_tail(&sk->sk_receive_queue, skb);// 唤醒等待该sock的进程wake_up_interruptible(sk->sk_sleep);}
}
5. 到达服务器的Socket连接
服务器应用程序处理:
// 服务器端Socket代码
public class WebServer {public void start() throws IOException {ServerSocket serverSocket = new ServerSocket(80);while (true) {// 等待客户端连接(内核唤醒进程)Socket clientSocket = serverSocket.accept();// 创建线程处理请求new Thread(() -> handleRequest(clientSocket)).start();}}private void handleRequest(Socket clientSocket) throws IOException {// 6. 获取数据内容InputStream in = clientSocket.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(in));// 读取HTTP请求String requestLine = reader.readLine();System.out.println("收到请求: " + requestLine);// 读取请求头String header;while (!(header = reader.readLine()).isEmpty()) {System.out.println("请求头: " + header);}// 处理请求并返回响应OutputStream out = clientSocket.getOutputStream();String response = "HTTP/1.1 200 OK\r\n\r\nHello World";out.write(response.getBytes());out.flush();clientSocket.close();}
}