管道-进程案例: 单机聊天程序

This commit is contained in:
flykhan 2023-08-17 18:18:20 +08:00
parent 85e2fc451e
commit dea9717412
3 changed files with 183 additions and 0 deletions

BIN
day4/chat_tool/chat_tool Executable file

Binary file not shown.

130
day4/chat_tool/chat_tool.c Normal file
View File

@ -0,0 +1,130 @@
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
// 创建FIFO
int createFifo(const char *fifoName)
{
if (mkfifo(fifoName, 0644) == -1) // 创建FIFO
{
if (errno != EEXIST)
{
perror(fifoName); // 输出错误信息
return 1;
}
}
return 0;
}
// 发送数据
void sendData(const char *fifoName, const char *sender)
{
int fd = open(fifoName, O_WRONLY); // 打开FIFO以进行写操作
while (1)
{
char buf[128] = {};
int len = read(STDIN_FILENO, buf, 128); // 从标准输入读取数据
buf[len - 1] = '\0'; // 去除换行符
write(fd, buf, len); // 写入FIFO
if (strcmp(buf, "bye") == 0) // 如果输入为"bye",则退出循环
{
break;
}
}
close(fd); // 关闭FIFO
printf("%s 发送完毕\n", sender); // 输出发送方的信息
}
// 接收数据
void receiveData(const char *fifoName, const char *receiver)
{
int fd = open(fifoName, O_RDONLY); // 打开FIFO以进行读操作
while (1)
{
char buf[128] = "";
int len = read(fd, buf, 128); // 从FIFO读取数据
if (len <= 0)
break;
printf("接收 %s: %s\n", receiver, buf); // 输出接收到的数据和接收方的信息
}
close(fd); // 关闭FIFO
printf("%s 接收完毕\n", receiver); // 输出接收方的信息
}
int main(int argc, char const *argv[])
{
const char *fifo_bob_to_lucy = "fifo_bob_to_lucy"; // Bob到Lucy的FIFO名称
const char *fifo_lucy_to_bob = "fifo_lucy_to_bob"; // Lucy到Bob的FIFO名称
// 创建FIFO
if (createFifo(fifo_bob_to_lucy) != 0) // 创建Bob到Lucy的FIFO
return 1;
if (createFifo(fifo_lucy_to_bob) != 0) // 创建Lucy到Bob的FIFO
return 1;
if (argc != 2)
{
printf("Useage: ./chat_tool [角色名: lucy | bob]");
return 1;
}
if (strcmp(argv[1], "lucy") != 0 && strcmp(argv[1], "bob") != 0)
{
printf("用户仅可选择 lucy 或 bob");
return 1;
}
int i = 0;
for (; i < 2; i++)
{
int pid = fork(); // 创建子进程
if (pid == 0)
break;
}
if (i == 0)
{
// 第一个子进程
if (strcmp(argv[1], "lucy") == 0) // 如果是Lucy方
{
sendData(fifo_lucy_to_bob, "Lucy"); // 发送数据给Bob
}
else if (strcmp(argv[1], "bob") == 0) // 如果是Bob方
{
sendData(fifo_bob_to_lucy, "Bob"); // 发送数据给Lucy
}
}
else if (i == 1)
{
// 第二个进程,读数据
if (strcmp(argv[1], "lucy") == 0) // 如果是Lucy方
{
receiveData(fifo_bob_to_lucy, "Lucy"); // 接收来自Bob的数据
}
else if (strcmp(argv[1], "bob") == 0) // 如果是Bob方
{
receiveData(fifo_lucy_to_bob, "Bob"); // 接收来自Lucy的数据
}
}
else
{
// 主进程
while (1)
{
int pid_ = waitpid(0, NULL, WNOHANG); // 等待所有子进程退出
if (pid_ == -1)
{
// 所有子进程都已经退出
break;
}
}
}
return 0;
}

53
day4/chat_tool/readme.md Normal file
View File

@ -0,0 +1,53 @@
使用文档chat_tool.c
该程序是一个聊天工具,允许两个角色("lucy" 和 "bob")之间进行消息的发送和接收。
用法:
./chat_tool [角色名: lucy | bob]
参数说明:
- 角色名:指定聊天的角色,可选的值为 "lucy" 或 "bob"。
注意事项:
- 在运行程序之前,请确保已经创建了相应的 FIFO命名管道
- 创建 FIFO 的函数为 `createFifo(const char *fifoName)`,请确保正确调用该函数。
- FIFO 的名称分别为 "fifo_bob_to_lucy" 和 "fifo_lucy_to_bob"。
示例用法:
1. 创建 FIFO
$ ./chat_tool bob
$ ./chat_tool lucy
2. 运行程序:
- Bob 方发送消息给 Lucy 方:
$ ./chat_tool bob
- Lucy 方发送消息给 Bob 方:
$ ./chat_tool lucy
3. 聊天操作:
- 在程序运行后,输入消息并按下回车键发送。
- 输入 "bye" 退出聊天。
注意事项:
- 请确保在两个不同的终端窗口或会话中分别运行 Bob 方和 Lucy 方。
- Bob 方和 Lucy 方可以同时发送和接收消息。
示例:
- Bob 方发送消息给 Lucy 方:
$ ./chat_tool bob
Hello Lucy!
How are you?
bye
- Lucy 方发送消息给 Bob 方:
$ ./chat_tool lucy
Hi Bob!
I'm good. How about you?
bye