导言 最近学习完成了数据库和多人聊天室,想基于这些东西,设计一个老掉牙的网盘项目(才不是收到齐哥刺激)。目前是只有空闲时间能做,大概还是跟之前更新一样,大概一周一更慢慢写。
头文件 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
来接地址信息,判断pwd
和ls
可能存在无地址的情况,依据情况分别跳出。当指令是在七条指令当中时,将地址分割为多个地址字段。放入结构体当中,发送给服务端。
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); }