网络-TCP服务器实现FTP仿写功能

avatar
作者
猴君
阅读量:4

目录

1.要求

2. 功能思想

2.1 list功能思想:

2.2 put filename功能思想:

3.功能代码

3.1 list 服务器向客户端发送目录

3.2 put 服务器接收客户端文件

3.3 get 服务器向客户端发送文件

3.4 功能判断

4.完整代码

4.1 服务器端完整代码

4.2 客户端完整代码


1.要求

模拟FTP核心原理:客户端连接服务器后,向服务器发送一个文件。文件名可以通过参数指定,服务器端接收客户端传来的文件(文件名随意),如果文件不存在自动创建文件,如果文件存在,那么清空文件然后写入。

项目功能介绍:

均有服务器和客户端代码,基于TCP写的。

客户端和服务器链接成功后出现以下提示:四个功能

***************list**************//列出服务器所在目录下的普通文件名

***********put filename**********//从客户端所在路径上传文件

***********get filename**********//从服务器所在路径下载文件

**************quit***************//退出(可只退出客户端,服务器等待下一个客户端链接)

2. 功能思想

2.1 list功能思想:

list:客户端输入list-------》把list发送给服务器--------》判断是否为list-------》目录操作-----》循环读目录文件-----》判断是否为普通文件-------》是普通文件就发送给客户端-----》客户端接收并打印到终端---------》发送一个结束的标志

2.2 put filename功能思想:

put filename(cp):客户端输入put 文件名------》把put 文件名发送给服务器------》服务器判断是否为put ---------》(cp:源文件在客户端所在路径下,目标文件在服务器所在路径下)---》客户端循环读源文件内容发送给服务器,服务器循环接收客户端内容,写到目标文件里---------》发送一个结束的标志

3.功能代码

3.1 list 服务器向客户端发送目录

服务器端:获取服务器端目录,并发送给客户端

// 获取服务器目录 void list(int acceptfd) {     DIR *dir;     dir = opendir("./"); // 打开服务器所在目录     struct dirent *list; // 定义指向目录文件的指针     struct stat st;      // 保存文件属性、      // 循环读取目录下的文件     while ((list = readdir(dir)) != NULL)     {         stat(list->d_name, &st);                  // 获取文件类型         if ((st.st_mode & __S_IFMT) == __S_IFREG) // 判断是否为普通文件         {             // 把文件名字发送给客户端             send(acceptfd, list->d_name, sizeof(list->d_name), 0);         }     }     send(acceptfd, "end", 128, 0); // 向客户端发送结束标志 } 

客户端:接收服务器端发送的目录并输出

// 获取服务器目录下文件 void list(int acceptfd) {     int ret;     char buf[128] = {0};      // 循环接收服务器发送的目录信息     while (1)     {         memset(buf, 0, sizeof(buf));         ret = recv(acceptfd, buf, sizeof(buf), 0);          if (ret < 0)         {             perror("recv err");             return;         }          if (strcmp(buf, "end") == 0) // 服务器发送结束             break;         else             printf("%s ", buf);     }     printf("\n");     return; }

3.2 put 服务器接收客户端文件

服务器端:接收客户端发送的文件

// 服务器下载文件 void putfile(int acceptfd, char *p) {     int putfd;     char buf[128] = ""; // 暂存接收的内容     ssize_t num;        // 实际接收的字符个数      // 打开文件:如果没有,需要创建;如果有了,清空文件     putfd = open(p + 4, O_WRONLY | O_CREAT | O_TRUNC, 0755);     if (putfd < 0)     {         perror("open put file err");         return;     }      // 循环接收客户端发来的消息     while (1)     {         memset(buf, 0, sizeof(buf));         num = recv(acceptfd, buf, sizeof(buf), 0);         if (num < 0)         {             perror("recv error");             return;         }         if (strcmp(buf, "end") == 0) // end结束         {             break;         }         else         {             write(putfd, buf, strlen(buf)); // 向文件中写入         }     }      close(putfd);     return; }

客户端代码:向服务器发送文件

// 向服务器上传文件 void putfile(int acceptfd, char *p) {     int putfd;     char buf[128] = "";     size_t num;     // 上传文件给服务器     // 打开源文件     putfd = open(p + 4, O_RDONLY);     if (putfd < 0)     {         perror("open err");         return;     }     // 循环读原文件发送给服务器     while (1)     {         memset(buf, 0, sizeof(buf));         num = read(putfd, buf, sizeof(buf) - 1);         buf[num] = '\0';          if (num == 0) // 文件发送完毕         {             send(acceptfd, "end", 128, 0);             printf("send end\n");             break;         }         send(acceptfd, buf, 128, 0);     }      close(putfd);     return; }

3.3 get 服务器向客户端发送文件

服务器端:向客户端发送文件

// 服务器发送文件 void getfile(int acceptfd, char *p) {     int getfd;     char buf[128] = "";     ssize_t num; // num读取个数      // 打开需要发送给客户端的文件     getfd = open(p + 4, O_RDONLY);     if (getfd < 0)     {         perror("open get file error");         return;     }      // 循环读取文件发送给客户端     while (1)     {         memset(buf, 0, sizeof(buf));         num = read(getfd, buf, sizeof(buf) - 1);         buf[num] = '\0';         if (num == 0) // 判断是否发送完毕         {             send(acceptfd, "end", 128, 0);             printf("发送完毕\n");             break;         }          send(acceptfd, buf, 128, 0); // 发送内容到客户端         memset(buf, 0, sizeof(buf));     }      close(getfd);     return; }

客户端:客户端接收服务器发送的文件

// 从服务器下载文件 void getfile(int acceptfd, char *p) {     int getfd;     ssize_t num;     char buf[128] = "";      // 打开文件     getfd = open(p + 4, O_WRONLY | O_CREAT | O_TRUNC, 0666);     if (getfd < 0)     {         perror("open  err");         return;     }     // 循环接收客户端发来消息,写到目标文件里     while (1)     {         memset(buf, 0, sizeof(buf));         num = recv(acceptfd, buf, sizeof(buf), 0);         if (num < 0)         {             perror("recv err");             return;         }          if (strcmp(buf, "end") == 0)         {             printf("接收结束\n");             break;         }         else         {             write(getfd, buf, strlen(buf));         }     }     close(getfd);     return; }

3.4 功能判断

服务器端:接收客户端发送的命令

// 6.接收客户端的命令         char buf[128] = "";         ssize_t num;         while (1)         {             // 每次接收前清空buf             memset(buf, 0, sizeof(buf));             num = recv(acceptfd, buf, sizeof(buf), 0);             // num为接收到的字符个数             if (num < 0) // 接收失败             {                 perror("recv error");                 return -1;             }             else if (num == 0) // 客户端退出             {                 perror("client exit");                 break;             }             else // 正常接收到字符             {                 printf("buf: %s \n", buf);             }              // 判断命令操作             if (strncmp(buf, "list", 4) == 0) // 获取目录             {                 list(acceptfd);             }             else if (strncmp(buf, "put ", 4) == 0) // 接收客户端文件             {                  putfile(acceptfd, buf);             }             else if (strncmp(buf, "get ", 4) == 0) // 向客户端发送文件             {                 getfile(acceptfd, buf);             }             else if (strcmp(buf, "quit") == 0) // 退出             {                 break;             }         }

客户端:判断终端输入的命令

// 4.发送/接收数据    send()/recv()     // 一旦连接服务器成功以后,从终端获取用户输入的数据,然后发送给服务器     while (1)     {         help();         // 从终端获取命令         fgets(buf, sizeof(buf), stdin);         if (buf[strlen(buf) - 1] == '\n')         {             buf[strlen(buf) - 1] = '\0';         }          send(clientfd, buf, sizeof(buf), 0);          if (strcmp("list", buf) == 0) // 接收服务器发来的文件名         {             list(clientfd);         }         else if (strncmp("put ", buf, 4) == 0) // 上传文件给服务器         {             putfile(clientfd, buf);         }         else if (strncmp("get ", buf, 4) == 0) // 从服务器下载文件         {             getfile(clientfd, buf);         }         else if (strcmp("quit", buf) == 0)             break;     }

4.完整代码

4.1 服务器端完整代码

#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdio.h> #include <sys/types.h> #include <netinet/ip.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <dirent.h> #include <stdlib.h>  // 菜单 void help() {     printf("***************list**************\n");   // 列出服务器所在目录下的普通文件名     printf("***********put <filename>**********\n"); // 从客户端所在路径上传文件     printf("***********get <filename>**********\n"); // 从服务器所在路径下载文件     printf("**************quit***************\n");   // 退出(可只退出客户端,服务器等待下一个客户端链接) }  // 获取服务器目录 void list(int acceptfd) {     DIR *dir;     dir = opendir("./"); // 打开服务器所在目录     struct dirent *list; // 定义指向目录文件的指针     struct stat st;      // 保存文件属性、      // 循环读取目录下的文件     while ((list = readdir(dir)) != NULL)     {         stat(list->d_name, &st);                  // 获取文件类型         if ((st.st_mode & __S_IFMT) == __S_IFREG) // 判断是否为普通文件         {             // 把文件名字发送给客户端             send(acceptfd, list->d_name, sizeof(list->d_name), 0);         }     }     send(acceptfd, "end", 128, 0); // 向客户端发送结束标志 }  // 服务器下载文件 void putfile(int acceptfd, char *p) {     int putfd;     char buf[128] = ""; // 暂存接收的内容     ssize_t num;        // 实际接收的字符个数      // 打开文件:如果没有,需要创建;如果有了,清空文件     putfd = open(p + 4, O_WRONLY | O_CREAT | O_TRUNC, 0755);     if (putfd < 0)     {         perror("open put file err");         return;     }      // 循环接收客户端发来的消息     while (1)     {         memset(buf, 0, sizeof(buf));         num = recv(acceptfd, buf, sizeof(buf), 0);         if (num < 0)         {             perror("recv error");             return;         }         if (strcmp(buf, "end") == 0) // end结束         {             break;         }         else         {             write(putfd, buf, strlen(buf)); // 向文件中写入         }     }      close(putfd);     return; }  // 服务器发送文件 void getfile(int acceptfd, char *p) {     int getfd;     char buf[128] = "";     ssize_t num; // num读取个数      // 打开需要发送给客户端的文件     getfd = open(p + 4, O_RDONLY);     if (getfd < 0)     {         perror("open get file error");         return;     }      // 循环读取文件发送给客户端     while (1)     {         memset(buf, 0, sizeof(buf));         num = read(getfd, buf, sizeof(buf) - 1);         buf[num] = '\0';         if (num == 0) // 判断是否发送完毕         {             send(acceptfd, "end", 128, 0);             printf("发送完毕\n");             break;         }          send(acceptfd, buf, 128, 0); // 发送内容到客户端         memset(buf, 0, sizeof(buf));     }      close(getfd);     return; }  int main(int argc, char const *argv[]) {      int res;     int serverfd; // 服务器fd     int acceptfd;      // 1.创建流式套接字     serverfd = socket(AF_INET, SOCK_STREAM, 0);     if (serverfd < 0)     {         perror("serverfd socket error");         ;         return -1;     }     printf("server socket scuess\n");      // 2.指定本地的网络信息  struct sockaddr_in     // 定义结构体变量 myaddr     struct sockaddr_in myaddr;      // 长度     socklen_t addrlen = sizeof(myaddr);      memset(&myaddr, 0, addrlen);     myaddr.sin_family = AF_INET; // ipv4族     myaddr.sin_addr.s_addr = INADDR_ANY;     myaddr.sin_port = htons(atoi(argv[1])); // 端口      // 3.绑定套接字  bind()     // 绑定自己的地址     res = bind(serverfd, (struct sockaddr *)&myaddr, addrlen);     if (res < 0)     {         perror("bind error");         return -1;     }     printf("bind scuess\n");      // 4.监听套接字  listen()     res = listen(serverfd, 5);     if (res < 0)     {         perror("listen error");         return -1;     }     printf("listen scuess\n");      // 5.链接客户端的请求  accept()     // 定义代表客户端的结构体变量     struct sockaddr_in acceptaddr;     while (1)     {         acceptfd = accept(serverfd, (struct sockaddr *)&acceptaddr, &addrlen);         if (acceptfd < 0)         {             perror("accept error");             return -1;         }         printf("acceptfd: %d \n", acceptfd);         printf("新的连接过来了\n");         printf("ip = %s, port = %d\n", inet_ntoa(acceptaddr.sin_addr),                ntohs(acceptaddr.sin_port));         help();          // 6.接收客户端的命令         char buf[128] = "";         ssize_t num;         while (1)         {             // 每次接收前清空buf             memset(buf, 0, sizeof(buf));             num = recv(acceptfd, buf, sizeof(buf), 0);             // num为接收到的字符个数             if (num < 0) // 接收失败             {                 perror("recv error");                 return -1;             }             else if (num == 0) // 客户端退出             {                 perror("client exit");                 break;             }             else // 正常接收到字符             {                 printf("buf: %s \n", buf);             }              // 判断命令操作             if (strncmp(buf, "list", 4) == 0) // 获取目录             {                 list(acceptfd);             }             else if (strncmp(buf, "put ", 4) == 0) // 接收客户端文件             {                  putfile(acceptfd, buf);             }             else if (strncmp(buf, "get ", 4) == 0) // 向客户端发送文件             {                 getfile(acceptfd, buf);             }             else if (strcmp(buf, "quit") == 0) // 退出             {                 break;             }         }         close(acceptfd);     }      close(serverfd);      return 0; } 

4.2 客户端完整代码

#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <arpa/inet.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <sys/stat.h> #include <dirent.h> #include <fcntl.h>  // 菜单 void help() {     printf("***************list**************\n");   // 列出服务器所在目录下的普通文件名     printf("***********put <filename>**********\n"); // 从客户端所在路径上传文件     printf("***********get <filename>**********\n"); // 从服务器所在路径下载文件     printf("**************quit***************\n");   // 退出(可只退出客户端,服务器等待下一个客户端链接) }  // 获取服务器目录下文件 void list(int acceptfd) {     int ret;     char buf[128] = {0};      // 循环接收服务器发送的目录信息     while (1)     {         memset(buf, 0, sizeof(buf));         ret = recv(acceptfd, buf, sizeof(buf), 0);          if (ret < 0)         {             perror("recv err");             return;         }          if (strcmp(buf, "end") == 0) // 服务器发送结束             break;         else             printf("%s ", buf);     }     printf("\n");     return; }  // 向服务器上传文件 void putfile(int acceptfd, char *p) {     int putfd;     char buf[128] = "";     size_t num;     // 上传文件给服务器     // 打开源文件     putfd = open(p + 4, O_RDONLY);     if (putfd < 0)     {         perror("open err");         return;     }     // 循环读原文件发送给服务器     while (1)     {         memset(buf, 0, sizeof(buf));         num = read(putfd, buf, sizeof(buf) - 1);         buf[num] = '\0';          if (num == 0) // 文件发送完毕         {             send(acceptfd, "end", 128, 0);             printf("send end\n");             break;         }         send(acceptfd, buf, 128, 0);     }      close(putfd);     return; }  // 从服务器下载文件 void getfile(int acceptfd, char *p) {     int getfd;     ssize_t num;     char buf[128] = "";      // 打开文件     getfd = open(p + 4, O_WRONLY | O_CREAT | O_TRUNC, 0666);     if (getfd < 0)     {         perror("open  err");         return;     }     // 循环接收客户端发来消息,写到目标文件里     while (1)     {         memset(buf, 0, sizeof(buf));         num = recv(acceptfd, buf, sizeof(buf), 0);         if (num < 0)         {             perror("recv err");             return;         }          if (strcmp(buf, "end") == 0)         {             printf("接收结束\n");             break;         }         else         {             write(getfd, buf, strlen(buf));         }     }     close(getfd);     return; }  int main(int argc, char const *argv[]) {      int clientfd;     char buf[128] = "";     ssize_t num;      // 1.创建流式套接字     clientfd = socket(AF_INET, SOCK_STREAM, 0);     if (clientfd < 0)     {         perror("clientfd socket error");         return -1;     }     printf("client socket scuess\n");      // 2.指定服务器的网络信息    struct sockaddr_in     // 定义结构体变量 server_addr     struct sockaddr_in server_addr;      server_addr.sin_family = AF_INET;                 // ipv4族     server_addr.sin_addr.s_addr = inet_addr(argv[1]); // ip地址     server_addr.sin_port = htons(atoi(argv[2]));      // 端口      // 3.请求链接服务器   connect()     // 长度     socklen_t addrlen = sizeof(server_addr);      // 客户端的socket连接服务器     int ret = connect(clientfd, (struct sockaddr *)&server_addr, addrlen);     if (ret < 0)     {         perror("connect err");         return -1;     }     printf("connect scuess\n");      // 4.发送/接收数据    send()/recv()     // 一旦连接服务器成功以后,从终端获取用户输入的数据,然后发送给服务器     while (1)     {         help();         // 从终端获取命令         fgets(buf, sizeof(buf), stdin);         if (buf[strlen(buf) - 1] == '\n')         {             buf[strlen(buf) - 1] = '\0';         }          send(clientfd, buf, sizeof(buf), 0);          if (strcmp("list", buf) == 0) // 接收服务器发来的文件名         {             list(clientfd);         }         else if (strncmp("put ", buf, 4) == 0) // 上传文件给服务器         {             putfile(clientfd, buf);         }         else if (strncmp("get ", buf, 4) == 0) // 从服务器下载文件         {             getfile(clientfd, buf);         }         else if (strcmp("quit", buf) == 0)             break;     }      close(clientfd);      return 0; } 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!