一、服务器
简单来说就是个简单的Linux C程序,实现了读取一个命名管道的功能。下面是代码解析:
1、头文件
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
这些是头文件,用于提供各种系统调用函数、宏定义和数据类型的声明。
2、宏定义
#define FIFO_PATH "/tmp/mp_fifo"
#define MSG_LEN 50
#define EXIT_MASK "exit"
这里定义了三个宏,分别表示命名管道的路径、消息长度和退出标志。
3、结构体定义
struct msg_inf
{
long process_id;//进程id
char msg[MSG_LEN];
};
这里定义了一个结构体,包含进程id和消息。
4、判断有名管道是否存在
if(access(FIFO_PATH,F_OK))
{
umask(0000);
mkfifo(FIFO_PATH,0777);
}
这段代码判断命名管道是否存在,如果不存在,则调用mkfifo
函数创建它。access
函数可以检查文件或目录是否存在,并且可以检查当前用户是否具有读、写或执行权限。mkfifo
函数用于创建一个命名管道。
5、打开有名管道
int fifo_fd = open(FIFO_PATH,O_RDWR);
if(fifo_fd == -1)
{
perror("open");
return -1;
}
这段代码打开命名管道并返回文件描述符。O_RDWR
表示以读写方式打开,perror
用于打印出错信息。
6、循环读取信息
struct msg_inf MI;
while(1)
{
memset(&MI,0,sizeof(MI));
read(fifo_fd,&MI,sizeof(MI));
if(strcmp(EXIT_MASK,MI.msg) == 0)
{
printf("%ld下线了\n",MI.process_id);
}
else
{
printf("%ld:%s\n",MI.process_id,MI.msg);
}
}
进入一个无限循环。循环中第一步是清空MI结构体,然后使用read函数从FIFO中读取消息,并将读取的内容存储到MI结构体中。
接着通过判断MI中的消息内容,来决定是输出下线提示还是打印接收到的消息内容。循环将一直运行,直到程序被手动结束。
7、关闭管道
close(fifo_fd);
下面是完整代码:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#define FIFO_PATH "/tmp/mp_fifo"
#define MSG_LEN 50
#define EXIT_MASK "exit"
struct msg_inf
{
long process_id;//进程id
char msg[MSG_LEN];
};
int main()
{
if(access(FIFO_PATH,F_OK))
{
umask(0000);
mkfifo(FIFO_PATH,0777);
}
int fifo_fd = open(FIFO_PATH,O_RDWR);
if(fifo_fd == -1)
{
perror("open");
return -1;
}
//我想弄一个客户端链接服务器的机制 --- 链表保存
struct msg_inf MI;
while(1)
{
memset(&MI,0,sizeof(MI));
read(fifo_fd,&MI,sizeof(MI));
if(strcmp(EXIT_MASK,MI.msg) == 0)
{
printf("%ld下线了\n",MI.process_id);
}
else
{
printf("%ld:%s\n",MI.process_id,MI.msg);
}
}
close(fifo_fd);
return 0;
}
二、客户端:
用C语言程序实现了一个基于FIFO(命名管道)的客户端聊天室程序,以下是代码解析:
1、头文件
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
2、宏定义
#define FIFO_PATH "/tmp/mp_fifo"
#define MSG_LEN 50
#define EXIT_MASK "exit"
定义了FIFO文件路径、消息长度、退出消息的字符串。
3、定义结构体
struct msg_inf
{
long process_id;
char msg[MSG_LEN];
};
定义了消息结构体,包含进程ID和消息内容。
4、捕获信号的处理函数
void Fun(int num)
{
struct msg_inf MI;
memset(&MI,0,sizeof(MI));
MI.process_id = getpid();
strcpy(MI.msg,EXIT_MASK);
write(tmp_fd,&MI,sizeof(MI));
close(tmp_fd);
exit(1);
}
这个函数在程序捕获到SIGINT信号(即Ctrl+C)时被调用。它向FIFO中写入一个包含进程ID和退出消息的结构体,告诉服务器客户端已经退出,并关闭FIFO文件描述符
5、主函数
int main()
{
if(access(FIFO_PATH,F_OK))
{
umask(0000);
mkfifo(FIFO_PATH,0777);
}
int fifo_fd = open(FIFO_PATH,O_RDWR);
if(fifo_fd == -1)
{
perror("open");
return -1;
}
tmp_fd = fifo_fd;
signal(SIGINT,Fun);
struct msg_inf MI;
memset(&MI,0,sizeof(MI));
MI.process_id = getpid();
while(1)
{
memset(MI.msg,0,MSG_LEN);
scanf("%s",MI.msg);
write(fifo_fd,&MI,sizeof(MI));
if(strcmp(EXIT_MASK,MI.msg) == 0)
{
printf("退出聊天室成功!\n");
break;
}
}
close(fifo_fd);
return 0;
}
首先通过access函数判断FIFO文件是否存在,如果不存在则使用umask和mkfifo创建它。然后打开FIFO文件并获得它的文件描述符,如果打开失败则输出错误信息并退出程序。
接着将FIFO文件描述符赋值给全局变量tmp_fd,以便在Fun函数中使用。然后注册SIGINT信号,并将Fun函数作为信号处理函数。
接下来定义一个消息结构体MI,将自己的进程ID赋值给它。然后进入循环,从标准输入中读取消息内容,将进程ID和消息内容写入FIFO文件中。
如果读取到的消息内容与退出消息相同,打印退出信息并退出循环。
最后关闭FIFO文件描述符,程序运行结束。
完整代码:
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#define FIFO_PATH "/tmp/mp_fifo"
#define MSG_LEN 50
#define EXIT_MASK "exit"
int tmp_fd;
struct msg_inf
{
long process_id;//进程id
char msg[MSG_LEN];
};
void Fun(int num)
{
struct msg_inf MI;
memset(&MI,0,sizeof(MI));
MI.process_id = getpid();
strcpy(MI.msg,EXIT_MASK);
write(tmp_fd,&MI,sizeof(MI));//告诉服务器我挂了
close(tmp_fd);
exit(1);
}
int main()
{
if(access(FIFO_PATH,F_OK))
{
umask(0000);
mkfifo(FIFO_PATH,0777);
}
int fifo_fd = open(FIFO_PATH,O_RDWR);
if(fifo_fd == -1)
{
perror("open");
return -1;
}
tmp_fd = fifo_fd;
signal(SIGINT,Fun);
//我想弄一个客户端链接服务器的机制 --- 链表保存
struct msg_inf MI;
memset(&MI,0,sizeof(MI));
//先把自己的id赋值进结构体
MI.process_id = getpid();
while(1)
{
memset(MI.msg,0,MSG_LEN);
scanf("%s",MI.msg);
write(fifo_fd,&MI,sizeof(MI));
if(strcmp(EXIT_MASK,MI.msg) == 0)
{
printf("退出聊天室成功!\n");
break;
}
}
close(fifo_fd);
return 0;
}