首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【嵌入式Linux应用开发基础】网络编程(2):TCP协议

【嵌入式Linux应用开发基础】网络编程(2):TCP协议

作者头像
byte轻骑兵
发布2026-01-21 15:39:59
发布2026-01-21 15:39:59
1300
举报

TCP(Transmission Control Protocol,传输控制协议)是互联网中的一种面向连接的、可靠的、基于字节流的传输层通信协议。在嵌入式Linux应用开发中,网络编程是重要的一环,而TCP协议则是实现网络通信的基础之一。

一、TCP 协议概述

TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议,在嵌入式 Linux 应用开发的网络编程中起着至关重要的作用。它确保数据在网络中的可靠传输,适用于对数据准确性要求较高的场景,如文件传输、电子邮件、网页浏览等。

二、TCP 协议特点

  • 面向连接:在使用TCP协议进行通信之前,必须先建立TCP连接。这种连接是全双工的,即通信双方可以同时发送和接收数据。
  • 可靠性:TCP提供可靠交付的服务。通过TCP连接传送的数据,无差错、不丢失、不重复,并且按序到达。如果数据包丢失或出现差错,则TCP负责重发数据。
  • 有序性:TCP能够把发送的数据划分成一个个数据块,编号后发送,接收方根据编号将这些数据块组装成完整的数据。因此,在接收端可以确保数据块按照发送的顺序进行组装。
  • 流量控制:TCP提供了流量控制的功能,保证发送方的发送速度不会过快,导致接收方处理不及时,从而导致数据丢失。发送方会根据接收方返回的确认信息,调整自己的发送速度。
  • 拥塞控制:TCP能够根据网络状况调整传输数据的速率,防止出现拥塞。如果网络出现拥塞,TCP会通过降低发送方的数据传输速率和进行重传等措施来保证数据的可靠传输。

三、TCP协议的数据传输流程

TCP协议的数据传输流程包括连接建立、数据传输和连接终止三个阶段。

3.1. 连接建立(三次握手)

  • 第一步客户端发起连接请求。客户端向服务器发送一个 SYN 包,其中 Seq=x 表示客户端的初始序列号 x,这个包用于请求建立连接。
  • 第二步服务器返回确认信号。服务器收到客户端的 SYN 包后,向客户端发送一个 SYN + ACK 包。Seq=y 是服务器的初始序列号,Ack=x + 1 表示服务器确认收到了客户端序列号为 xSYN 包,期望下一个收到的序列号是 x + 1
  • 第三步连接建立成功。客户端收到服务器的 SYN + ACK 包后,向服务器发送一个 ACK 包。Seq=x + 1 表示客户端的下一个序列号,Ack=y + 1 表示客户端确认收到了服务器序列号为 ySYN 包,期望下一个收到的序列号是 y + 1。此时,连接建立成功。

3.2. 数据传输

  • 客户端和服务器之间可以进行多次数据传输。客户端向服务器发送数据段,包含序列号 Seq=X1 和确认号 Ack=Y1
  • 服务器收到数据段后,向客户端发送 ACK 确认包,包含自己的序列号 Seq=Y2 和确认号 Ack=X2,表示确认收到了客户端序列号为 X1 的数据段,期望下一个收到的序列号是 X2。这个过程会根据实际需要循环多次。
  • 同时,TCP还会进行数据的可靠性检测,如果发现某个数据包没有被接收方正确接收,则会进行重传。

3.3. 连接释放(四次挥手)

  • 第一步客户端向服务器发送连接释放请求。客户端向服务器发送一个 FIN 包,Seq=X3Ack=Y3 表示客户端希望关闭连接,同时包含当前的序列号和确认号。
  • 第二步服务器发送确认信号。服务器收到客户端的 FIN 包后,向客户端发送一个 ACK 包,Seq=Y4Ack=X4 表示确认收到客户端的关闭请求。
  • 第三步服务器向客户端发送连接释放请求。服务器向客户端发送一个 FIN 包,Seq=Y5Ack=X5 表示服务器也希望关闭连接。
  • 第四步客户端发送确认信号。客户端收到服务器的 FIN 包后,向服务器发送一个 ACK 包,Seq=X6Ack=Y6 表示确认收到服务器的关闭请求。此时,连接释放完成。

四、嵌入式Linux下的TCP网络编程

4.1. 服务器端开发流程

  1. 创建 Socket:使用socket()函数创建一个 TCP 套接字。
  2. 绑定地址和端口:使用bind()函数将套接字绑定到指定的 IP 地址和端口号。
  3. 监听连接:使用listen()函数开始监听客户端的连接请求。
  4. 接受连接:使用accept()函数接受客户端的连接请求,并返回一个新的套接字用于与客户端通信。
  5. 数据传输:使用read()write()函数在新的套接字上进行数据的读写操作。
  6. 关闭连接:使用close()函数关闭套接字,释放资源。

4.2. 客户端开发流程

  1. 创建 Socket:使用socket()函数创建一个 TCP 套接字。
  2. 连接服务器:使用connect()函数连接到服务器的指定 IP 地址和端口号。
  3. 数据传输:使用read()write()函数在套接字上进行数据的读写操作。
  4. 关闭连接:使用close()函数关闭套接字,释放资源。

4.3. 示例代码

服务器端代码:

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#define PORT 8888

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};
    const char *hello = "Hello from server";

    // 创建socket文件描述符
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 设置socket选项
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    // 绑定socket到指定地址和端口
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    // 监听连接
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }
    // 接受连接
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }
    // 读取客户端发送的数据
    read(new_socket, buffer, 1024);
    printf("Client: %s\n", buffer);
    // 发送响应数据给客户端
    send(new_socket, hello, strlen(hello), 0);
    printf("Hello message sent\n");
    // 关闭连接
    close(new_socket);
    close(server_fd);
    return 0;
}

首先创建一个 TCP 套接字,然后将其绑定到本地的指定端口并开始监听客户端连接。当有客户端连接时,接受连接并读取客户端发送的数据,最后发送响应数据给客户端,完成通信后关闭套接字。

客户端代码:

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>

#define PORT 8888

int main() {
    int sock = 0;
    struct sockaddr_in serv_addr;
    char *hello = "Hello from client";
    char buffer[1024] = {0};

    // 创建socket文件描述符
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket creation error");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    // 将IPv4地址从文本转换为二进制形式
    if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
        perror("Invalid address/ Address not supported");
        return -1;
    }
    // 连接到服务器
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("Connection Failed");
        return -1;
    }
    // 发送数据到服务器
    send(sock, hello, strlen(hello), 0);
    printf("Hello message sent\n");
    // 读取服务器响应数据
    read(sock, buffer, 1024);
    printf("Server: %s\n", buffer);
    // 关闭连接
    close(sock);
    return 0;
}

创建一个 TCP 套接字,连接到服务器的指定 IP 地址和端口,发送数据给服务器,读取服务器的响应数据,最后关闭套接字。

五、TCP 协议的性能优化

5.1. 网络层面优化

①调整 TCP 参数

  • 窗口大小:TCP 窗口大小决定了发送方可以连续发送的数据量。增大窗口大小能减少等待确认的时间,提高数据传输效率。在 Linux 系统中,可以通过修改 /proc/sys/net/ipv4/tcp_window_scaling 来启用窗口缩放选项,同时调整 /proc/sys/net/ipv4/tcp_rmem/proc/sys/net/ipv4/tcp_wmem 分别设置接收和发送窗口的大小范围。
  • 超时重传时间:合理设置超时重传时间(RTO)很重要。如果 RTO 过短,会导致不必要的重传;如果过长,会增加数据传输的延迟。Linux 系统中可以通过 /proc/sys/net/ipv4/tcp_retries1/proc/sys/net/ipv4/tcp_retries2 来调整重传次数和重传间隔。

②优化网络拓扑

  • 减少网络跳数,缩短数据传输路径,降低延迟和丢包率。例如,在企业网络中合理规划路由器和交换机的部署,避免数据绕路传输。
  • 采用高速稳定的网络设备,如高性能的网卡、交换机等,提高网络带宽和可靠性。

5.2. 应用层面优化

①批量数据传输

  • 将小数据块合并成大数据块进行传输,减少 TCP 协议头的开销。例如,在文件传输应用中,可以将多个小文件打包成一个大文件进行传输。
  • 使用缓冲技术,在应用程序中设置缓冲区,当缓冲区满或者达到一定时间间隔时再进行数据发送。

②异步 I/O 操作

  • 采用异步 I/O 模型,如 Linux 下的 epoll 机制,使应用程序在等待数据读写时可以同时处理其他任务,提高并发处理能力。在高并发的服务器应用中,使用 epoll 可以显著提升性能。

③多线程或多进程处理

  • 对于服务器端应用,可以使用多线程或多进程来处理多个客户端连接。每个线程或进程负责一个或多个客户端的请求,避免单个线程或进程处理过多连接导致性能瓶颈。例如,Web 服务器可以为每个客户端请求分配一个线程来处理。

5.3. 协议层面优化

  • TCP 快速打开(TFO):TFO 允许在 TCP 连接建立的同时发送数据,减少了三次握手的延迟。在支持 TFO 的系统中,客户端和服务器可以通过交换 TFO 密钥来实现快速打开连接。
  • 选择性确认(SACK):SACK 允许接收方告知发送方哪些数据块已经正确接收,发送方可以只重传丢失的数据块,而不是从丢失点开始全部重传,提高了重传效率。在 Linux 系统中,SACK 是默认启用的。

5.4. TCP协议性能优化技术矩阵

优化方向

关键技术

嵌入式实现方法

适用场景

连接建立

TCP Fast Open (TFO)

setsockopt(fd, SOL_TCP, TCP_FASTOPEN, &enable, sizeof(enable))

高频短连接(如HTTP API)

传输效率

Zero-Copy传输

sendfile(sockfd, file_fd, &offset, filesize)

OTA固件升级

拥塞控制

BBR算法

setsockopt(fd, SOL_TCP, TCP_CONGESTION, "bbr", 3)

高延迟网络(5G车载通信)

内存管理

动态缓冲区调整

setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize))

内存受限设备

可靠性

选择性确认(SACK)

echo 1 > /proc/sys/net/ipv4/tcp_sack

高丢包率网络(工业现场)

实时性

禁用Nagle算法

int flag = 1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int))

实时控制指令传输

连接复用

Keep-Alive机制

setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepalive_time, sizeof(int))

长期连接的IoT设备

六、TCP 协议的典型应用场景

6.1. 文件传输

  • FTP(文件传输协议):FTP 是基于 TCP 协议的标准文件传输协议,广泛用于在不同计算机之间传输文件。由于 TCP 协议的可靠性,能够确保文件在传输过程中不丢失、不损坏,保证了文件的完整性。
  • HTTP 文件下载:在 Web 应用中,用户通过浏览器下载文件时,通常使用 HTTP 协议。HTTP 是基于 TCP 协议的应用层协议,利用 TCP 的可靠传输特性,确保文件能够完整地下载到本地。

6.2. 电子邮件

  • SMTP(简单邮件传输协议):SMTP 用于发送电子邮件,它基于 TCP 协议,保证了邮件在发送过程中的可靠传输,确保邮件能够准确无误地到达收件人的邮件服务器。
  • POP3(邮局协议版本 3)和 IMAP(互联网消息访问协议):这两个协议用于接收电子邮件,同样基于 TCP 协议,确保收件人能够完整地获取邮件内容。

6.3. 远程登录和管理

  • Telnet:早期的远程登录协议,通过 TCP 协议建立远程连接,允许用户在本地计算机上登录到远程服务器并执行命令。但由于 Telnet 是明文传输,存在安全风险,现在逐渐被 SSH 取代。
  • SSH(安全外壳协议):SSH 是一种安全的远程登录和管理协议,基于 TCP 协议,使用加密技术对数据进行加密传输,保证了远程登录过程中的安全性和数据完整性。

6.4. 数据库访问

  • 许多数据库管理系统,如 MySQL、Oracle 等,使用 TCP 协议进行客户端与服务器之间的通信。TCP 的可靠性确保了数据库操作(如查询、插入、更新等)的准确执行,避免数据丢失或损坏。

6.5. 实时通信(部分场景)

  • 虽然 TCP 协议存在一定的延迟,但在一些对实时性要求不是特别高的实时通信场景中仍然被广泛使用。例如,即时通讯软件中的文字消息传输,由于 TCP 的可靠性,能够保证消息准确无误地送达对方。

七、深度优化技术解析

7.1. 零拷贝技术栈

代码语言:javascript
复制
应用层数据  -> 用户态缓冲区  -> 内核缓冲区  -> 网卡DMA
          ↓               ↓
          应用层直接操作硬件 (DPDK)

嵌入式实现

  • 小数据包:使用io_uring异步IO
  • 文件传输:sendfile()
  • 自定义协议:splice()+vmsplice()

7.2. 内存优化策略

代码语言:javascript
复制
// 预分配内存池管理
#define POOL_SIZE 32
struct {
    uint8_t buffer[1500];  // MTU大小
    uint16_t len;
    bool used;
} packet_pool[POOL_SIZE];

// 获取内存块时进行边界检查
uint8_t* alloc_buffer() {
    for(int i=0; i<POOL_SIZE; i++) {
        if(!packet_pool[i].used) {
            packet_pool[i].used = true;
            return packet_pool[i].buffer;
        }
    }
    return NULL;  // 内存耗尽处理
}

7.3. 实时性保障方案

代码语言:javascript
复制
普通Linux内核          vs         实时化改造
--------------------------     ----------------------
| 应用进程             |         |  Xenomai实时域   |
| 普通网络协议栈       |         |  实时网络驱动     |
| 通用中断处理         |         |  低延迟中断路由   |
--------------------------     ----------------------
            平均延迟1-5ms                  <200μs

实现方法

  • 使用RT-Preempt补丁
  • 关键网络线程设置为FIFO调度策略
  • 绑定CPU核心减少上下文切换

八、调试与监控工具箱

8.1. 网络质量分析

代码语言:javascript
复制
# 测量TCP吞吐量
iperf3 -c 192.168.1.100 -t 30 -J > report.json

# 时延抖动检测
ping -D 192.168.1.100 | awk '{print $1,$7}' | tsconv

8.2. 内核状态监控

代码语言:javascript
复制
# 实时查看TCP重传率
watch -n 1 "grep 'TcpRetransSegs' /proc/net/netstat"

# 内存使用监控
cat /proc/net/sockstat | grep "TCP"

8.3. 离线分析工具链

代码语言:javascript
复制
Wireshark捕获 -> 导出CSV -> Python分析脚本 -> Grafana可视化
                  ↓
              故障模式识别(重传风暴、窗口冻结等)

九、常见问题排查表

现象

可能原因

解决方案

连接超时

防火墙阻挡/路由问题

使用traceroute检查网络路径

数据传输不完整

未处理粘包问题

添加协议头长度字段

系统频繁重启

网络阻塞导致看门狗超时

在select()循环中增加喂狗点

内存持续增长

Socket未关闭导致泄漏

使用valgrind --leak-check=yes检测

十、参考资料

  • 《TCP/IP 详解 卷 1:协议》:作者是 W. Richard Stevens。这本书是 TCP/IP 协议方面的经典之作,详细介绍了 TCP/IP 协议族的各个协议,包括网络层的 IP 协议、传输层的 TCP 和 UDP 协议等,对理解 TCP/IP 协议栈的工作原理有很大帮助。
  • 《嵌入式 Linux 应用开发完全手册》:作者是韦东山。书中有关于嵌入式 Linux 网络编程的章节,介绍了 Socket 编程、TCP/IP 协议等基础知识,并结合实际案例讲解了在嵌入式 Linux 环境下如何进行网络应用开发,帮助读者快速上手嵌入式 Linux 网络编程。
  • 嵌入式 Linux 应用程序开发 - (7) TCP - IP 网络通信应用程序 (TCP - Client):该 CSDN 博客文章从嵌入式 QT 环境下 TCP/IP 客户端开发的角度,介绍了 TCP/IP 协议在嵌入式 Linux 中的应用,包括客户端开发的步骤、相关函数和类的使用等,通过实际案例帮助读者理解如何在嵌入式 Linux 中进行 TCP/IP 网络通信应用程序的开发。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-05-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、TCP 协议概述
  • 二、TCP 协议特点
  • 三、TCP协议的数据传输流程
    • 3.1. 连接建立(三次握手)
    • 3.2. 数据传输
    • 3.3. 连接释放(四次挥手)
  • 四、嵌入式Linux下的TCP网络编程
    • 4.1. 服务器端开发流程
    • 4.2. 客户端开发流程
    • 4.3. 示例代码
  • 五、TCP 协议的性能优化
    • 5.1. 网络层面优化
    • 5.2. 应用层面优化
    • 5.3. 协议层面优化
    • 5.4. TCP协议性能优化技术矩阵
  • 六、TCP 协议的典型应用场景
    • 6.1. 文件传输
    • 6.2. 电子邮件
    • 6.3. 远程登录和管理
    • 6.4. 数据库访问
    • 6.5. 实时通信(部分场景)
  • 七、深度优化技术解析
    • 7.1. 零拷贝技术栈
    • 7.2. 内存优化策略
    • 7.3. 实时性保障方案
  • 八、调试与监控工具箱
    • 8.1. 网络质量分析
    • 8.2. 内核状态监控
    • 8.3. 离线分析工具链
  • 九、常见问题排查表
  • 十、参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档