首页 > 其他分享 >20240815有名管道双端线程通信

20240815有名管道双端线程通信

时间:2024-08-15 19:56:01浏览次数:13  
标签:线程 管道 ret 端线 20240815 fd pthread PATH buf

//端1
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <signal.h>

#define TINGYU_PATH "/home/ubuntu/youan/tingyu_fifo" // 定义管道1的路径
#define YOUAN_PATH "/home/ubuntu/youan/youan_fifo"   // 定义管道2的路径

// 定义全局变量
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; // 互斥锁

// 线程函数声明
void* send_thread(void* arg);
void* recv_thread(void* arg);
void cleanup(int sig); // 清理函数声明

int tingyu_fd, youan_fd;  // 全局文件描述符

int main() {
    int ret;
    pthread_t send_tid, recv_tid; // 发送和接收线程的标识符

    // 设置信号处理程序
    signal(SIGINT, cleanup);

    // 创建管道1
    ret = mkfifo(TINGYU_PATH, 0777);
    if (ret < 0 && errno != EEXIST) {
        perror("mkfifo TINGYU_PATH failed"); // 创建失败,打印错误信息
        return -1;
    }

    // 创建管道2
    ret = mkfifo(YOUAN_PATH, 0777);
    if (ret < 0 && errno != EEXIST)
    {
        perror("mkfifo YOUAN_PATH failed"); // 创建失败,打印错误信息
        return -1;
    }

    // 打开管道1用于读取(从接收端接收数据)
    tingyu_fd = open(TINGYU_PATH, O_RDONLY | O_NONBLOCK);
    if (tingyu_fd < 0) {
        perror("open TINGYU_PATH failed"); // 打开失败,打印错误信息
        return -1;
    }

    // 打开管道2用于写入(向接收端发送数据)
    youan_fd = open(YOUAN_PATH, O_WRONLY);
    if (youan_fd < 0) {
        perror("open YOUAN_PATH failed"); // 打开失败,打印错误信息
        close(tingyu_fd); // 关闭管道1的文件描述符
        return -1;
    }

    // 创建发送线程
    ret = pthread_create(&send_tid, NULL, send_thread, (void*)&youan_fd);
    if (ret) 
    {
        perror("pthread_create send_tid failed"); // 创建线程失败,打印错误信息
        close(tingyu_fd);
        close(youan_fd);
        return -1;
    }

    // 创建接收线程
    ret = pthread_create(&recv_tid, NULL, recv_thread, (void*)&tingyu_fd);
    if (ret) {
        perror("pthread_create recv_tid failed"); // 创建线程失败,打印错误信息
        close(tingyu_fd);
        close(youan_fd);
        return -1;
    }

    // 等待线程结束
    pthread_join(send_tid, NULL);
    pthread_join(recv_tid, NULL);

    // 关闭文件描述符
    close(tingyu_fd);
    close(youan_fd);

    // 删除管道文件
    unlink(TINGYU_PATH);
    unlink(YOUAN_PATH);
    //销毁互斥
    pthread_mutex_destroy(&lock);

    return 0;
}

// 发送线程函数
void* send_thread(void* arg)
{
    int pipefd = *(int*)arg; // 获取管道文件描述符
    char buf[1024]; // 缓冲区
    ssize_t ret;

    printf("发送线程启动\n"); // 打印发送线程启动信息

    while (1) 
    {
        printf("输入要发送的消息:"); // 提示用户输入信息
        if (fgets(buf, sizeof(buf), stdin) == NULL) 
        { // 读取用户输入
            perror("fgets failed"); // 输入失败,打印错误信息
            break;
        }
       buf[strcspn(buf, "\n")] = '\0'; // 去掉换行符
      // getchar(); // 读取回车键
        pthread_mutex_lock(&lock); // 加锁
        ret = write(pipefd, buf, strlen(buf)); // 写入管道
        pthread_mutex_unlock(&lock); // 解锁
        if (ret < 0) 
        {
            perror("write to pipe failed"); // 写入失败,打印错误信息
            break;
        }
    }

    printf("发送线程结束\n"); // 打印发送线程结束信息
 
    return NULL;
}

// 接收线程函数
void* recv_thread(void* arg)
{
    int pipefd = *(int*)arg; // 获取管道文件描述符
    char buf[1024]; // 缓冲区
    ssize_t ret;

    printf("接收线程启动\n"); // 打印接收线程启动信息

    while (1) 
    {
       pthread_mutex_lock(&lock); // 加锁
        ret = read(pipefd, buf, sizeof(buf) - 1); // 从管道读取数据
        pthread_mutex_unlock(&lock); // 解锁
        if (ret < 0) 
        {
            if (errno == EAGAIN || errno == EWOULDBLOCK) 
            { // 如果没有数据可读
                usleep(100000); // 等待100毫秒再试
                continue;
            }
            perror("read from pipe failed"); // 读取失败,打印错误信息
            break;
        }
        if (ret == 0)
        {
            // 管道关闭
            break;
        }
        buf[ret] = '\0'; // 添加字符串结束符
        printf("\n");
        printf("收到消息: %s\n", buf); // 打印接收到的消息
    }

    printf("接收线程结束\n"); // 打印接收线程结束信息
    return NULL;
}

// 清理函数,关闭文件描述符并删除管道
void cleanup(int sig) {
    printf("收到信号CTRL+C,准备清理...\n"); // 打印清理信息
    if (tingyu_fd >= 0) close(tingyu_fd); // 关闭管道1的文件描述符
    if (youan_fd >= 0) close(youan_fd); // 关闭管道2的文件描述符
    unlink(TINGYU_PATH); // 删除管道1
    unlink(YOUAN_PATH); // 删除管道2
    //销毁互斥
    pthread_mutex_destroy(&lock);
    printf("清理完成,程序退出...\n"); // 打印退出信息
    exit(0); // 退出程序
}
//端二
#include <stdio.h>// 标准输入输出头文件
#include <stdlib.h>// 标准函数库头文件
#include <sys/types.h>// 系统头文件
#include <sys/stat.h>// 系统头文件
#include <fcntl.h>// 文件控制头文件
#include <unistd.h>// unistd.h头文件
#include <string.h>// 字符串头文件
#include <pthread.h>// 线程头文件
#include <errno.h>// 错误号头文件
#include <signal.h>// 信号处理头文件

#define TINGYU_PATH "/home/ubuntu/youan/tingyu_fifo"// 发送端管道文件路径
#define YOUAN_PATH "/home/ubuntu/youan/youan_fifo"// 接收端管道文件路径

void* send_thread(void* arg);// 发送线程
void* recv_thread(void* arg);// 接收线程
void cleanup(int sig);// 信号处理函数

int tingyu_fd, youan_fd;  // 线程id
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 互斥锁

int main() {
    int ret;
    pthread_t send_tid, recv_tid;

    //捕获Ctrl-C信号
    signal(SIGINT, cleanup);

    // 创建管道1
    ret = mkfifo(TINGYU_PATH, 0777);
    if (ret < 0 && errno != EEXIST)// 如果管道已经存在,则不再创建
    {
        perror("mkfifo TINGYU_PATH failed");
        return -1;
    }

    // 创建管道2
    ret = mkfifo(YOUAN_PATH, 0777);
    if (ret < 0 && errno != EEXIST) // 如果管道已经存在,则不再创建
    {
        perror("mkfifo YOUAN_PATH failed");
        return -1;
    }

    // 打开管道1用于写入(向发送端发送数据)
    tingyu_fd = open(TINGYU_PATH, O_WRONLY);// 打开管道1用于写入
    if (tingyu_fd < 0) 
    {
        perror("open TINGYU_PATH failed");
        return -1;
    }

    // 打开管道2用于读取(从发送端接收数据)
    youan_fd = open(YOUAN_PATH, O_RDONLY | O_NONBLOCK);// 打开管道2用于读取,设置非阻塞模式
    if (youan_fd < 0) 
    {
        perror("open YOUAN_PATH failed");
        close(tingyu_fd);
        return -1;
    }

    // 创建发送线程
    ret = pthread_create(&send_tid, NULL, send_thread, (void*)&tingyu_fd);
    if (ret) {
        perror("pthread_create send_tid failed");
        close(tingyu_fd);
        close(youan_fd);
        return -1;
    }

    // 创建接收线程
    ret = pthread_create(&recv_tid, NULL, recv_thread, (void*)&youan_fd);
    if (ret) {
        perror("pthread_create recv_tid failed");
        close(tingyu_fd);
        close(youan_fd);
        return -1;
    }

    // 等待线程结束
    pthread_join(send_tid, NULL);
    pthread_join(recv_tid, NULL);

    // 关闭文件描述符
    close(tingyu_fd);
    close(youan_fd);

    // 删除管道文件
    unlink(TINGYU_PATH);
    unlink(YOUAN_PATH);

    // 销毁互斥
    pthread_mutex_destroy(&mutex);

    return 0;
}

void* send_thread(void* arg) 
{
    int pipefd = *(int*)arg;
    char buf[1024];
    ssize_t ret;

    printf("发送端线程开始\n");// 打印提示信息

    while (1) 
    {
        printf("输入要发送的消息:");
        if (fgets(buf, sizeof(buf), stdin) == NULL)
        {
            perror("fgets failed");
            break;
        }
        buf[strcspn(buf, "\n")] = '\0'; // 去掉换行符
         // getchar(); // 读取回车键
        pthread_mutex_lock(&mutex); // 加互斥锁
        ret = write(pipefd, buf, strlen(buf));
        pthread_mutex_unlock(&mutex); // 解互斥锁
        if (ret < 0)
        {
            perror("write to pipe failed");
            break;
        }
    }

    printf("发送端线程结束\n");
    return NULL;
}

void* recv_thread(void* arg) {
    int pipefd = *(int*)arg;
    char buf[1024];
    ssize_t ret;

    printf("接收端线程开始\n");

    while (1)
    {
        pthread_mutex_lock(&mutex); // 加互斥锁
        ret = read(pipefd, buf, sizeof(buf) - 1);
        pthread_mutex_unlock(&mutex); // 解互斥锁
        if (ret < 0) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) //如果管道为空,则等待100ms后再次尝试读取
            {
                usleep(100000); // 100ms
                continue;
            }
            perror("read from pipe failed");
            break;
        }
        if (ret == 0)
        {
            // Pipe closed
            break;
        }
        buf[ret] = '\0';
        printf("\n");
        printf("接收端收到消息: %s\n", buf);
    }

    printf("接收端线程结束\n");
    return NULL;
}

void cleanup(int sig) {
    printf("收到信号Ctrl-C,准备清理...\n");
    if (tingyu_fd >= 0) close(tingyu_fd);
    if (youan_fd >= 0) close(youan_fd);
    unlink(TINGYU_PATH);
    unlink(YOUAN_PATH);
    //销毁互斥
    pthread_mutex_destroy(&mutex);
    printf("清理完成,程序退出...\n");
    exit(0);
}

标签:线程,管道,ret,端线,20240815,fd,pthread,PATH,buf
From: https://blog.csdn.net/qq_65171301/article/details/141230548

相关文章

  • shell编程中的管道符 ‘|‘
    在Shell编程中,管道符`|`是一个非常有用的工具,用于将一个命令的输出传递给另一个命令作为输入。这种操作叫做管道(piping)。 具体来说,当你在Shell中使用`|`时,它会将前一个命令的标准输出(stdout)作为后一个命令的标准输入(stdin)。这允许你将多个命令组合在一起,实现复杂的操作......
  • golang 管道channel相关问题
    一funcmain(){ c1:=make(chanany) <-c1}上面代码运行肯定会报deadlock的死锁错误,但是下面这样,如果有一个协程一直在运行,则不会报错,大致就是因为协程还在运行,所属主协程main不确定是否会往管道c1中写数据,所以就会一直阻塞在这里,上面的代码块或者没有一直执行的协程......
  • Linux系统中的管道命令、grep命令、sed命令和awk命令
    本章将和大家分享Linux系统中的管道命令、grep命令、sed命令和awk命令。废话不多说,下面我们直接进入主题。一、管道命令Linux中的管道命令(pipe)是一种非常强大的特性,它允许你将一个命令的输出作为另一个命令的输入。管道命令极大地增强了命令行的灵活性和功能,使得复杂的数据处理......
  • Linux标准输入输出与重定向、管道技术
    Linux标准输入输出与重定向、管道技术1.标准输入输出1.1概念每个Linux程序执行时,默认打开三个标准文件描述符:标准输入(STDIN):文件描述符为0,通常对应终端键盘。标准输出(STDOUT):文件描述符为1,默认输出到屏幕。错误输出(STDERR):文件描述符为2,默认输出到屏幕。1.2示例cat......
  • 在管道之前或之后分离 X 和 y 中的数据?
    我有以下内容:train_set,test_set=train_test_split(arbres_df,test_size=0.2,random_state=42)哪个是旧的train_test_split我们知道。然后我将功能和目标分开:train_feat=train_set.drop("anneedeplantation",axis=1).reset_index(drop=True)train_......
  • 多普勒流量计 | 高精度非接触式测量,管道流量监测无障碍
    ​我们广州的客户一直在寻找一款高精度且便于部署的流量计,用于实时监控生产管线中的流体流量。经过反复比较,最终我们选择了这款超声波多普勒流量计。该流量计采用多普勒效应的测量原理,通过发射和接收声波信号,精确测量管道内流体的流速分布。与传统测量方式相比,它最大的优势......
  • USB 端点和管道的区别
    在USB体系架构中,经常会混用USB端点和USB管道的概念,包括本人也经常混用。但严格来说它们是两个不同的概念,具体表现在:端点是USB设备端的概念,是真实的特理设备上的概念,其特性是通过端点描述符来描述的。而管道是USB主机端的上软件的概念,其概据USB的设备端点信息建立的数据软件数据......
  • 果宇科技与某迪公司应用布袋除尘器的管道插入式粉尘检测仪案例
    项目背景:某迪为了确保工业生产的安全、‌提高生产效率以及保护环境,‌保障工作人员的健康,该企业选购24台管道插入式粉尘检测仪,下面果宇科技小编分享管道插入式粉尘检测仪在某迪公司布袋除尘器的应用案例:技术背景与工作原理管道插入式粉尘检测仪概述:GY/VGD-100-PIL管道插入......
  • 管道与重定向
    文章目录 1.重定向2.输出重定向 3.输入重定向3.1通过输入重定向创建文件:4.管道4.1常用小命令5.参数传递:xargs总结1.重定向文件描述符:进程在运行的过程中根据需要会打开多个文件,每打开一个文件会有一个数字标识。这个标识叫文件描述符。进程使用文件描述符来......
  • Redis中pipeline(管道)详解
    redis管道pipeline举个例子:小卖铺免费让你拿50瓶饮料,你是一次拿一瓶拿回家,还是打包一次或者多次拿回家?概念Redis管道(pipelining)是一种在客户端向服务端发送多个请求而不等待响应的技术。它可以显著提高Redis应用程序的性能。管道的主要思想是客户端向服务端发送多个请求......