c++ - 如何在 C++ 中使用管道构建聊天程序
问题描述
我想实现一个运行 chatter 1 或 chatter 2 的小程序,这取决于调用 main 时的参数输入。打开 2 个终端后,chatter 1,chatter 2 向上,我希望在 2 个终端之间发送小字符串消息。
我尝试实现一个简单的管道程序,其中一个进程将以读取或写入的方式打开管道。然后,如果您不是出于其他目的的管道,则该过程将关闭相应的端、读端或写端。当我打开 2 个终端并使用参数 0 或 1 调用 main 时,我调用 2 个进程来打开管道。
但是,我无法运行程序以在 2 个进程之间连续发送消息。每当检测到键盘输入时,进程就会退出。
我怀疑我没有正确打开管道。(我的代码中没有打开函数)。open 函数还需要我输入管道的路径名,它位于 /proc/[PID]/fd 中。我看到每次运行程序时 PID 都会有所不同。那么,我怎样才能将它放入 open 函数的参数中。
请帮我修改我的代码。
#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", getpid());
onServiceStart(chatter,
fileDescription2, //chatter2 will use fileDescription2 to read,
fileDescription1); //chatter2 will use fileDescription1 to write,
}
}
解决方案
有几个问题。进程立即退出的原因是因为您的程序只运行管道的一侧,而不是另一侧。chatter = 0
例如,如果您使用fileDescription2
for运行它writePipe
,但您要做的第一件事onServiceStart()
是close()
读取writePipe
. 这意味着无论何时您写入writePipe[1]
,您都会收到 EPIPE 错误,因为writePipe[0]
它已关闭。
如果打算启动程序的两个实例,一个以 with作为参数调用0
,另一个以更好,因为您只需要一个。1
请注意,创建的一对匿名管道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()
orpoll()
循环同时等待来自标准输入和管道的数据。
推荐阅读
- reactjs - 如何从控制台日志显示数据到网站反应?
- debugging - 如何在 LLDB 中将表达式设置为观察点?
- javascript - ReactJS -> 我如何制作受限路线?
- python - 限制用户更新模型表单
- java - 无法更新 doc 文件的语言 [JAVA]
- c# - C# - 在 Windows 服务中调用/实现 Rest Web 服务
- opengl - 在 OpenGL-OpenCL 纹理互操作中,PBO 如何从纹理中接收数据?
- javascript - 如何设置一个值
- python - 验证错误 django 在我的模板中不起作用
- mongodb - MongoDB使用聚合比较两个数组ID和更新时间