第一章:网络编程基础回顾

做网络编程这么多年,我经常被问到同一个问题:「到底该从哪开始学?」

说实话,很多人一上来就撸代码,结果遇到各种诡异问题——连接超时、数据乱序、内存泄漏……最后发现,根子都在基础没打牢。

这一章,我们就来把地基夯实。我会带着你从OSI七层模型开始,一路走到Socket编程实战。嗯,都是我自己踩过的坑,你直接拿去用就行。

1.1 OSI七层模型:理论上的「完美蓝图」

OSI七层模型,说白了就是国际标准化组织(ISO)给网络通信画的一张「设计图纸」。它把通信过程拆成了7层,每一层只管自己的事。

层级 名称 核心职责 常见协议/设备
7 应用层 为用户提供网络服务接口 HTTP、FTP、SMTP
6 表示层 数据格式转换、加密、压缩 SSL/TLS、JPEG、ASCII
5 会话层 建立、管理、终止会话 NetBIOS、RPC
4 传输层 端到端可靠传输 TCP、UDP
3 网络层 路由选择、逻辑寻址 IP、ICMP、路由器
2 数据链路层 帧封装、差错控制 以太网、交换机、MAC
1 物理层 比特流传输 网线、光纤、集线器
我的经验: 实际工作中,没人会真的按七层去开发。但排查问题时,这七层就是你的「故障定位地图」。我曾经遇到一个诡异的丢包问题,从应用层一路查到物理层,最后发现是网线水晶头接触不良——嗯,这种坑你早晚也会遇到。

1.2 TCP/IP四层模型:工业界的「实战派」

OSI太理想化了,工业界更喜欢用TCP/IP四层模型。它把七层压缩成了四层,去掉了表示层和会话层,把应用层、表示层、会话层合并为一层。

核心对比:
  • 应用层:对应OSI的5/6/7层,HTTP、DNS、FTP都在这里
  • 传输层:对应OSI的第4层,TCP/UDP的主战场
  • 网络层:对应OSI的第3层,IP协议的核心
  • 网络接口层:对应OSI的1/2层,硬件相关

你想想看,我们平时写网络程序,打交道最多的就是传输层和应用层。TCP保证数据不丢不乱,UDP追求速度不管顺序——这两个选择,直接影响你的架构设计。

避坑指南: 我曾经接手过一个实时视频流项目,前人用了TCP,结果因为重传机制导致画面卡顿严重。后来改成UDP + 应用层丢包补偿,流畅度直接翻倍。选协议,一定要看业务场景。

1.3 Socket编程基础:从理论到代码的「桥梁」

Socket是什么?说白了,它就是操作系统提供的一个「网络通信的接口」。你不需要关心底层网卡怎么发数据,只需要调用几个函数就行。

我习惯把Socket编程的核心流程总结成四个字:「建连收发」。

1.3.1 核心API速览

函数 作用 服务端 客户端
socket() 创建套接字 ✅ ✅
bind() 绑定IP和端口 ✅ 可选
listen() 监听连接 ✅ ❌
accept() 接受连接 ✅ ❌
connect() 发起连接 ❌ ✅
send()/recv() 发送/接收数据 ✅ ✅
close() 关闭连接 ✅ ✅

1.3.2 一个最简单的TCP回显服务器

来看代码。这是我当年入门时写的第一个网络程序,现在看依然经典。

// server.c - TCP回显服务器
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>

int main() {
    // 1. 创建socket
    int server_fd = socket(AF_INET, SOCK_STREAM, 0);
    
    // 2. 绑定地址
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8080);
    addr.sin_addr.s_addr = INADDR_ANY;
    bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
    
    // 3. 监听
    listen(server_fd, 5);
    
    printf("服务器启动,监听端口 8080...\n");
    
    // 4. 接受连接
    struct sockaddr_in client_addr;
    socklen_t client_len = sizeof(client_addr);
    int client_fd = accept(server_fd, 
                           (struct sockaddr*)&client_addr, 
                           &client_len);
    
    // 5. 收发数据
    char buffer[1024] = {0};
    recv(client_fd, buffer, sizeof(buffer), 0);
    printf("收到: %s\n", buffer);
    send(client_fd, buffer, strlen(buffer), 0);
    
    // 6. 关闭
    close(client_fd);
    close(server_fd);
    return 0;
}
注意: 这段代码只是为了演示流程,生产环境绝对不能这么写。为什么?因为它是单线程阻塞模型,一次只能服务一个客户端。后面章节我会带你一步步优化到高并发。

1.4 客户端-服务器模型:网络程序的「基本盘」

几乎所有网络程序,本质上都是客户端-服务器模型。服务器提供服务,客户端消费服务。就这么简单。

但这里有个关键点:谁先发起连接?

  • 客户端主动连接:最常见的模式,比如浏览器连Web服务器
  • 服务器主动连接:少见,比如P2P中的反向连接
  • 双向连接:WebSocket、gRPC等,连接建立后双方都能主动发数据
我的建议: 刚开始做设计时,先画清楚「谁主动、谁被动」。我曾经见过一个团队,把客户端和服务器的角色搞反了,结果调试了三天才发现是connect和bind用反了——这种低级错误,画个图就能避免。

1.5 本章知识体系总览

下面这张图,是我自己总结的「网络编程基础地图」。每次带新人,我都会先让他们看这张图。

网络编程基础知识体系 协议模型 OSI七层模型 TCP/IP四层模型 核心协议(TCP/UDP/IP) Socket编程 socket() / bind() / listen() accept() / connect() send() / recv() / close() 通信模型 客户端-服务器模型 同步/异步 阻塞/非阻塞 从协议 → Socket → 模型,层层递进
核心要点:
  • OSI七层是理论,TCP/IP四层是实践
  • Socket是操作系统对网络协议的封装
  • 客户端-服务器模型是所有网络架构的起点
  • 选TCP还是UDP,取决于你的业务对可靠性和延迟的要求
最后提醒一句: 别急着写高并发代码。先把单连接调通,把基础API用熟。我见过太多人一上来就搞epoll、多线程,结果连bind失败都不会排查——基础不牢,地动山摇。

可可精品资料库