客户端输入:
ls : 显示本地文件列表
service ls: 显示服务器文件列表
upload xxx: 实现xxx文件读取与上传
download xxx : 实现xxx文件下载与存储
公共函数commonfunc.c 代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/stat.h> #include <fcntl.h> #include "commonfunc.h" #include <stddef.h> #include <dirent.h> #define BACKLOG 10//最大连接数 /******************函数作用:网络初始化*****************/ int network_init(int net_type, const char* NET_IP, short NET_NUM) { int sockfd; if(-1 == (sockfd = socket(PF_INET, SOCK_STREAM, 0))) //创建监听套接字 { perror("Create socket error!"); //exit(EXIT_FAILURE); return -1; } struct sockaddr_in sockadd; memset(&sockadd, 0, sizeof(sockadd)); sockadd.sin_family = AF_INET; sockadd.sin_port = htons(NET_NUM); sockadd.sin_addr.s_addr = inet_addr(NET_IP); if(NET_CLIENT == net_type) { //连接服务器 if(-1 == connect(sockfd, (struct sockaddr*)(&sockadd),\ sizeof(sockadd))) { perror("Connect error!"); //exit(EXIT_FAILURE); return -1; } } else { if(NET_SERVER == net_type) { //绑定IP地址端口号 if(-1 == bind(sockfd, (struct sockaddr*)(&sockadd),\ sizeof(sockadd))) { perror("Bind error!"); return -1; } if(-1 == listen(sockfd, BACKLOG)) //监听客户端 { perror("Listen error!"); return -1; } } else { return -1; } } return sockfd; } /**************************命令解析函数************************/ int ftp_cmd_analyse(const char* cmd) { if(NULL == cmd) { return CMD_ERROR; } else { if(0 == strncmp(cmd, "ls",2)) //列出本地文件列表指令 return CMD_LS; else { if(0 == strncmp(cmd, "server ls", 9)) //列出服务器文件列表指令 return CMD_SERVER_LS; else { if(0 == strcmp(cmd, "quit")) //断开链接指令 return CMD_QUIT; else { if(0 == strncmp(cmd, "download ", 9)) //从服务器下载文件指令 return CMD_DOWNLOAD; else { if(0 == strncmp(cmd, "upload ", 7)) //上传文件到服务器指令 return CMD_UPLOAD; else { return CMD_ERROR; } } } } } } } /****************从服务器端获取文件列表函数********************/ int ftp_getlist(int getsockfd) { char GET_BUFF[BUFF_LEN]; int readsize; sprintf(GET_BUFF, "server ls"); if(-1 == write(getsockfd, GET_BUFF, BUFF_LEN)) //向服务器发送命令 { perror("Send cmd error!"); return -1; } else { while(1) //循环读取 { readsize = read(getsockfd, GET_BUFF, BUFF_LEN); if(readsize <= 0) //读错误 { perror("Get list error!"); return -1; } else { if(0 == strncmp(GET_BUFF, GET_LIST_END, \ sizeof(GET_LIST_END))) //判断服务器是否发送完毕 { break; //发送完毕,退出 } else { printf("%s\n", GET_BUFF); //服务器端发送完毕,显示文件 } } } } return getsockfd; } /**************把服务器端文件列表发送到客户端函数**************/ int ftp_putlist(int putsockfd) { const char* LIST_NAME="."; char PUT_BUFF[BUFF_LEN]; int strn, strm; DIR* dp; struct dirent *ep; struct stat st; char LIST_PATH[256]; dp = opendir(LIST_NAME); //打开目录 if(NULL != dp) //打开目录成功 { while(ep = readdir(dp)) //循环读目录 { if(ep->d_name[0] != '.') //如果不是隐藏文件或目录 { sprintf(PUT_BUFF,"%s",ep->d_name); write(putsockfd, PUT_BUFF, BUFF_LEN); } } if(-1 == write(putsockfd, GET_LIST_END, BUFF_LEN)) //发送结束 { perror("Write endstring error!"); return -1; } } else { if(-1 == write(putsockfd, GET_LIST_END, BUFF_LEN)) //发送结束 { perror("Write endstring error!"); return -1; } perror("Can't open the directory!"); return -1; } closedir(dp); return putsockfd; } /*************************文件接收函数*************************/ int ftp_getfile(int getsockfd, const char* GET_FILENAME) { int getfilefd; //存放接收文件的文件描述符 int getfilesize; //实际接收的文件大小 char GET_BUFF[BUFF_LEN]; //接收缓存 //打开一个文件描述符用与保存来自发送端的文件 if(-1 == (getfilefd = open(GET_FILENAME, O_WRONLY|O_CREAT|O_TRUNC, 0666))) { perror("Can't open or creat file!"); return -1; } else { while(getfilesize = read(getsockfd, GET_BUFF, BUFF_LEN) > 0) //接收文件 { if(0 == strncmp(GET_BUFF, "ERROR:", 6)) //接收文件出错 { printf("%s", GET_BUFF); return -1; } else { //取出数据包头中包含的数据区大小 memcpy(&getfilesize, GET_BUFF, 4); /*GET_BUFF+4是因为数据包前四个字节存放的是数据长度,之后的 1024个字节才存放的实际的数据*/ if(-1 == write(getfilefd, GET_BUFF+4, getfilesize)) { perror("Download error!"); //接收出错,返回 close(getfilefd); //关闭文件 return -1; } if(getfilesize < (BUFF_LEN-4)) //已经读取到文件末尾 break; //接收结束,退出 } } close(getfilefd); //关闭文件 return getfilefd; //接收完成,返回接收到的文件的文件描述符。 } } /*****************************文件发送函数********************************/ int ftp_putfile(int putsockfd, const char* PUT_FILENAME) { int putfilefd; //存放接收文件的文件描述符 int putfilesize; //实际接收的文件大小 char PUT_BUFF[BUFF_LEN]; if(-1 == (putfilefd = open(PUT_FILENAME, O_RDONLY))) //打开文件 { perror("Open error!"); write(putsockfd, E_NOFILE, BUFF_LEN); //把错误信息写回。 /*如果不写回错误信息,发送端会卡死*/ return -1; } else { while((putfilesize = read(putfilefd, PUT_BUFF+4, (BUFF_LEN-4))) \ >0) { memcpy(PUT_BUFF, &putfilesize, 4); if(-1 == write(putsockfd, PUT_BUFF, BUFF_LEN)) { perror("Put file error!"); close(putfilefd); return -1; } memset(PUT_BUFF, 0, BUFF_LEN); //清空缓冲区 } } close(putfilefd); return putfilefd; }
//公共函数commonfunc.h头文件
#ifndef __NETWORK_H_ #define __NETWORK_H_ #define NET_SERVER 11 #define NET_CLIENT 22 #define BUFF_LEN 1028//接收发送缓冲区大小 #define CMD_LS 11//列出客户端所有文件 #define CMD_SERVER_LS 22//列出服务器所有文件 #define CMD_DOWNLOAD 33//下载文件 #define CMD_UPLOAD 44//上传文件 #define CMD_QUIT 55//退出 #define CMD_ERROR -1//错误 #define E_NOFILE "ERROR:No such file or directory!\n" #define E_DODNLOAD "ERROR:Download error!\n" #define E_UPLOAD "ERROR:Upload error!\n" #define GET_LIST_END "SUCCESS:GET LIST SUCCESS!" int network_init(int net_type, const char* IP_ADDRESS, \ short INET_NUM); void ftp_print_help(void); int ftp_cmd_analyse(const char* cmd); int ftp_getlist(int getsockfd); int ftp_putlist(int putsockfd); int ftp_getfile(int getsockfd, const char* GET_FILENAME); int ftp_putfile(int putsockfd, const char* PUT_FILENAME); #endif
//客户端程序///
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/stat.h> #include <fcntl.h> #include "commonfunc.h" #include <dirent.h> #define INET_NUM 8888 //端口号 #define IP_ADDRESS "10.104.6.110" //服务器IP #ifndef BUFF_LEN #define BUFF_LEN 1028 #endif #define CMD_LS 11//列出客户端所有文件 #define CMD_SERVER_LS 22//列出服务器所有文件 #define CMD_DOWNLOAD 33//下载文件 #define CMD_UPLOAD 44//上传文件 #define CMD_QUIT 55//退出 #define CMD_ERROR -1//错误 int main(void) { int sockfd; DIR* dp; struct dirent *ep; sockfd = network_init(NET_CLIENT, IP_ADDRESS, INET_NUM); //初始化网络连接 if(sockfd == -1) { perror("Network init error!"); exit(EXIT_FAILURE); } printf("Connect success!\n\n"); printf("*********Operation Help*********\n"); //操作帮助 printf("显示本地文件列表: ls\n"); printf("显示服务器文件列表: server ls\n"); printf("实现xxx文件读取与上传: upload xxx\n"); printf("实现xxx文件下载与存储: download xxx\n"); printf("断开socket链接: quit\n"); printf("*************************************\n\n"); char SEND_BUFF[BUFF_LEN]; //发送数据缓冲区 int cmd_result; //存放命令解析结果 while(1) { fgets(SEND_BUFF, sizeof(SEND_BUFF), stdin); //输入命令 SEND_BUFF[strlen(SEND_BUFF)-1] = '\0'; //去掉最后输入的回车符 cmd_result = ftp_cmd_analyse(SEND_BUFF); //解析输入的指令 switch(cmd_result) { case CMD_ERROR: printf("ERROR!\n"); break; case CMD_LS: //列出本地文件列表 dp=opendir ("."); printf("*********File List of Client*********\n"); while((ep = readdir(dp))) { if(ep->d_name[0] != '.') { printf("%s\n",ep->d_name); } } printf("*************************************\n"); printf("List file success!\n"); closedir(dp); break; /// case CMD_SERVER_LS: //列出服务器端可下载的所有文件 printf("*********File List of Server*********\n"); if(ftp_getlist(sockfd) == -1) { printf("List file error!\n"); } else { printf("*************************************\n"); printf("List file success!\n"); } break; case CMD_DOWNLOAD: //从服务器下载文件 if(write(sockfd, SEND_BUFF, BUFF_LEN) == -1) { perror("Send cmd error!"); break; } if(ftp_getfile(sockfd, SEND_BUFF+9) == -1) //下载文件 { printf("Download error!\n"); } else { printf("Download The File Success!!\n"); } break; case CMD_UPLOAD: //上传文件到服务器 if(write(sockfd, SEND_BUFF, BUFF_LEN) == -1) { perror("Send cmd error!"); break; } if(ftp_putfile(sockfd, SEND_BUFF+7) == -1)//上传文件 { printf("Upload error!\n"); } else { printf("Upload The File Success!!\n"); } break; case CMD_QUIT: //断开连接 printf("Welcome to use again!\nQUIT!\n"); close(sockfd);//客户端关闭文件描述符后就会自动断开连接 exit(EXIT_SUCCESS); break; default: break; } } close(sockfd);//客户端关闭文件描述符后就会自动断开连接 return 0; }
//服务器程序///
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/stat.h> #include <fcntl.h> #include "commonfunc.h" #define INET_NUM 8888 //端口号 #define IP_ADDRESS "10.104.6.110" //IP地址 #define BUFF_LEN 1028 #define CMD_LS 11 //列出客户端所有文件 #define CMD_SERVER_LS 22 //列出服务器所有文件 #define CMD_DOWNLOAD 33 //下载文件 #define CMD_UPLOAD 44 //上传文件 #define CMD_QUIT 55 //退出 #define CMD_ERROR -1 //错误 int main(void) { int sockfd; //网络套接字 sockfd = network_init(NET_SERVER, IP_ADDRESS, INET_NUM); //初始化网络连接 if(sockfd == -1) { perror("Network init error!"); exit(EXIT_FAILURE); } printf("LISTEN-ing...\n"); char RCV_BUFF[BUFF_LEN]; //接收缓存 char SEND_BUFF[BUFF_LEN]; //发送缓存 int cmd_result; //命令解析结果 int connectfd; //建立连接后用于通信的套接字文件 int readlen; //读取到的字节数 while(1) { if((connectfd = accept(sockfd, NULL, NULL)) == -1) //链接出错,给出提示 { perror("Connect error!\n"); break; } printf("Connect success!\n"); while(1) { readlen = read(connectfd, RCV_BUFF, sizeof(RCV_BUFF)); //接收命令 if(readlen <0)//接收出错 { perror("Read error!\n"); break; } else { if(readlen == 0) //客户端关闭文件描述符后就会断开连接 { printf("Welcome to use again!\nQUIT...\n"); break; } else { printf("**************************\n"); printf("RECV:%s\n",RCV_BUFF); cmd_result = ftp_cmd_analyse(RCV_BUFF); //解析命令 switch(cmd_result) { case CMD_ERROR: printf("CMD_ERROR!\n"); break; case CMD_SERVER_LS: //查看服务器文件列表 if(ftp_putlist(connectfd) == -1) { printf("List files error!\n"); } else { printf("List files success!\n"); } break; case CMD_DOWNLOAD: //客户端从服务器下载文件 printf("Put files:%s\n", RCV_BUFF+9); if(ftp_putfile(connectfd, RCV_BUFF+9) == -1) { printf("Put files error!\n"); } else { printf("Put files success!\n"); } break; case CMD_UPLOAD: //客户端上传文件到服务器 printf("Get files:%s\n", RCV_BUFF+7); if(ftp_getfile(connectfd, RCV_BUFF+7) == -1) { printf("Get files error!\n"); } else { printf("Get files success!\n"); } break; default: break; } } } } close(connectfd);//客户端退出,断开连接 } close(sockfd); return 0; }
//