使用消息队列模拟实现本地ftp

简介

  • 利用消息队列,模拟本地的一个 ftp 请求,并测试功能是否稳定。

代码

protocol.h

#ifndef _PROTOCOL_H__
#define _PROTOCOL_H__

#define PATHNAME "./protocol.h"
#define PROJID 0x00000001UL

#define PATHSIZE 128
#define DATASIZE 1024

enum{
    MSG_PARH = 1,
    MSG_DATA,
    MSG_EMPTY
};

typedef struct msg_path_st{
    long mtype;
    char path[PATHSIZE];
}msg_path_t;

typedef struct msg_data_st{
    long mtype;
    char data[DATASIZE];
    int data_len;
}msg_data_t;

typedef struct msg_empty_st{
    long mtype;
}msg_empty_t;

typedef union recv2send_un
{
    long mtype;
    msg_data_t data;
    msg_empty_t empty;
}recv2send_t;

#endif

recviver.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>

#include "./protocol.h"

int msg_send(void *data, int msgid, int msg_len){

    if (msgsnd(msgid, data, msg_len, 0) < 0)
    {
        perror("msgsnd()");
        exit(1);
    }

    return 0;
}

int parser(msg_path_t path, int msgid){

    int fd;
    msg_data_t will_send;
    msg_empty_t empty;


    fd = open(path.path, O_RDONLY);
    if(fd < 0){

        perror("open()");
        // 返回错误信息
        will_send.mtype = MSG_DATA;
        strcpy(will_send.data, "error path!");
        will_send.data_len = strlen(will_send.data);

        msg_send(&will_send, msgid, sizeof(will_send) - sizeof(long));

        empty.mtype = MSG_EMPTY;
        msg_send(&empty, msgid, 0);

        exit(1);
    }

    // 返回文件
    int pass = 0;
    struct stat stat_fd;
    int len;

    fstat(fd, &stat_fd);

    pass = 0;
    while(pass < stat_fd.st_size){

        len = read(fd, will_send.data, DATASIZE);
        will_send.data_len = len;
        pass += len;

        printf("file_size = %d, len = %d, pass = %d\n", stat_fd.st_size, len, pass);

        will_send.mtype = MSG_DATA;
        msg_send(&will_send, msgid, sizeof(will_send) - sizeof(long));
    }
    empty.mtype = MSG_EMPTY;
    msg_send(&empty, msgid, 0);

    return 0;
}

int main(){


    key_t key;
    int msgid;
    msg_path_t recv_path;

    key = ftok(PATHNAME, PROJID);
    if(key < 0){
        perror("ftok()");
        exit(1);
    }

    msgid = msgget(key, IPC_CREAT | 0644);
    if(msgid < 0){
        perror("msgget()");
        exit(1);
    }

    if(msgrcv(msgid, &recv_path, sizeof(recv_path) - sizeof(long), 0, 0) < 0){
        perror("msgsnd()");
        exit(1);
    }
    puts("read path");


    parser(recv_path, msgid);


    pause();

    msgctl(msgid, IPC_RMID, NULL);


    exit(0);
}

sender.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#include "./protocol.h"

int main(int argc, char **argv){

    if(argc < 3){
        fprintf(stderr, "Usage: ./myget /path/to/get/file /path/to/save/file\n");
        exit(0);
    }

    key_t key;
    int msgid;
    msg_path_t send_path;
    recv2send_t recv_msg;

    int fd;

    fd = open(argv[2], O_CREAT | O_TRUNC | O_WRONLY, 0644);
    if(fd < 0){
        perror("open()");
        exit(1);
    }

    key = ftok(PATHNAME, PROJID);
    if(key < 0){
        perror("ftok()");
        exit(1);
    }

    msgid = msgget(key, 0);
    if(msgid < 0){
        perror("msgget()");
        exit(1);
    }

    send_path.mtype = MSG_PARH;
    strcpy(send_path.path, argv[1]);

    if(msgsnd(msgid, &send_path, sizeof(send_path) - sizeof(long), 0) < 0){
        perror("msgsnd()");
        exit(1);
    }
    puts("send ok");

    int over = 0;
    int pass;
    int len;
    while(!over){

        if(msgrcv(msgid, &recv_msg, sizeof(recv_msg) - sizeof(long), 0, 0) < 0){
            perror("msgrcv()");
            exit(1);
        }

        switch(recv_msg.mtype){
            case MSG_DATA:

                msg_data_t temp = recv_msg.data;

                pass = 0;
                while(pass < temp.data_len){
                    
                    len = write(fd, temp.data + pass, temp.data_len);
                    printf("len = %d, data_len = %d, pass = %d\n", len, temp.data_len, pass);
                    pass += len;
                    temp.data_len -= len;

                }   
                

                break;

            case MSG_EMPTY:
                over = 1;
                break;
        }

    }

    exit(0);
}

测试

普通文件

  • 请求 /etc/services 文件,保存为 ./services
  • 准备请求
    01
  • 请求结束
    02
  • diff 两个文件,判断内容是否相同
    03

空洞文件

  • 制作一个空洞文件
dd if=/dev/urandom of=./hole-64M bs=4M count=16 seek=16
  • 准备请求
    04
  • 请求结束
    05
  • diff 文件差异
    06

请求没有权限的文件

  • 请求 /etc/shadow 文件
    07
  • 对没有权限和错误路径统一总结为 error path,且保存在输出文件中

总结

  • 程序能正确的返回请求的文件,同时对请求文件的权限也有判断和处理。

改进

  • 可以结合 socket,将程序改为不同主机之间的 ftp。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值