IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Unix网络编程-管道和FIFO -> 正文阅读

[系统运维]Unix网络编程-管道和FIFO

管道

/**
 * @file pipe.c
 * 1.客户端传送给服务端一个路径名字
 * 2.服务端读取文件内容通过ipc传送给客户端
 * 3.客户端将读取的内容显示到标准输出
 * 
 * 管道本身是半双工,fork之后是可以全双工,但是只有一个管道缓冲区,根本没法进行通信
 * 全双工的通信还是像下面这样,用两个管道,用两个缓冲区实现
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#define FILEPATH "/home/adce/mycode/vscode/unix_process/pipe/file/pipeFile.txt"
#define PATHSIZE 1024
void Client(int writefd, int readfd);
void Server(int writefd, int readfd);
int main(int argc, char **argv)
{
    int pipe_client[2]; // 客户端写的管道
    int pipe_server[2]; // 服务端写的管道
    if (pipe(pipe_client) < 0 || pipe(pipe_server) < 0)
    {
        perror("pipe");
        exit(-1);
    }
    // 让子进程运行服务端程序,父进程运行客户端程序
    pid_t server_pid;
    if ((server_pid = fork()) < 0)
    {
        perror("fork");
        exit(-1);
    }
    if (server_pid == 0)    // 子进程运行服务端程序
    {
        close(pipe_client[1]);  // 关掉客户端的写通道
        close(pipe_server[0]);  // 关掉服务端的读通道
        Server(pipe_server[1], pipe_client[0]); // 执行服务端程序
        exit(0);    // 执行完就结束
    }
    // 父进程运行客户端程序
    close(pipe_client[0]);  // 关掉客户端的读端
    close(pipe_server[1]);  // 关掉服务端的写端
    Client(pipe_client[1], pipe_server[0]);
    waitpid(server_pid, NULL, 0);   // 收尸子进程
    exit(0);
}

void Client(int writefd, int readfd)
{
    char pathbuf[PATHSIZE];
    strncpy(pathbuf, FILEPATH, PATHSIZE);
    size_t pathlen = strlen(pathbuf);   // 得到路径的真实长度
    ssize_t writesize = write(writefd, pathbuf, pathlen);
    if (writesize < pathlen)    // 如果写入的字节不够,就报错,默认是阻塞写,肯定会够,不够就是出错了
    {
        fprintf(stderr, "write size less than pathlen.\n");
        exit(-1);
    }
    // 循环读
    ssize_t readsize;
    char buf[1024];
    printf("client begin read:\n");
    while ((readsize = read(readfd, buf, 1024)) > 0)
    {
        write(STDOUT_FILENO, buf, readsize);    // 将读到的内容输出到标准输出
    }
    printf("client read over.\n");
    exit(0);
}

void Server(int writefd, int readfd)
{
    char buf[PATHSIZE];
    ssize_t readsize;
    if((readsize = read(readfd, buf, PATHSIZE)) < 0) // 先把路径读出来
    {
        // 读出错
        perror("read");
        exit(-1);
    }
    int filefd;
    filefd = open(buf, O_RDONLY);
    if (filefd < 0)
    {
        fprintf(stderr, "open() failed.");
        exit(-1);
    }
    while ((readsize = read(filefd, buf, PATHSIZE)) > 0)
    {
        write(writefd, buf, readsize);
    }
    write(writefd, "send over!\n", 12);
    exit(0);
}
/**
 * @file pipe-popen.c
 * 1.使用popen调用cat命令读取文件
 * 我们在用shell命令的时候,有一个管道通配符 |
 * 这个popen就是这个作用,启用一个shell命令,并预留管道通信
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FILEPATH "/home/adce/mycode/vscode/unix_process/pipe/file/pipeFile.txt"
#define PATHSIZE 1024
int main(int argc, char **argv)
{
    char command[PATHSIZE];
    char buf[1024];
    FILE *fp;
    sprintf(command, "cat %s", FILEPATH);
    fp = popen(command, "r");
    int readsize;
    while (fgets(buf, 1024, fp) != NULL)
    {
        printf(buf);
    }
    exit(0);
}

FIFO

两个无关系的进程之间通信。

/**
 * @file fifo-server.c
 * 使用命名管道通信
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
// 最宽松的权限
#define FILE_MODE (S_IRWXU | S_IRWXG | S_IRWXO)
#define FIFOCLIENT "/home/adce/mycode/vscode/unix_process/fifo/file/fifo.client"
#define FIFOSEVER "/home/adce/mycode/vscode/unix_process/fifo/file/fifo.server"
#define FILEPATH "/home/adce/mycode/vscode/unix_process/fifo/file/fifoFile.txt"
#define PATHSIZE 1024
void Client(int writefd, int readfd);
int main(int argc, char **argv)
{
    int readfd, writefd;
    writefd = open(FIFOCLIENT, O_WRONLY, 0);
    readfd = open(FIFOSEVER, O_RDONLY, 0);
    if (readfd < 0 || writefd < 0)
    {
        perror("open");
        exit(-1);
    }
    Client(writefd, readfd);
    unlink(FIFOCLIENT);
    unlink(FIFOSEVER);
    exit(0);
}
void Client(int writefd, int readfd)
{
    char pathbuf[PATHSIZE];
    strncpy(pathbuf, FILEPATH, PATHSIZE);
    size_t pathlen = strlen(pathbuf);   // 得到路径的真实长度
    ssize_t writesize = write(writefd, pathbuf, pathlen);
    if (writesize < pathlen)    // 如果写入的字节不够,就报错,默认是阻塞写,肯定会够,不够就是出错了
    {
        fprintf(stderr, "write size less than pathlen.\n");
        exit(-1);
    }
    // sleep(1);   // 等待服务端先把内容写入fifo,否则可能会读空
    // 循环读
    ssize_t readsize;
    char buf[1024];
    printf("client begin read:\n");
    while ((readsize = read(readfd, buf, 1024)) > 0)
    {
        write(STDOUT_FILENO, buf, readsize);    // 将读到的内容输出到标准输出
    }
    printf("client read over.\n");
    exit(0);
}


/**
 * @file fifo-server.c
 * 使用命名管道通信
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
// 最宽松的权限
#define FILE_MODE (S_IRWXU | S_IRWXG | S_IRWXO)
#define FIFOSEVER "/home/adce/mycode/vscode/unix_process/fifo/file/fifo.server"
#define FIFOCLIENT "/home/adce/mycode/vscode/unix_process/fifo/file/fifo.client"
#define PATHSIZE 1024
void Server(int writefd, int readfd);
int main(int argc, char **argv)
{
    if ((mkfifo(FIFOSEVER, FILE_MODE) < 0) && (errno != EEXIST))
    {
        perror("mkfifo");
        exit(-1);
    }
    if ((mkfifo(FIFOCLIENT, FILE_MODE) < 0) && (errno != EEXIST))
    {
        perror("mkfifo");
        exit(-1);
    }
    int readfd, writefd;
    readfd = open(FIFOCLIENT, O_RDONLY, 0);
    writefd = open(FIFOSEVER, O_WRONLY, 0);
    if (readfd < 0 || writefd < 0)
    {
        perror("open");
        exit(-1);
    }
    Server(writefd, readfd);
    exit(0);
}

void Server(int writefd, int readfd)
{
    char buf[PATHSIZE];
    ssize_t readsize;
    if((readsize = read(readfd, buf, PATHSIZE)) < 0) // 先把路径读出来
    {
        // 读出错
        perror("read");
        exit(-1);
    }
    int filefd;
    filefd = open(buf, O_RDONLY);
    if (filefd < 0)
    {
        fprintf(stderr, "open() failed.");
        exit(-1);
    }
    while ((readsize = read(filefd, buf, PATHSIZE)) > 0)
    {
        write(writefd, buf, readsize);
    }
    write(writefd, "send over!\n", 12);
    exit(0);
}

一个服务端,多个客户端通信:

/**
 * @file proto.h
 * 客户端和服务端共同遵守的协议
 * 定义消息体数据结构
 * 为了简化,这里服务器就统一回复:[pid] OK.
 */
#ifndef PROTO_H_
#define PROTO_H_

#include <limits.h>
#include <unistd.h>
#include <string.h>
#define FIFO_MODE (S_IRWXU | S_IRWXG | S_IRWXO)
#define SERVER_FIFO "/home/adce/mycode/vscode/unix_process/fifo/file/serverfifo"
#define CLIENT_FIFO "/home/adce/mycode/vscode/unix_process/fifo/file/clientfifo."
#define MEGDATESIZE (PIPE_BUF - sizeof(int))
struct msg_st
{
    int pid;        // > 0
    char data[MEGDATESIZE];  // date
};
#endif


/**
 * @file server.c
 * 可以处理多个客户端的通信
 * 使用结构体消息
 * 有一个众所周知的server fifo,服务端从这里面读取数据
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include "proto.h"
#include <signal.h>
void handle(int p)
{
    printf("logout.\n");
    exit(0);
}
int main(int agrc, char **argv)
{
    signal(SIGINT, handle);
    // 尝试创建并打开fifo
    if (mkfifo(SERVER_FIFO, FIFO_MODE) < 0 && errno != EEXIST)
    {
        perror("mkfifo");
        exit(-1);
    }
    // 自己先打开写fifo,再打开读fifo,防止客户端关闭的时候,服务器整个被阻塞
    int readfd = open(SERVER_FIFO, O_RDONLY);
    if (readfd < 0)
    {
        perror("open");
        exit(-1);
    }
    // 这个只有在readfd阻塞之后才会执行,readfd只会阻塞一次,防止readfd失效,一直占用写端,但是这个fd不用,用nofd表示。
    int nofd = open(SERVER_FIFO, O_WRONLY); 
    if (nofd < 0)
    {
        perror("open");
        exit(-1);
    }

    // 死循环执行任务
    char buf[1024];
    char client_path[1024];
    struct msg_st msg;
    printf("server begin recv:\n");
    while (read(readfd, &msg, sizeof(msg)) > 0)
    {
        printf("[%d]:%s\n", msg.pid, msg.data); // 服务器把接受到的消息打印到终端上
        sprintf(client_path, "%s%d", CLIENT_FIFO, msg.pid);
        sprintf(buf, "[%d]:OK.", msg.pid);
        int sendfd = open(client_path, O_WRONLY);
        if (sendfd < 0)
        {
            perror("open");
            exit(-1);
        }
        strncpy(msg.data, buf, sizeof(buf));
        write(sendfd, &msg, sizeof(msg));
    }
    exit(0);
}


/**
 * @file client.c
 * 客户端有自己独立的client fifo
 * fifo的地址通过结构体传送给服务器
 * 服务器通过这个fifo传回数据
 */
#include "proto.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
void handle(int p)
{
    printf("logout.\n");
    exit(0);
}
int main(int argc, char **argv)
{
    signal(SIGINT, handle);
    pid_t pid = getpid();
    char path[1024];
    sprintf(path, "%s%d", CLIENT_FIFO, pid);
    if (mkfifo(path, FIFO_MODE) < 0 && errno != EEXIST) // 新建自己的fifo
    {
        perror("mkfifo");
        exit(-1);
    }
    // 打开服务端的fifo
    int sendfd = open(SERVER_FIFO, O_WRONLY);
    struct msg_st msg;
    char buf[1024];
    gets(buf);  // 手动输入消息
    msg.pid = pid;
    strncpy(msg.data, buf, strlen(buf));
    write(sendfd, &msg, sizeof(msg));   // 发送消息
    int recvfd = open(path, O_RDONLY);  // 打开自己的fifo,读内容,注意,不能打开早了,否则会阻塞
    while(1)
    {
        read(recvfd, &msg, sizeof(msg));
        puts(msg.data);
        gets(buf);
        strncpy(msg.data, buf, strlen(buf));
        write(sendfd, &msg, sizeof(msg));   // 发送消息
    }
    exit(0);
}
  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-04-28 12:14:41  更:2022-04-28 12:15:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 20:01:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码