《Linux系统编程篇》Linux Socket 网络编程02 (Linux 进程间通信(IPC))——基础篇

从 Socket 到 TCP/UDP:给初学者的一条清晰学习路线

很多人刚学网络编程时,会同时碰到这几个词:

  • socket
  • TCP
  • UDP
  • client
  • server

这篇文章的目标不是堆概念,而是帮你建立一个能直接拿来写 C 网络程序的理解框架。


一、先说结论:Socket 不是协议,而是编程接口

很多初学者容易把 socketTCPUDP 混成同一种东西,但它们并不是一层的概念。

最简单的理解方式是:

  • TCPUDP 是传输层协议
  • socket 是操作系统提供给程序员的网络编程接口

也就是说:

  • 协议决定"网络上怎么传"
  • socket 决定"程序里怎么写"

你可以把它理解成:

  • TCP/UDP 是道路规则
  • socket 是方向盘、油门和刹车

程序员写 C 网络程序时,并不是直接"操作 TCP 协议",而是通过 socket API,让操作系统帮你完成 TCP 或 UDP 通信。


二、Socket 到底是什么?

Socket 可以先粗略理解成:

程序和网络之间的一扇门

程序想发数据到网络,或者想从网络收数据,都要先打开这扇门。

在 C 语言里,这扇门通常是通过 socket() 这个函数创建出来的。

例如:

c 复制代码
int fd = socket(AF_INET, SOCK_STREAM, 0);

这句代码的意思大致是:

  • AF_INET:使用 IPv4
  • SOCK_STREAM:使用流式通信,也就是 TCP
  • 返回值 fd:一个套接字描述符,后面读写网络都通过它来完成

如果是 UDP,通常会写成:

c 复制代码
int fd = socket(AF_INET, SOCK_DGRAM, 0);

所以你会发现:

  • socket 是编程入口
  • SOCK_STREAM 时,背后对应 TCP
  • SOCK_DGRAM 时,背后对应 UDP

三、TCP 和 UDP 的核心区别

如果只讲一句最有用的话:

  • TCP:可靠、面向连接、适合重要数据
  • UDP:轻量、无连接、适合低延迟场景

但这句还不够,真正写程序时要理解下面几件事。

1. TCP 是面向连接的

TCP 通信前,客户端和服务端要先建立连接。

它的感觉更像"先打通电话,再说话"。

所以 TCP 程序里通常会看到这些动作:

  • 服务端:socket -> bind -> listen -> accept
  • 客户端:socket -> connect
  • 双方:send/recvread/write

2. UDP 是无连接的

UDP 不需要先建立连接。

它更像"直接寄明信片",发出去就发出去了,不保证一定收到。

所以 UDP 程序里通常不会有:

  • listen
  • accept

而是直接:

  • sendto
  • recvfrom

3. TCP 可靠,UDP 不保证可靠

TCP 会尽量保证:

  • 数据不丢
  • 数据按顺序到达
  • 数据不重复

UDP 则不保证这些:

  • 可能丢包
  • 可能乱序
  • 可能重复

这就是为什么:

  • 文件传输、HTTP、SSH、MQTT 通常走 TCP
  • 音视频、实时游戏、广播发现常常用 UDP

4. TCP 没有消息边界,UDP 有消息边界

这是 C 网络编程里特别容易踩坑的一点。

TCP 是"字节流",不是"一条一条消息"。

比如你连续发送两次:

text 复制代码
hello
world

接收端可能收到:

  • helloworld
  • hello 然后 world
  • hel 然后 loworld

所以 TCP 编程时,你必须自己设计"消息边界",比如:

  • 固定长度
  • 分隔符
  • 头部 + 长度字段

UDP 则天然是一包一包的,消息边界由协议本身保留。


四、Client 和 Server 到底是什么?

不管 TCP 还是 UDP,初学时都要建立一个清晰模型:

  • Server:提供服务、等别人来连接或发消息
  • Client:主动发起连接或发送请求

TCP 中的角色更明显

TCP 服务端通常这样工作:

  1. socket()
  2. bind() 绑定 IP 和端口
  3. listen() 开始监听
  4. accept() 接受客户端连接
  5. 和客户端收发数据

TCP 客户端通常这样工作:

  1. socket()
  2. connect() 连接服务端
  3. 收发数据

UDP 中也有"服务端/客户端"说法

虽然 UDP 是无连接的,但工程里仍然常说"UDP 服务端"和"UDP 客户端"。

区别主要在于:

  • 服务端通常固定监听某个端口
  • 客户端通常主动往这个端口发数据

只是它们之间没有 TCP 那种"连接建立"的状态。


五、TCP 的最小工作流程

下面是最常见的 TCP 通信时序:

TCP 服务端典型流程

c 复制代码
socket();
bind();
listen();
accept();
recv();
send();
close();

TCP 客户端典型流程

c 复制代码
socket();
connect();
send();
recv();
close();

这套流程里最关键的两个动作是:

  • listen():开始监听端口
  • accept():真正拿到一个客户端连接

很多初学者会以为 listen() 之后就能直接通信,其实真正用于和客户端通信的,通常是 accept() 返回的新连接 fd。


六、UDP 的最小工作流程

UDP 比 TCP 简单很多,因为没有连接建立过程。

时序可以理解成这样:

UDP 服务端典型流程

c 复制代码
socket();
bind();
recvfrom();
sendto();
close();

UDP 客户端典型流程

c 复制代码
socket();
sendto();
recvfrom();
close();

UDP 少了:

  • listen()
  • accept()
  • connect()(虽然 UDP 也可以调用 connect,但它的语义和 TCP 不一样)

所以从上手难度看,UDP 的 API 更简单,但应用层要自己考虑更多问题,比如丢包、重发、顺序控制等。


七、C 语言里最常见的 Socket API

如果你准备开始写 C 网络程序,最常见的函数大概就是下面这些。

创建套接字

c 复制代码
socket()

创建网络通信对象。

绑定地址和端口

c 复制代码
bind()

通常服务端需要绑定固定端口,客户端有时不需要显式绑定。

TCP 监听和接收连接

c 复制代码
listen()
accept()

只在 TCP 服务端常见。

发起连接

c 复制代码
connect()

TCP 客户端常用。

接收和发送数据

c 复制代码
send()
recv()
sendto()
recvfrom()
  • send/recv:常见于 TCP
  • sendto/recvfrom:常见于 UDP

关闭套接字

c 复制代码
close()

释放连接和文件描述符。


八、为什么很多协议都基于 TCP?

理解这一点后,你会更容易把 MQTT、HTTP、SSH、WebSocket 放到同一张图里。

很多应用层协议本身不处理"丢包重传、乱序重组、可靠传输"这些底层细节,所以它们往往直接建立在 TCP 之上。

例如:

  • HTTP 基于 TCP
  • SSH 基于 TCP
  • MQTT 通常基于 TCP
  • WebSocket 基于 TCP

也就是说:

  • 应用协议负责定义"消息长什么样"
  • TCP 负责把这些字节可靠送过去

所以可以把它理解成:

MQTT 不是 TCP 的替代品,而是运行在 TCP 之上的应用层协议。

这对理解你前面学的 MQTT 很关键。


九、MQTT 和 Socket/TCP/UDP 的关系

如果你已经学过 MQTT,这里就能把知识串起来。

MQTT 通常工作在这样的层次结构上:

text 复制代码
MQTT
  ↓
TCP
  ↓
IP
  ↓
网卡 / 网络

在程序实现上,一般是:

  • 应用层写 MQTT 客户端逻辑
  • MQTT 库内部通过 socket 去操作 TCP 连接
  • 操作系统负责把数据发到网络上

所以:

  • 你写 MQTT 程序时,通常不需要自己直接写 socket()
  • 你写原始 TCP/UDP 程序时,才会直接使用 socket API

这也是为什么 MQTT 入门看起来更简单,因为很多底层细节已经被库封装掉了。


十、什么时候用 TCP,什么时候用 UDP?

这不是一个纯理论问题,而是工程里经常要做的选择。

更适合 TCP 的场景

  • 登录认证
  • 文件传输
  • 配置下发
  • 远程控制命令
  • HTTP 接口
  • MQTT 消息系统

这些场景的特点通常是:

  • 不能乱
  • 不能丢
  • 顺序很重要

更适合 UDP 的场景

  • 局域网设备发现
  • 视频直播
  • 音频实时传输
  • 游戏状态同步
  • 广播或组播场景

这些场景更关注:

  • 延迟低
  • 实时性高
  • 丢一点数据比卡顿更能接受

十一、初学者最容易踩的坑

1. 以为 TCP 一次 send 对应一次 recv

这是错误的。

TCP 是字节流,不保留消息边界,所以应用层必须自己设计协议格式。

2. 以为 UDP 简单就一定更好

UDP 只是 API 更少,不代表系统更简单。真正做可靠业务时,UDP 的很多问题要自己补。

3. 以为服务端只有一个 socket

TCP 服务端通常会有两个层次:

  • 监听 socket
  • 每个客户端连接对应的通信 socket

4. 以为 connect 只属于 TCP

UDP 也可以 connect(),但它不是建立真正的连接,而是绑定默认对端地址,语义和 TCP 不一样。

5. 以为网络编程就是会调几个函数

真正的难点往往不在 API,而在:

  • 协议设计
  • 超时处理
  • 粘包拆包
  • 并发连接
  • 断线重连
  • 错误恢复

十二、给初学者的推荐学习顺序

如果你正在从 MQTT 往更底层学习,建议按下面这个顺序来。

第一步:先理解 TCP 和 UDP 的区别

先建立概念模型,不要急着背 API。

你至少要能回答:

  • TCP 为什么可靠?
  • UDP 为什么快?
  • TCP 为什么会有粘包问题?

第二步:写最小 TCP 程序

建议先写:

  • 一个 TCP 服务端
  • 一个 TCP 客户端
  • 能完成一次字符串收发

因为 TCP 更贴近大多数实际业务。

第三步:再写最小 UDP 程序

写一个:

  • UDP 服务端监听端口
  • UDP 客户端发送一条消息
  • 服务端收到后回一条确认消息

第四步:回头理解 MQTT 为什么更省心

学完原始 socket 编程后,你会更深刻地理解:

  • 为什么 MQTT 库能帮你省掉很多工作
  • 为什么应用层协议和传输层协议要分层

十三、本文总结

如果只记住几句话,最重要的是下面这些:

  • socket 是编程接口,不是协议
  • TCPUDP 是传输层协议
  • TCP 面向连接、可靠,但没有消息边界
  • UDP 无连接、轻量,保留消息边界,但不保证可靠
  • MQTT 通常运行在 TCP 之上,而不是替代 TCP

对于 C 程序员来说,真正的学习路径通常是:

  1. 先学清楚 TCP 和 UDP 的通信模型
  2. 再写最小 socket 程序
  3. 再去理解更高层的协议,比如 MQTT、HTTP、WebSocket

当你能把这几个层次分开看时,网络编程就不会再显得混乱:

  • socket 是"怎么写程序"
  • TCP/UDP 是"怎么传数据"
  • MQTT/HTTP 是"数据内容按什么规则组织"

这套分层思维,比单独记函数名更重要。

相关推荐
普马萨特2 小时前
基站 / WiFi 粗略位置对 A-GNSS 的影响
网络·人工智能·算法
yiwenrong2 小时前
history 常见优化配置
linux
@insist1233 小时前
网络工程师-WLAN 无线局域网全解析
大数据·网络·网络工程师·软考·软件水平考试
Joren的学习记录3 小时前
【Linux运维大神系列】Kubernetes详解7(k8s技术笔记3)
linux·运维·kubernetes
q_30238195563 小时前
告别kubectl命令地狱!MCP-K8s让AI成为你的智能运维助手
运维·人工智能·语言模型·chatgpt·kubernetes·文心一言·devops
Three~stone3 小时前
Wireshark 4.6.4 安装教程
网络·测试工具·wireshark
chenqianghqu4 小时前
ubuntu 22.04环境中安装goland
linux·运维·ubuntu
pl4H522a64 小时前
Ctf组会-网络基础,一篇总览基本的网络知识
网络
gwjcloud4 小时前
Frp内网穿透
linux·运维·服务器