嵌入式Linux C应用编程——socket网络编程(一、网络基础知识)

网络基础知识

本文以正点原子嵌入式Linux C编程文档为主,并包含了部分AI生成的内容,内容仅供参考。

网络通信概述

网络通信本质上是一种进程间通信(IPC),但不同于同一主机内的进程通信,它是位于网络中不同主机上的进程之间的通信,通常称为 socket IPC

网络通信的三个层次

层次 组成 作用
硬件层 网卡设备、网线、光纤、WiFi 等 收发网络数据,是网络通信的物理基础
驱动层 Linux 内核网卡驱动代码 驱动底层网卡硬件,向上提供 socket 接口
应用层 应用程序(调用 socket 接口) 实现具体的网络应用程序

传输媒介分为有线传输(双绞线、光纤等)和无线传输(WiFi、蓝牙、ZigBee、4G/5G/GPRS 等)。

socket 接口是内核向应用层提供的一套网络编程接口,学习网络编程就是学习 socket 编程。除了 socket 外,还有 http、网络控件等更高级的封装接口。


网络互连模型

OSI 七层模型

OSI(Open System Interconnection)七层参考模型由 ISO 制定,是一个网络互联的标准体系,从高到低依次为:

层号 名称 功能说明 常见协议/设备
7 应用层 最靠近用户的一层,为用户提供应用接口和网络服务。直接为用户提供各种网络服务。 HTTP、FTP、TFTP、SMTP、DNS、POP3
6 表示层 提供各种用于应用层数据的编码和转换功能,确保一个系统的应用层发送的数据能被另一个系统的应用层识别。如果必要,该层可提供一种标准表示形式,用于将计算机内部的多种数据格式转换成通信中采用的标准表示形式。数据压缩/解压缩和加密/解密也是表示层可提供的功能之一。 JPEG/PNG(图像编码)、ASCII/Unicode(字符编码)
5 会话层 对应主机进程,指本地主机与远程主机正在进行的会话。负责建立、管理和终止表示层实体之间的通信会话,组织和协调两个会话进程之间的通信,并对数据交换进行管理。 SSL/TLS(安全会话)、RPC(远程过程调用)、SOCKS(网络代理)
4 传输层 定义传输数据的协议端口号,以及端到端的流控和差错校验。该层建立了主机端到端的连接,为上层协议提供端到端的可靠和透明的数据传输服务。我们通常说的 TCP、UDP 协议就工作在这一层,端口号既是这里的"端"。 TCP、UDP,端口号即这里的"端"
3 网络层 进行逻辑地址寻址,实现不同网络之间的路径选择(路由)。通过 IP 寻址来建立两个节点之间的连接,为源端发送的数据包选择合适的路由和交换节点,正确无误地按照地址传送给目的端的传输层。也就是通常说的 IP 层。 IP(IPv4/IPv6)、ICMP、IGMP
2 数据链路层 负责建立和管理节点间逻辑连接、进行硬件地址寻址(MAC)、差错检测等功能。将比特组合成字节进而组合成帧,用 MAC 地址访问介质,错误发现但不能纠正。该层又分为逻辑链路控制子层(LLC)和媒体访问控制子层(MAC)。 分为 LLC 子层和 MAC 子层
1 物理层 利用传输介质为数据链路层提供物理连接,实现比特流的透明传输(经实际电路传送后的比特流没有发生变化,对传送的比特流来说,这个电路好像是看不见的)。尽可能屏蔽掉具体传输介质和物理设备的差异,使数据链路层不必考虑网络的具体传输介质是什么。 集线器、中继器、调制解调器、网线

"透明传输比特流" 的含义:经实际电路传送后的比特流没有发生变化,对传送的比特流来说,这个电路好像是看不见的。

举个现实的例子:用浏览器打开网页

光看理论可能比较抽象,下面以 在浏览器输入网址打开网页 这个过程为例,看看每一层分别做了什么:

flowchart LR subgraph 发送端[你的电脑 — 数据封装] direction TB L7["⑦ 应用层<br>浏览器发送 HTTP 请求"] L6["⑥ 表示层<br>编码压缩、加密"] L5["⑤ 会话层<br>SSL 握手建立安全会话"] L4["④ 传输层<br>切成 TCP 段,<br>标记源端口和目标端口"] L3["③ 网络层<br>打上源 IP 和目标 IP"] L2["② 数据链路层<br>套上 MAC 帧头"] L1["① 物理层<br>转成电信号发出"] L7 --> L6 --> L5 --> L4 --> L3 --> L2 --> L1 end NET[" 网络传输<br>路由器逐跳转发<br>MAC 逐段改变<br>IP 保持不变"] subgraph 接收端[目标服务器 — 数据拆封] direction TB R1["① 物理层<br>电信号还原成比特"] R2["② 数据链路层<br>检查 MAC,拆掉帧头"] R3["③ 网络层<br>检查 IP,拆掉 IP 头"] R4["④ 传输层<br>重组 TCP 段为完整数据"] R5["⑤ 会话层<br>SSL 解密"] R6["⑥ 表示层<br>解压缩"] R7["⑦ 应用层<br>服务器收到请求,<br>返回网页内容"] R1 --> R2 --> R3 --> R4 --> R5 --> R6 --> R7 end 发送端 -->|"数据流向"| NET -->|"数据流向"| 接收端
角色 在这个例子中具体做了什么
在浏览器地址栏输入 https://www.example.com,敲回车
应用层 浏览器 构造一个 HTTP GET 请求,头部写着"我要访问 / 这个页面"
表示层 浏览器/OS HTTP 数据被 gzip 压缩以节省带宽;如果是 HTTPS,还会进行加密;浏览器解析返回的 HTML、解码图片(JPEG/PNG)
会话层 浏览器/OS 如果是 HTTPS,与服务器进行 SSL/TLS 握手,协商加密算法、交换证书,建立安全会话通道
传输层 操作系统内核 TCP 协议将 HTTP 数据切分成多个数据段(Segment),每个段标记源端口(随机高位端口)和目标端口(443)。保证所有段按序到达、不丢失
网络层 操作系统内核 IP 协议给每个 TCP 段套上 IP 头,写入源 IP(192.168.1.x,即本机IP)和目标 IP(93.184.216.34—example.com 的 IP)。然后查询路由表,决定从哪个网口发出
数据链路层 网卡驱动 将 IP 数据包封装成以太网帧(Frame),添加源 MAC 地址和目标 MAC 地址(下一跳路由器 MAC)。通过 ARP 协议获取路由器 MAC
物理层 网卡/网线/WiFi 将帧转换为电信号(网线)或无线电波(WiFi),通过物理介质发送出去
网络传输 路由器/交换机 数据经过多个路由器,每经过一跳,数据链路层和物理层重新封装(MAC 地址逐跳改变),但网络层的 IP 地址不变
①→⑦ 服务器接收 服务器 数据到达服务器后,从物理层开始逐层拆封,从电信号还原出 HTTP 请求,交给 Web 程序处理,然后把网页内容按同样路径返回给浏览器

可以看到,每一层都只关心自己的职责:应用层只管发请求,不管数据怎么切分、怎么路由;传输层只管可靠传输,不管数据是图片还是文字;物理层只管传比特流,不管比特流代表什么意思。各层各司其职,这就是分层设计的意义。

TCP/IP 模型

TCP/IP 模型是 OSI 模型的简化版本,有两种常见划分:

  1. TCP/IP 五层模型:将 OSI 的上三层(应用层、表示层、会话层)合并为应用层,其余四层不变,即:应用层 → 传输层 → 网络层 → 数据链路层 → 物理层
  2. TCP/IP 四层模型:在五层模型基础上,将数据链路层和物理层合并为网络接口层,即:应用层 → 传输层 → 网络层 → 网络接口层

实际应用中多使用四层模型,五层模型是专门为介绍网络原理而设计的。

img

数据的封装与拆封

数据发送(封装)过程:

img

数据接收(拆封)过程与发送相反:从物理层开始,逐层向上拆解各层首部,最终还原出原始的用户数据。


IP 地址

IP 地址(Internet Protocol Address)用于标识互联网中的每台主机身份,是软件地址(不是硬件 MAC 地址)。

IP 地址和MAC 地址的关系:IP 地址负责跨网络找到目标主机(端到端),MAC 地址负责每一段链路上的实际传输(逐跳)。

如果两台主机在同一局域网内,先通过 IP 判断在同一网段,再通过 ARP 协议广播查询目标 IP 对应的 MAC 地址,直接用 MAC 通信。如果跨网络,则先将数据帧发给路由器(通过 ARP 获取路由器 MAC),路由器拆掉 MAC 帧头、查看 IP、重新封装新的 MAC 地址转发给下一跳。

编址方式

  • IPv4:32 位二进制数,由 4 个 8 位字段组成,通常用点分十进制表示(如 192.168.1.1
  • IPv6:128 位地址长度,8 个 16 位字段组成
  • IP 地址包含两部分:网络地址 + 主机地址,通过子网掩码来划分

IP 地址的五类划分

类别 首位 网络地址长度 主机地址长度 范围 默认子网掩码 用途
A 0 1 字节 3 字节 1.0.0.1 ~ 127.255.255.254 255.0.0.0 大型网络
B 10 2 字节 2 字节 128.0.0.1 ~ 191.255.255.254 255.255.0.0 中型网络
C 110 3 字节 1 字节 192.0.0.1 ~ 223.255.255.254 255.255.255.0 小型网络(局域网)
D 1110 224.0.0.1 ~ 239.255.255.254 多播(Multicast)
E 11110 240.0.0.1 ~ 255.255.255.254 保留,将来使用

img

私有地址(只能在局域网中使用)

类别 私有地址范围
A 10.0.0.0 ~ 10.255.255.255
B 172.16.0.0 ~ 172.31.255.255
C 192.168.0.0 ~ 192.168.255.255

特殊 IP 地址

类型 格式 说明
直接广播地址 主机号全为 1 向某个网络上所有主机发送报文。但要求发送方必须知道广播网络对应的网络号。如 C 类地址 192.168.0.181 的广播地址为 192.168.0.255
受限广播地址 255.255.255.255(32 位全 1) 主机在启动时往往还不知道本网络的网络号,这时只能采用受限广播地址在本网络内部进行广播
多播地址 D 类地址 一对多通信,发送者只发送一次数据包,多个接收者接收。D 类地址只能用作目的地址,而不能作为主机中的源地址
环回地址 127.X.X.X 用于网络软件测试和本机进程间通信,如 ping 127.1.1.1 测试本地 TCP/IP 协议是否正常
0.0.0.0 32 位全 0 表示本网络上的本主机,只能用作源地址。0.0.0.0 是不能被 ping 通的。在服务器中,它并不是一个真实的 IP 地址,而是表示本机中所有 IPv4 地址。监听 0.0.0.0 的端口,就是监听本机中所有 IP 的端口

如何判断两个 IP 是否在同一网段

网络标识 = IP 地址 & 子网掩码

两个 IP 地址的网络标识相同,则它们处于同一网络。

示例:

  • 192.168.1.50 & 255.255.255.0 → 网络标识 192.168.1.0
  • 192.168.1.100 & 255.255.255.0 → 网络标识 192.168.1.0
  • 两者相同则处于同一网络

TCP/IP 协议

TCP/IP 协议是一个协议族(而非单一协议),包含众多协议:

  • 应用层协议:HTTP、FTP、SMTP、MQTT、DNS 等
  • 传输层协议:TCP、UDP
  • 网络层协议:IP、ICMP、IGMP 等

常见应用层协议

协议 全称 默认端口 作用
HTTP 超文本传输协议 80 万维网数据通信的基础,浏览器-服务器模式
FTP 文件传输协议 21 在两台主机之间进行文件传输,支持上传/下载、目录操作、权限设置、身份验证
SMTP 简单邮件传输协议 25 帮助每台计算机在发送或中转信件时找到下一个目的地
TFTP 简单文件传输协议 69 主机之间进行简单文件传输
SSH 安全外壳协议 22 专为远程登录会话和其他网络服务提供安全性的协议
Telnet 终端远程登录协议 23 在本地计算机上完成远程主机工作的能力
POP3 邮局协议版本 3 110 支持使用客户端远程管理在服务器上的电子邮件

TCP 协议

TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于 IP 的传输协议

TCP 的核心特点

特点 说明
面向连接 TCP 是一个面向连接的协议,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一个 TCP 连接(通过三次握手),否则将无法发送数据。
确认与重传 当数据从主机 A 发送到主机 B 时,主机 B 会返回给主机 A 一个确认应答(ACK);发送端将数据发送出去后会等待对端的确认应答,如果有确认应答说明数据已经成功到达对端。在一定的时间内如果没有收到确认应答,发送端就认为数据已经丢失,并进行重发。由此,即使产生了丢失,仍然可以保证数据能够到达对端,实现可靠传输。
全双工通信 TCP 连接一旦建立,就可以在连接上进行双向的通信,任何一个主机都可以向另一个主机发送数据,数据是双向同时流通的。
基于字节流 将数据按字节大小进行编号,接收端通过 ACK 来确认收到的数据编号。通过这种机制能够保证 TCP 协议的有序性和完整性,因此 TCP 能够提供可靠性传输。
流量控制(滑动窗口协议) TCP 流量控制主要是针对接收端的处理速度不如发送端发送速度快的问题,消除发送方使接收方缓存溢出的可能性。TCP 流量控制主要使用滑动窗口协议,滑动窗口是接受数据端使用的窗口大小,用来告诉发送端接收端的缓存大小,以此可以控制发送端发送数据的大小,从而达到流量控制的目的。发送方在发送过程中始终保持着一个发送窗口,只有落在发送窗口内的帧才允许被发送;同时接收方也维持着一个接收窗口,只有落在接收窗口内的帧才允许接收。通过调整发送窗口和接收窗口的大小可以实现流量控制。
差错控制 TCP 协议除了确认应答与重传机制外,还会采用校验和(Checksum)的方式来检验数据的有效性。主机在接收数据时,会将重复的报文丢弃、将乱序的报文重组,发现某段报文丢失了会请求发送方进行重发。因此 TCP 往上层协议递交的数据是顺序的、无差错的完整数据
拥塞控制 如果网络上的负载(发送到网络上的分组数)大于网络上的容量(网络同时能处理的分组数),就可能引起拥塞。判断网络拥塞的两个因素:延时吞吐量。拥塞控制的机制分为开环(预防)和闭环(消除)。注意区别:流量控制是通过接收方来控制流量,而拥塞控制是通过发送方来控制流量。TCP 拥塞控制的几种方法:慢启动、拥塞避免、快重传和快恢复

TCP 报文格式

当数据由上层发送到传输层时,数据会被封装为 TCP 数据段(也称为 TCP 报文或 TCP 报文段),由 TCP 首部 + 数据区域 组成。一般 TCP 首部通常为 20 个字节大小(最大 60 字节),各字段如下:

字段 长度 说明
源端口号 / 目标端口号 各 2 字节(共 4 字节) 每个 TCP 报文都包含源主机和目标主机的端口号,用于寻找发送端和接收端应用进程。这两个值加上 IP 首部中的源 IP 和目标 IP 就能确定唯一一个 TCP 连接。有时一个 IP 地址和一个端口号也称为 socket(插口)
序号(Sequence Number) 4 字节 用来标识从 TCP 发送端向接收端发送的数据字节流,它的值表示这个报文段中的第一个数据字节所处位置码。在 TCP 传送的数据流中,每一个字节都有一个序号。例如,一报文段的序号为 300,且数据共 100 字节,则下一个报文段的序号就是 400。序号是 32bit 无符号数,到达 2³²−1 后从 0 开始。
确认序号(Acknowledge Number) 4 字节 期望收到对方下次发送的数据的第一个字节的序号,即期望收到的下一个报文段首部中的序号。确认序号 = 上次已成功收到数据字节序号 + 1。只有 ACK 标志为 1 时,确认序号才有效。由于 TCP 为全双工服务,确认序号通常会与反向数据封装在同一个报文中(即捎带),所以连接的每一端都必须保持每个方向上的传输数据序号准确性。
首部长度 4 bit 指出 TCP 报文段首部长度(以字节为单位),最大能记录 15×4 = 60 字节。该字段后还有 6bit 空间保留未用,现在置为 0。
6 个标志位 6 bit URG / ACK / PSH / RST / SYN / FIN,见下方详解。
窗口大小 2 字节 表示从确认号开始,本报文的发送方可以接收的字节数,即接收窗口大小,用于流量控制。
校验和 2 字节 对整个 TCP 报文段(包括 TCP 首部和 TCP 数据)以 16 位字进行计算所得。这是一个强制性的字段
紧急指针 2 字节 本报文段中紧急数据的最后一个字节的序号。只有当 URG 标志为 1 时该字段才有效。
选项 最多 40 字节 大小不确定,最多 40 字节。

img

6 个标志位详解

标志位 名称 作用
URG 紧急指针标志 为 1 时表示紧急指针字段有效。
ACK 确认标志 只有当 ACK=1 时,确认序号字段才有效。
PSH 推送标志 为 1 时接收方应该尽快将本报文段立即传送给其应用层。
RST 复位标志 为 1 时表示出现连接错误,必须释放连接,然后再重建传输连接。复位比特还用来拒绝一个不法的报文段或拒绝打开一个连接。
SYN 同步标志 SYN=1、ACK=0 时表示请求建立一个连接,携带 SYN 标志的 TCP 报文段为同步报文段。
FIN 结束标志 为 1 表示发送方没有数据要传输了,要求释放连接。

注意区分:小写 ack 是确认序号(Acknowledge number),大写 ACK 是标志位。

三次握手(建立连接)

三次握手是 TCP 建立连接的过程,由客户端主动发起,一般来说会经历以下过程:

① 第一次握手
客户端将 TCP 报文标志位 SYN 置为 1,随机产生一个序号值 seq=J,保存在 TCP 首部的序号字段里,指明客户端打算连接的服务器的端口,并将该数据包发送给服务器端。发送完毕后,客户端进入 SYN_SENT 状态,等待服务器端确认。

② 第二次握手
服务器端收到数据包后由标志位 SYN=1 知道客户端请求建立连接,服务器端将 TCP 报文标志位 SYN 和 ACK 都置为 1ack=J+1,随机产生一个序号值 seq=K,并将该数据包发送给客户端以确认连接请求。服务器端进入 SYN_RCVD 状态。

③ 第三次握手
客户端收到确认后,检查 ack 是否为 J+1、ACK 是否为 1,如果正确则将标志位 ACK 置为 1ack=K+1,并将该数据包发送给服务器端。服务器端检查 ack 是否为 K+1、ACK 是否为 1,如果正确则连接建立成功。客户端和服务器端进入 ESTABLISHED 状态,完成三次握手,随后双方可以开始传输数据了。

sequenceDiagram participant C as 客户端 participant S as 服务端 Note over C: CLOSED → SYN_SENT C->>S: ① SYN=1, seq=J Note over S: LISTEN → SYN_RCVD S->>C: ② SYN=1, ACK=1, seq=K, ack=J+1 Note over C: SYN_SENT → ESTABLISHED C->>S: ③ ACK=1, seq=J+1, ack=K+1 Note over S: SYN_RCVD → ESTABLISHED Note over C,S: 连接建立成功,开始传输数据

注意区分:小写 ack 代表的是头部的确认号(Acknowledge number);大写 ACK 则是 TCP 首部的标志位,用于标志 TCP 包是否对上一个包进行了确认操作,如果确认了,则把 ACK 标志位设置成 1。

在完成握手后,客户端与服务器就成功建立了连接,同时双方都得到了彼此的窗口大小、序列号等信息。在后续传输 TCP 报文段时,每个报文段首部的 SYN 标志都会被置 0,因为它只用于发起连接、同步序号。

为什么要三次握手?

  • 为了保证传输的安全可靠,让双方都确认对方能够正常收发
  • 类比:打电话时的互相确认 — "你能听到我吗?" / "我能听到你,你能听到我吗?" / "我能听到你"

四次挥手(关闭连接)

四次挥手(有些书也会称为四次握手)是指关闭 TCP 连接的过程。当通信双方不再需要传输数据时,需要经过四次挥手来断开连接。

由于 TCP 连接是全双工的,因此每个方向都必须要单独进行关闭。当一方完成数据发送任务后,发送一个 FIN 来终止这一方向的连接;收到一个 FIN 只是意味着这一方向上没有数据流动了(不会再收到数据),但在这个 TCP 连接上仍然能够发送数据,直到这一方向也发送了 FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭

挥手请求可以是客户端发起,也可以是服务端发起,下面以客户端发起为例:

① 第一次挥手
Client 端发起挥手请求,向 Server 端发出一个 FIN 报文段(FIN 标志位置为 1),主动进行关闭连接。此时 Client 端进入 FIN_WAIT_1 状态,表示 Client 端没有数据要发送给 Server 端了。

② 第二次挥手
Server 端收到了 Client 端发送的 FIN 报文段,向 Client 端返回一个 ACK 报文段(ACK 标志位置为 1,ack=seq+1)。Client 端进入 FIN_WAIT_2 状态,Server 端告诉 Client 端:"我确认并同意你的关闭请求"。

③ 第三次挥手
Server 端向 Client 端发送一个 FIN 报文段(FIN 标志位置为 1),请求关闭连接。Server 端进入 LAST_ACK 状态。

④ 第四次挥手
Client 端收到 Server 端发送的 FIN 报文段后,向 Server 端发送 ACK 报文段(ACK 标志位置为 1),然后 Client 端进入 TIME_WAIT 状态。Server 端收到 Client 端的 ACK 报文段以后,就关闭连接。此时,Client 端等待 2MSL 的时间后依然没有收到回复,则证明 Server 端已正常关闭,Client 端也可以关闭连接了。

sequenceDiagram participant C as 客户端 participant S as 服务端 Note over C: ESTABLISHED → FIN_WAIT_1 C->>S: ① FIN=1, seq=M Note over S: ESTABLISHED → CLOSE_WAIT S->>C: ② ACK=1, seq=M+1 Note over C: FIN_WAIT_1 → FIN_WAIT_2 Note over S: CLOSE_WAIT → LAST_ACK S->>C: ③ FIN=1, seq=N Note over C: FIN_WAIT_2 → TIME_WAIT C->>S: ④ ACK=1, seq=N+1 Note over S: LAST_ACK → CLOSED Note over C: 等待 2MSL 后 → CLOSED

为什么需要四次?
TCP 连接是全双工的,每个方向的关闭必须单独进行。收到一个 FIN 只意味着该方向上没有数据流动了,但另一个方向仍可以发送数据。所以主动关闭方发送 FIN 后,被动关闭方先回复 ACK,等自己也没数据要发了再发送 FIN,一来一回就是四次。

TCP 状态说明

状态 说明
CLOSED 初始状态
LISTENING 服务器端 Socket 处于监听状态,等待客户端连接
SYN_SENT 客户端已发送 SYN 报文,等待服务器确认
SYN_RCVD 服务器收到 SYN 报文,处于三次握手中间状态(很短暂)
ESTABLISHED 连接已建立,可以正常传输数据
FIN_WAIT_1 主动关闭方发送 FIN 后进入该状态
FIN_WAIT_2 收到对方对 FIN 的 ACK 后进入该状态
TIME_WAIT 收到对方 FIN 并发送 ACK 后进入,等待 2MSL 后进入 CLOSED
CLOSE_WAIT 被动关闭方收到 FIN 并回复 ACK 后进入,等待自身关闭连接
LAST_ACK 被动关闭方发送 FIN 后进入,等待对方 ACK

UDP 协议(补充)

UDP(User Datagram Protocol,用户数据报协议)是传输层的无连接、不可靠协议。

对比项 TCP UDP
连接性 面向连接(需三次握手) 无连接
可靠性 可靠传输(确认+重传) 不可靠(尽力交付)
数据方式 面向字节流 面向报文
速度 较慢(需握手、确认等机制) 较快
流量控制 有(滑动窗口)
适用场景 文件传输、网页浏览等需要可靠传输的场景 直播、网络电话等实时性要求高、可容忍丢包的场景

端口号的概念

端口号是一个数字编号,用于在一台主机中唯一标识一个能进行网络通信的进程。

项目 说明
取值范围 0 ~ 65535
作用 通过"IP 地址 + 端口号"唯一确定主机上的一个网络进程
类比 IP 地址 = 宿舍楼地址,端口号 = 房间号

常见服务的默认端口号

服务 端口号 协议/说明
HTTP 80 超文本传输协议
FTP 21 文件传输协议
SMTP 25 简单邮件传输协议
TFTP 69 简单文件传输协议
SSH 22 安全外壳协议(远程登录)
Telnet 23 终端远程登录协议
POP3 110 邮局协议版本 3
posted @ 2026-07-21 18:56  Javenwww  阅读(1)  评论(0)    收藏  举报