如何在C ++中使用管道构建聊天程序

如何解决如何在C ++中使用管道构建聊天程序

我想实现一个运行小程序1或小程序2的小程序,具体取决于调用main时输入的参数。打开2个终端和第1个聊天室后,我希望在2个终端之间发送小的字符串消息。

我尝试实现一个简单的管道程序,在该程序中,进程将以读取或写入的方式打开管道。然后,如果进程不是您用于其他目的的管道,则该进程将关闭相应的一端,读取端或写入端。打开2个终端,并使用参数0或1调用main时,我调用2个进程打开管道。

但是,我在运行程序以在2个进程之间连续发送消息时遇到麻烦。每当检测到键盘输入时,该过程就会退出。

我怀疑我没有正确打开管道。 (我的代码中没有打开函数)。打开函数还要求我输入管道的路径名,该路径名在/ proc / [PID] / fd中。我看到每次运行程序时PID都会不同。因此,如何将其放入开放函数的参数中。

请帮助我修改代码。

#include <unistd.h>   /* to use pipe,getpid*/
#include <stdio.h>    /*to use prinf*/
#include <iostream>   /*to use cin,cout*/
#include <string.h>   /*to use str function*/
#include <errno.h>    /* to use with errno*/

int onServiceStart(int chatter,int readPipe[],int writePipe[]){
    if( close(readPipe[1]) == -1 ){   //if use the pipe to read,then close the write end of the pipe
        std::cout<<"Error closing the write end of read pipe"<<errno<<std::endl;
    };
    if( close(writePipe[0]) == -1 ){   //if use the pipe to write,then close the read end of the pipe
        std::cout<<"Error closing the read end of write pipe"<<errno<<std::endl;
    };
    while(true){
        //preparing to get the string from keyboard
        std::string chatInput;
        getline(std::cin,chatInput);
        //send the string to pipe
        if ( write( writePipe[1],chatInput.c_str(),strlen( chatInput.c_str() )) == -1) {
            std::cout<<"Error writing to write end of write pipe"<<errno<<std::endl;
        };
        //preparing the buffer to put the string to after reading from pipe
        char buffer;
        if ( read(readPipe[0],&buffer,1)== -1) {
            std::cout<<"Error reading from read end of read pipe"<<errno<<std::endl;
        };
        std::cout<<buffer;
    }
};

int main(int argc,char *argv[]){
    int chatter = *(argv[1]) - '0';
    int fileDescription1[2],fileDescription2[2] ;
    if ( pipe(fileDescription1)==-1 ) {
        printf("cannot create pipe 1");
    };
    if ( pipe(fileDescription2)==-1 ) {
        printf("cannot create pipe 2");
    };

    switch (chatter) {
        case 0:
            printf("PID %d,chatter 1: \n",getpid());
            onServiceStart(chatter,fileDescription1,//chatter1 will use fileDescription1 to read,fileDescription2);     //chatter1 will use fileDescription2 to write,case 1:
            printf("PID %d,chatter 2: \n",fileDescription2,//chatter2 will use fileDescription2 to read,fileDescription1);    //chatter2 will use fileDescription1 to write,}
}

解决方法

有几个问题。进程立即退出的原因是,您的程序仅在管道的一侧运行,而不在另一侧运行。例如,如果您使用chatter = 0运行它,则将fileDescription2用作writePipe,但是在onServiceStart()中要做的第一件事是close()的阅读面writePipe中的。这意味着每当您写入writePipe[1]时,由于writePipe[0]已关闭,您将收到EPIPE错误。

如果要启动程序的两个实例,一个以0作为参数,另一个以1进行调用,则需要使用一对named pipes它们之间可以进行通信,尽管如果您希望进行双向通信,则命名UNIX socket甚至更好,因为您只需要一个即可。

请注意,只有在您的程序派生或创建多个线程时,使用pipe()创建的一对匿名管道才有用。

另一个问题是您没有从管道的另一端读取整个响应:

//preparing the buffer to put the string to after reading from pipe
char buffer;
if ( read(readPipe[0],&buffer,1)== -1) {
    ...

这仅读取一个字符。之后,您将再次从标准输入中读取内容,因此发送的每一行只会收到一个字符,这显然不是您想要的。

处理此问题的正确方法是通过传递O_NONBLOCK标志使管道成为非阻塞管道,并使用select()poll()循环来等待两个标准中的数据同时输入和管道。

,

我改用命名管道。未命名管道不能用于2个独立进程之间的通信,而只能用于父进程和子进程。

由于管道是单向的,因此我必须使用2个管道。对于每个进程,管道将用作只读或仅写。例如,进程0仅将管道1打开为只读,将仅调用read()函数读取管道。

由于它被命名为管道,因此我必须手动关闭和删除管道。在这段代码中,我还没有实现。在关闭程序或“ Crtl + C”程序时,将需要一种信号捕获机制来删除管道。如果您在main 0之前运行main 1,还会有一个小错误。不过,下面的小代码演示了管道的基础。

这是我的代码。

#include <unistd.h>    /* to use pipe,getpid */
#include <sys/stat.h>  /* to use named pipe mkfifo */
#include <sys/types.h> /* to use open() */
#include <fcntl.h>     /* to use open() */
#include <stdio.h>     /*to use prinf */
#include <iostream>    /*to use cin,cout */
#include <string.h>    /*to use str function */
#include <errno.h>     /* to use with errno */
#include <thread>      /* to use thread */

#define PIPE1_PATH "/home/phongdang/pipe1"
#define PIPE2_PATH "/home/phongdang/pipe2"

int openPipe(const char* pipePathName,int flag){
    int fileDescriptor;
    fileDescriptor = open(pipePathName,flag) ;
    if ( fileDescriptor == -1) {
        std::cout<<"Error open pipe at "<<pipePathName<<" .Error code: "<<errno<<std::endl;
    };
    return fileDescriptor;
}

void writePipe(int writePipeDescriptor){
    while (true){
        //preparing to get the string from keyboard
        std::string chatInput;
        getline(std::cin,chatInput);
        int writeBytes = write( writePipeDescriptor,chatInput.c_str(),strlen( chatInput.c_str() ));
        //send the string to pipe
        if ( writeBytes == -1) {
        std::cout<<"Error writing to write end of write pipe"<<errno<<std::endl;
        }
        else {
            printf("Writing to pipe %d bytes \n",writeBytes);
        }
        sleep(1);
    }
}

void readPipe(int readPipeDescriptor){
        char buffer[100];
    while (true){
        //preparing the buffer to put the string to after reading from pipe
memset(buffer,'\0',100);
       // memset(buffer,10);
        int readByte = read(readPipeDescriptor,10);
        if ( readByte== -1) {
            std::cout<<"Error reading from read end of read pipe"<<errno<<std::endl;
        }
        else std::cout<<"Read "<<readByte<<" bytes from pipe :"<<buffer<<std::endl;
        sleep(1);
    }
}

int main(int argc,char *argv[]){
    int chatter = *(argv[1]) - '0';
    int writePipeDescriptor,readFileDescriptor;
    switch (chatter) {
        case 0:
        {
            printf("PID %d,chatter 1: \n",getpid());
            //create pipe is done by chatter 0 only (this is just a hot fix to prevent error 17 EEXIST)
            if ( mkfifo(PIPE1_PATH,S_IRUSR | S_IWUSR | S_IWGRP ) ==-1 ) {  //create pipe for read/write/execute by owner,and others
                std::cout<<("cannot create pipe 1 \n")<<errno<<std::endl;
            };
            writePipeDescriptor = openPipe(PIPE1_PATH,O_WRONLY);
            readFileDescriptor  = openPipe(PIPE2_PATH,O_RDONLY);
            std::thread readThread(readPipe,readFileDescriptor);    //has to create thread and execute thread first.
            writePipe(writePipeDescriptor);
            readThread.join();
            break;
        }
        case 1:
        {
            printf("PID %d,chatter 2: \n",getpid());

            if ( mkfifo(PIPE2_PATH,S_IRUSR | S_IWUSR | S_IWGRP ) ==-1 ) {           //create pipe for read/write/execute by owner,and others
                std::cout<<("cannot create pipe 2 \n")<<errno<<std::endl;
            };
            readFileDescriptor = openPipe(PIPE1_PATH,O_RDONLY);
            writePipeDescriptor = openPipe(PIPE2_PATH,O_WRONLY);
            std::thread writeThread(writePipe,writePipeDescriptor);
            readPipe(readFileDescriptor);
            writeThread.join();
            break;
        }
    }
    return 0;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res