简介
- 利用消息队列,模拟本地的一个 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
- 准备请求
- 请求结束
- diff 两个文件,判断内容是否相同
空洞文件
dd if=/dev/urandom of=./hole-64M bs=4M count=16 seek=16
请求没有权限的文件
- 请求 /etc/shadow 文件
- 对没有权限和错误路径统一总结为 error path,且保存在输出文件中
总结
- 程序能正确的返回请求的文件,同时对请求文件的权限也有判断和处理。
改进
- 可以结合 socket,将程序改为不同主机之间的 ftp。