基于C语言的TCP通信测试程序开发指南

news2025/5/11 19:32:20

一、TCP通信基础原理

1.1 通信流程概述

TCP通信采用客户端-服务器模型,核心流程如下:

服务器端:

  1. 创建套接字(Socket)

  2. 绑定地址和端口(Bind)

  3. 开始监听(Listen)

  4. 接受连接(Accept)

  5. 数据交互(Send/Recv)

  6. 关闭连接(Close)

客户端:

  1. 创建套接字(Socket)

  2. 连接服务器(Connect)

  3. 数据交互(Send/Recv)

  4. 关闭连接(Close)

1.2 网络字节序

使用htonl()htons()等函数处理端口和地址转换,保证不同架构设备间的兼容性。


二、服务器端实现

2.1 完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int server_fd, client_fd;
    struct sockaddr_in address;
    int opt = 1;
    socklen_t addrlen = sizeof(address);
    char buffer[BUFFER_SIZE];

    // 创建TCP套接字
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 设置套接字选项
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &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);

    // 绑定地址
    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);
    }
    printf("Server listening on port %d...\n", PORT);

    // 接受连接
    if ((client_fd = accept(server_fd, (struct sockaddr*)&address, &addrlen)) < 0) {
        perror("accept");
        exit(EXIT_FAILURE);
    }

    // 接收数据
    ssize_t bytes_read = recv(client_fd, buffer, BUFFER_SIZE, 0);
    if (bytes_read > 0) {
        buffer[bytes_read] = '\0';
        printf("Received: %s\n", buffer);
        
        // 发送响应
        const char* response = "Message received";
        send(client_fd, response, strlen(response), 0);
    }

    close(client_fd);
    close(server_fd);
    return 0;
}

2.2 关键代码解析

  1. 套接字创建

    socket(AF_INET, SOCK_STREAM, 0)
    • AF_INET:IPv4协议

    • SOCK_STREAM:TCP协议类型

  2. 地址重用选项

    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))

    避免"Address already in use"错误

  3. 绑定地址

    bind(server_fd, (struct sockaddr*)&address, sizeof(address))
    • INADDR_ANY 表示绑定所有网络接口


三、客户端实现

3.1 完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define SERVER_IP "127.0.0.1"
#define PORT 8080
#define BUFFER_SIZE 1024

int main() {
    int sock;
    struct sockaddr_in serv_addr;
    char buffer[BUFFER_SIZE];

    // 创建套接字
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

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

    // 转换IP地址
    if (inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr) <= 0) {
        perror("invalid address");
        exit(EXIT_FAILURE);
    }

    // 连接服务器
    if (connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
        perror("connection failed");
        exit(EXIT_FAILURE);
    }

    // 发送数据
    const char* message = "Hello Server!";
    send(sock, message, strlen(message), 0);
    printf("Sent: %s\n", message);

    // 接收响应
    ssize_t bytes_received = recv(sock, buffer, BUFFER_SIZE, 0);
    if (bytes_received > 0) {
        buffer[bytes_received] = '\0';
        printf("Response: %s\n", buffer);
    }

    close(sock);
    return 0;
}

3.2 关键代码解析

  1. 地址转换

    inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr)

    将点分十进制IP转换为二进制格式

  2. 连接超时处理
    实际项目中建议添加超时设置:

    struct timeval timeout = {5, 0}; // 5秒超时
    setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));

四、编译与测试

4.1 编译方法

# 编译服务器
gcc server.c -o server

# 编译客户端
gcc client.c -o client

4.2 运行测试

# 服务器端
./server

# 客户端(另启终端)
./client

4.3 预期输出

服务器端:

Server listening on port 8080...
Received: Hello Server!

客户端:

Sent: Hello Server!
Response: Message received

五、进阶开发指南

5.1 多客户端支持

使用多线程处理并发连接:

#include <pthread.h>

void* client_handler(void* arg) {
    int client_fd = *(int*)arg;
    // 处理客户端请求
    close(client_fd);
    pthread_exit(NULL);
}

// 在accept循环中
while(1) {
    int client_fd = accept(...);
    pthread_t thread;
    pthread_create(&thread, NULL, client_handler, &client_fd);
    pthread_detach(thread);
}

5.2 数据完整性保障

  1. 添加包头校验:

struct packet_header {
    uint32_t magic;     // 固定标识 0xDEADBEEF
    uint32_t length;    // 数据长度
    uint16_t checksum;  // CRC校验
};
  1. 使用循环接收确保完整数据:

size_t total_received = 0;
while(total_received < expected_len) {
    ssize_t n = recv(fd, buffer+total_received, expected_len-total_received, 0);
    if(n <= 0) break;
    total_received += n;
}

5.3 性能优化技巧

  1. 禁用Nagle算法:

int flag = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int));
  1. 调整缓冲区大小:

int buf_size = 1024 * 1024; // 1MB
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &buf_size, sizeof(int));

六、常见问题排查

问题现象可能原因解决方案
Connection refused服务器未启动/端口未开放检查服务状态和防火墙设置
Address already in use端口被占用设置SO_REUSEADDR选项
数据不完整未处理部分发送/接收使用循环发送接收逻辑
连接超时网络不通/服务器无响应使用telnet测试端口连通性
数据乱码未正确处理字符串终止符确保接收缓冲区添加'\0'

七、扩展应用场景

  1. 文件传输工具:实现文件分块传输和校验

  2. 即时通讯系统:支持多用户文本消息传递

  3. 远程监控系统:实时传输传感器数据

  4. 分布式计算节点:任务分配与结果收集

通过本指南,开发者可以快速搭建基础的TCP通信测试环境,并根据实际需求进行功能扩展。建议结合Wireshark等网络分析工具进行协议级调试,以深入理解TCP通信机制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2373372.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

教育系统源码如何支持白板直播与刷题功能?功能开发与优化探索

很多行业内同学疑问&#xff0c;如何在教育系统源码中支持白板直播和刷题功能&#xff1f;本篇文章&#xff0c;小编将从功能设计、技术实现到性能优化&#xff0c;带你全面了解这个过程。 一、白板直播功能的核心需求与技术挑战 实时交互与同步性 白板直播的核心是“实时性”。…

再度深入理解PLC的输入输出接线

本文再次重新梳理&#xff1a; 两线式/三线式传感器的原理及接线、PLC的输入和输出接线&#xff0c;深入其内部原理&#xff0c;按照自己熟悉的方式去理解该知识 在此之前&#xff0c;需要先统一几个基础知识点&#xff1a; 在看任何电路的时候&#xff0c;需要有高低电压差&…

k8s(11) — 探针和钩子

钩子和探针的区别&#xff1a; 在 Kubernetes&#xff08;k8s&#xff09;中&#xff0c;钩子&#xff08;Hooks&#xff09;和探针&#xff08;Probes&#xff09;是保障应用稳定运行的重要机制&#xff0c;不过它们的用途和工作方式存在差异&#xff0c;以下为你详细介绍&…

使用jmeter对数据库进行压力测试

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 前言 很多人提到 jmeter时&#xff0c;只会说到jmeter进行接口自动化或接口性能测试&#xff0c;其实jmeter还能对数据库进行自动化操作。个人常用的场景有以下&…

Kubernetes生产实战(十四):Secret高级使用模式与安全实践指南

一、Secret核心类型解析 类型使用场景自动管理机制典型字段Opaque (默认)自定义敏感数据需手动创建data字段存储键值对kubernetes.io/dockerconfigjson私有镜像仓库认证kubelet自动更新.dockerconfigjsonkubernetes.io/tlsTLS证书管理Cert-Manager可自动化tls.crt/tls.keykube…

05 mysql之DDL

一、SQL的四个分类 我们通常可以将 SQL 分为四类&#xff0c;分别是&#xff1a; DDL&#xff08;数据定义语言&#xff09;、DML&#xff08;数据操作语言&#xff09;、 DCL&#xff08;数据控制语言&#xff09;和 TCL&#xff08;事务控制语言&#xff09;。 DDL 用于创建…

电池热管理CFD解决方案,为新能源汽车筑安全防线

在全球能源结构加速转型的大背景下&#xff0c;新能源汽车产业异军突起&#xff0c;成为可持续发展的重要驱动力。而作为新能源汽车 “心脏” 的电池系统&#xff0c;其热管理技术的优劣&#xff0c;直接决定了车辆的安全性、续航里程和使用寿命。电池在充放电过程中会产生大量…

TransmittableThreadLocal:穿透线程边界的上下文传递艺术

文章目录 前言一、如何线程上下文传递1.1 ThreadLocal单线程1.2 InheritableThreadLocal的继承困境1.3 TTL的时空折叠术 二、TTL核心设计解析2.1 时空快照机制2.2 装饰器模式2.3 采用自动清理机制 三、设计思想启示四、实践启示录结语 前言 在并发编程领域&#xff0c;线程上下…

基于STM32的甲醛检测

一、制作目标 以正点原子的miniSTM32F103RCT6开发板为主控&#xff0c;使用甲醛传感器检测环境空气中的甲醛含量&#xff08;以mg/m^3为单位&#xff09;、C02含量&#xff08;以ppm为单位&#xff09;和总有机挥发物含量TVOC&#xff08;以mg/m^3为单位&#xff09;在OLED显示…

洛图报告中的 FSHD 是什么?—— 解密九天画芯推动的三色光源显示技术

目录 一、洛图报告新焦点&#xff1a;FSHD 为何成为显示产业重要突破方向&#xff1f; &#xff08;一&#xff09;洛图报告核心结论&#xff1a;从技术突围到产业重构 二、技术解析&#xff1a;FSHD 如何重构显示底层逻辑&#xff1f; &#xff08;一&#xff09;物理架构…

【MySQL】事务(重点)

目录 一、什么是事务&#xff1a; 二、事务的前置知识了解 引擎是否支持事务 事务的提交方式 事务操作的前置准备&#xff1a; 三、事务回滚&#xff1a; 四、事务崩溃&#xff1a; 原子性&#xff1a; 持久性&#xff1a; 五、自动提交和手动提交&#xff1a; 六、…

Linux:线程同步与互斥

目录 线程互斥 锁 初始化 销毁 加锁 解锁 线程同步 条件变量 初始化 销毁 等待条件满足 唤醒等待 pthread_cond_signal pthread_cond_broadcast 生产者消费者模型 3种关系 2种角色 1个交易场所 POSIX信号量 初始化 销毁 等待 发布 线程互斥 互斥相关…

每天五分钟机器学习:拉格朗日对偶函数

本文重点 在数学优化领域,拉格朗日对偶函数作为连接原始约束问题与对偶问题的核心纽带,展现了将复杂约束优化转化为无约束优化的方式。 数学表达 原始问题建模 拉格朗日函数构造 此时的目标就是: 先假设w为常数,让拉格朗日函数对橙子变量λ求极大值,消掉λ之后,在对λ求…

AutoGen 框架解析:微软开源的多人 Agent 协作新范式

一、引言 在大语言模型&#xff08;LLM&#xff09;快速发展的今天&#xff0c;复杂任务的自动化协作需求日益增长。微软开源的AutoGen 框架&#xff08;GitHub Star 超 10 万&#xff09;提供了一种基于多智能体对话的协作范式&#xff0c;通过自然语言交互实现多角色 Agent …

【bibtex4word】在Word中高效转换bib参考文献,Texlive环境安装bibtex4word插件

前言 现已退出科研界&#xff0c;本人水货一个。希望帮到有缘人 本篇关于如何将latex环境中的参考文献bib文件转化为word&#xff0c;和一些踩坑记录。 可以看下面的资料进行配置&#xff0c;后面的文字是这些资料的补充说明。 参考文章&#xff1a;https://blog.csdn.net/g…

单片机-STM32部分:10-2、逻辑分析仪

飞书文档https://x509p6c8to.feishu.cn/wiki/VrdkwVzOnifH8xktu3Bcuc4Enie 安装包如下&#xff1a;根据自己的系统选择&#xff0c;目前这个工具只有window版本哦 安装方法比较简单&#xff0c;都按默认下一步即可&#xff0c;注意不要安装到中文路径哦。 其余部分参考飞书文档…

计算机网络基础科普

IP地址是计算机网络中标识设备的唯一地址 IPv4&#xff08;32位&#xff09;IPv6&#xff08;128位&#xff09; 1.IPv4&#xff08;32位&#xff09; 简介&#xff1a;IPv4&#xff08;Internet Protocol version 4&#xff09;是互联网协议&#xff08;IP&#xff09;的…

阿里云CDN的源站配置:权重的详解

在阿里云CDN中为静态资源域名cdn.example.com配置源站时&#xff0c;权重设置需根据实际架构和目标灵活调整。以下是具体建议和配置步骤&#xff1a; 一、权重的核心作用 在阿里云CDN中&#xff0c;源站权重用于控制多个源站之间的流量分配比例&#xff0c;适用于以下场景&…

虚幻引擎5-Unreal Engine笔记之显卡环境设置使开发流畅

虚幻引擎5-Unreal Engine笔记之显卡环境设置使开发流畅 code review! 文章目录 虚幻引擎5-Unreal Engine笔记之显卡环境设置使开发流畅1.电源管理2.显卡优先设置3.拯救者支持FnQ性能模式切换&#xff0c;建议开发前切至“野兽模式”或高性能模式。4.NVIDIA 驱动设置5.VS2022中…

【Linux】冯诺依曼体系结构和操作系统的理解

目录 冯诺依曼体系结构一个例子来深入理解 初识操作系统操作系统的作用设计操作系统的目的操作系统之上和之下分别有啥 管理的精髓&#xff0c;先描述&#xff0c;再组织 冯诺依曼体系结构 我们知道&#xff0c;计算机这个东西发明出来就是帮助人们快速解决问题的。那如果我们想…