使用Systerm V消息队列实现文件服务器应用程序

svmsg_file.h

#include <sys/types.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <stddef.h>
#include <limits.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/wait.h>
#include "tlpi_hdr.h"

#define SERVER_KEY 0x1aaaaaa1

struct requestMsg{
    long mtype;
    int clientId;
    char pathname[PATH_MAX];
};

#define REQ_MSG_SIZE (offsetof(struct requestMsg, pathname) - \
                      offsetof(struct requestMsg, clientId) + PATH_MAX)
#define RESP_MSG_SIZE 8192

struct responseMsg{
    long mtype;
    char data[RESP_MSG_SIZE];
};

#define RESP_MT_FAILURE     1
#define RESP_MT_DATA        2
#define RESP_MT_END         3

svmsg_file_server.c

#include "svmsg_file.h"

static void grimReaper(int sig)
{
    int savedErrno;

    savedErrno = errno;
    while(waitpid(-1, NULL, WNOHANG) > 0)
        continue;
    errno = savedErrno;
}

static void serveRequest(const struct requestMsg *req)
{
    int fd;
    ssize_t numRead;
    struct responseMsg resp;

    fd = open(req->pathname, O_RDONLY);
    if(fd == -1)
    {
        resp.mtype = RESP_MT_FAILURE;
        snprintf(resp.data, sizeof(resp.data), "%s", "Couldn't open");
        msgsnd(req->clientId, &req, strlen(resp.data) + 1, 0);
        exit(EXIT_FAILURE);
    }

    resp.mtype = RESP_MT_DATA;
    while((numRead = read(fd, resp.data, RESP_MSG_SIZE)) > 0)
    {
        if(msgsnd(req->clientId, &resp, numRead, 0) == -1)
            break;   
    }
    resp.mtype = RESP_MT_END;
    msgsnd(req->clientId, &resp, 0, 0);
}

int main(int argc, char *argv[])
{
    struct requestMsg req;
    pid_t pid;
    ssize_t msgLen;
    int serverId;
    struct sigaction sa;

    serverId = msgget(SERVER_KEY, IPC_CREAT | IPC_EXCL |
                        S_IRUSR | S_IWUSR | S_IWGRP);

    if(serverId == -1)
    {
        printf("msgget\n");
        exit(EXIT_FAILURE);
    }

    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    sa.sa_handler = grimReaper;
    if(sigaction(SIGCHLD, &sa, NULL) == -1)
    {
        errMsg("sigaction\n");
        
    }

    for(;;)
    {
        msgLen = msgrcv(serverId, &req, REQ_MSG_SIZE, 0, 0);
        if(msgLen == -1)
        {
            if(errno == EINTR)
                continue;
            errMsg("msgrcv");
            break;            
        }

        pid = fork();
        if(pid == -1)
        {
            errMsg("fork");
            break;
        }

        if(pid == 0)
        {
            serveRequest(&req);
            _exit(EXIT_SUCCESS);
        }
    }

    if(msgctl(serverId, IPC_RMID, NULL) == -1)
        errExit("msgctl");
    exit(EXIT_SUCCESS);        
}

svmsg_file_client.c

#include "svmsg_file.h"

static int clientId;

static void removeQueue( )
{
    if(msgctl(clientId, IPC_RMID, NULL) == -1)
    {
        errExit("msgctl");
    }
}

int main(int argc, char *argv[])
{
    struct requestMsg req;
    struct responseMsg resp;
    int serverId, numMsgs;
    ssize_t msgLen, totBytes;

    if(argc != 2 || strcmp(argv[1], "--help") == 0)
        usageErr("%s pathname\n", argv[0]);
    
    serverId = msgget(SERVER_KEY, S_IWUSR);
    if(serverId == -1)
        errExit("msgget - server message queue");
    
    clientId = msgget(IPC_PRIVATE, S_IRUSR | S_IWUSR | S_IWGRP);
    if(clientId == -1)
        errExit("msgget - client message queue");
    
    if(atexit(removeQueue) != 0)
        errExit("atexit");
    
    req.mtype = 1;
    req.clientId = clientId;
    strncpy(req.pathname, argv[1], sizeof(req.pathname));
    req.pathname[sizeof(req.pathname) - 1] = '\0';

    if(msgsnd(clientId, &req, REQ_MSG_SIZE, 0) == -1)
        errExit("msgsnd");
    
    msgLen = msgrcv(clientId, &req, RESP_MSG_SIZE, 0, 0);
    if(msgLen == -1)
        errExit("msgrcv");

    if(resp.mtype == RESP_MT_FAILURE)
    {
        printf("%s\n", resp.data);
        if(msgctl(clientId, IPC_RMID, NULL) == -1)
            errExit("msgctl");
        
        exit(EXIT_FAILURE);
    }

    totBytes = msgLen;
    for(numMsgs = 1; resp.mtype == RESP_MT_DATA; numMsgs++)
    {
        msgLen = msgrcv(clientId, &resp, RESP_MSG_SIZE, 0, 0);
        if(msgLen == -1)
            errExit("msgrcv");
        
        totBytes += msgLen;
    }

    printf("Receivd %ld bytes (%d message)\n", (long)totBytes, numMsgs);
    exit(EXIT_SUCCESS);       
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值