导言

最近学习完成了数据库和多人聊天室,想基于这些东西,设计一个老掉牙的网盘项目(才不是收到齐哥刺激)。目前是只有空闲时间能做,大概还是跟之前更新一样,大概一周一更慢慢写。

头文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* Usage: 实现收发功能,收消息没有限制,发消息需要信号,Switch判断发送,结构体发送指令,接收消息,接收文件*/
#ifndef CLIENT_H
#define CLIENT_H

#include "my_header.h"
#include <arpa/inet.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>

typedef struct SignalSend{
int sig_t; //用数字代替信号
int size; //路径个数
char pathname[12][32]; //接收路径
}SignalSend;

typedef struct FileBuf{
int sig_t; //用数字代替信号
int size; //路径长度
char buf[1024]; //接收路径
}FileBuf;

int SockfdCreate(char *argv1,char* argv2);
int EpollCreate(int sockfd);
int SendCommand(int sockfd, char* buf);
void RecvMsg(int sockfd);
int TransFile(int sockfd, char *pathname);
int RecvFile(int sockfd);

#endif

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "Client.h"
int main(int argc, char *argv[]){
//./client 127.0.0.1 1234
ARGS_CHECK(argc, 3);
int sockfd = SockfdCreate(argv[1], argv[2]);
int epfd = EpollCreate(sockfd);

struct epoll_event readyset[2];

while(1){
char buf[1024];
memset(buf, 0, 1024);

int readynum = epoll_wait(epfd, readyset, 2, -1);
for(int i = 0; i < readynum; ++i){
if(readyset[i].data.fd == STDIN_FILENO){
//接收反馈
ssize_t ret = read(STDIN_FILENO, buf, sizeof(buf));
if(ret <= 0){
printf("Exiting...\n");
goto end;
}
SendCommand(sockfd, buf);
}else{
RecvMsg(sockfd);
}
}
}
end:
close(sockfd);
close(epfd);
return 0;
}

本来要写线程,但是做了之后又不是很理想,写了又给拆了,目前考虑函数拆分,多个文件做整理。目前客户端安排接收服务端信息,发送我的指令。核心的函数SendCommand(sockfd, buf)RecvMsg(sockfd)

初始化

在函数里实现初始化,尽可能让主函数负责单独的事。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include "Client.h"
int SockfdCreate(char *argv1,char* argv2){
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
ERROR_CHECK(sockfd, -1, "socket");
struct sockaddr_in serveraddr;
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv2));
serveraddr.sin_addr.s_addr = inet_addr(argv1);
int cret = connect(sockfd, (struct sockaddr*) &serveraddr, sizeof(serveraddr));
ERROR_CHECK(cret, -1, "connect");
printf("Server has been connected\n");
return sockfd;
}
int EpollCreate(int sockfd){
int epfd = epoll_create(1);
ERROR_CHECK(epfd, -1, "epoll_create");

struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = STDIN_FILENO;
epoll_ctl(epfd, EPOLL_CTL_ADD, STDIN_FILENO, &event);

event.data.fd = sockfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &event);

return epfd;
}

接发信号

序号

根据指令返回序号,方便传输信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include "Client.h"
int Command(char *cmd){
if(strcmp(cmd, "cd") == 0) {
return 0;
}else if (strcmp(cmd, "ls") == 0) {
return 1;
}else if (strcmp(cmd, "pwd") == 0) {
return 2;
}else if (strcmp(cmd, "puts") == 0) {
return 3;
}else if (strcmp(cmd, "gets") == 0) {
return 4;
}else if (strcmp(cmd, "remove") == 0) {
return 5;
}else if (strcmp(cmd, "mkdir") == 0) {
return 6;
}else if (strcmp(cmd, "rmdir") == 0) {
return 7;
}else {
return -1;
}
}

发送信息

strtok函数跳过分隔符,用msgcmd来接地址信息,判断pwdls可能存在无地址的情况,依据情况分别跳出。当指令是在七条指令当中时,将地址分割为多个地址字段。放入结构体当中,发送给服务端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
int SendCommand(int sockfd, char* buf){
char *cmd = strtok(buf, " \n");
if(cmd == NULL){
printf("Error no command\n");
return 0;
}
int sig_t = Command(cmd);

char *msgcmd = strtok(NULL, " \n");

if (msgcmd == NULL && sig_t != 2 && sig_t != 1) { // pwd命令不需要参数
printf("Error no path\n");
return 0;
}

if (strtok(NULL, " \n") != NULL) {
printf("Error more command\n");
return 0;
}

if(sig_t >= 0 && sig_t <= 7 ){
SignalSend *sig = (SignalSend *)malloc(sizeof(SignalSend));
memset(sig, 0, sizeof(SignalSend));
sig->sig_t = sig_t;
sig->size = 0;
if(sig->sig_t != 2){
if(msgcmd != NULL){
if(strncmp(msgcmd, "/", 1) == 0){
memcpy(sig->pathname[sig->size], "/", sizeof("/"));
printf("%s\n",sig->pathname[sig->size]);
ERROR_CHECK(sig->pathname[sig->size], NULL, "strdup");
++ sig->size;
}
char *msg = strtok(msgcmd, "/");
while (msg != NULL && sig->size < 13){
memcpy(sig->pathname[sig->size], msg, strlen(msg));
++ sig->size;
printf("%s\n",sig->pathname[sig->size]);
msg = strtok(NULL, "/");
}
}
}
printf("%d\n", sig->size);
send(sockfd, sig, sizeof(SignalSend), 0);
free(sig);
return 1;
}else{
printf("error cmd_id\n");
return 0;
}
}

接收信号

发送信号后,服务端返回信息,根据返回的信息做出相应的判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void RecvMsg(int sockfd){
//接收到信号值
FileBuf *msg = (FileBuf *)malloc(sizeof(FileBuf));
memset(msg, 0, sizeof(FileBuf));
ssize_t ret = recv(sockfd, msg, sizeof(FileBuf), 0);
if(ret <= 0){
printf("Server exit\n");
exit(1);
}
printf("Command == %d\n", msg->sig_t);
//根据命令情况返回结果
if(msg->sig_t == 3){
TransFile(sockfd, msg->buf); //服务端此处只需要文件名
}else if(msg->sig_t == 4){
RecvFile(sockfd);
}else{
printf("msg->size == %d, msg->buf == %s\n", msg->size, msg->buf);
}
free(msg);
}