利用原始socket简单实现FTP的客户端和服务器端程序
来源:互联网 发布:vue.js是谁开发的 编辑:程序博客网 时间:2024/06/12 00:11
1.设计目的
本设计旨在利用原始socket简单实现FTP(File Transfer Protocol,文件传输协议)的客户端和服务器端程序,能够实现get、put、pwd、dir、cd等基本交互命令。
2.具体要求
用socket 编程接口编写两个程序,分别为客户程序(client.c)和服务器程序(server.c),该程序应能实现下述命令功能:
get:取远方的一个文件
put:传给远方一个文件
pwd:显示远主当前目录
dir:列出远方当前目录
cd :改变远方当前目录
? :显示你提供的命令
quit :退出返回
3.程序实现
3.1 client.c(客户端代码实现)
#include "Winsock.h"#include "windows.h" #include "stdio.h" #include "time.h" #include <iostream>using namespace std;#define RECV_PORT 3312 #define SEND_PORT 4302 #pragma comment(lib, "wsock32.lib")SOCKET sockclient;char filename[20]; //文件名 sockaddr_in ServerAddr; //服务器地址 char rbuff[1024]; //接收缓冲区 char sbuff[1024]; //发送缓冲区 char InputIP[20]; //存储输入的服务器IPvoid help()//处理help{ cout << " 欢迎进入迷你FTP帮助菜单 " << endl<< " * * * * * * * * * * * * * * * * * * * * * " << endl<< " 1.get....................下载(接受)文件 " << endl<< " get的用法: get 文件名 " << endl << endl<< " 2.put.................上传(发送)文件 " << endl<< " put的用法:put 文件名 " << endl<< " 3.pwd..........显示当前文件夹的绝对路径 " << endl<< " 4.dir............显示远方当前目录的文件 " << endl << endl<< " 5.cd.............改变远方当前目录和路径 " << endl<< " cd的用法(进入下级目录): cd 路径名 " << endl<< " cd的用法(进入上级目录): cd .. " << endl << endl<< " 6.?或者help................进入帮助菜单 " << endl<< " 7.quit..........................退出FTP " << endl<< " * * * * * * * * * * * * * * * * * * * * * " << endl;void list(SOCKET sockfd){ int nRead; while (true) { nRead = recv(sockclient, rbuff, 1024, 0); //recv函数通过sockclient套接口接受数据存入rbuff缓冲区,返回接受到的字节数 if (nRead == SOCKET_ERROR) { printf("read response error!\n"); exit(1); } if (nRead == 0)//数据读取结束 break; //显示数据 rbuff[nRead] = '\0'; printf("%s", rbuff); }}/*********************** put:传给远方一个文件***************************/int SendFile(SOCKET datatcps, FILE* file){ printf(" sending file data.."); for (;;) //从文件中循环读取数据并发送客户端 { int r = fread(sbuff, 1, 1024, file);//fread函数从file文件读取1个1024长度的数据到sbuff,返回成功读取的元素个数 if (send(datatcps, sbuff, r, 0) == SOCKET_ERROR) { printf("lost the connection to client!\n"); closesocket(datatcps); return 0; } if (r<1024) //文件传送结束 break; } closesocket(datatcps); printf("done\n"); return 1;}DWORD StartSock()//启动winsock { WSADATA WSAData; char a[20]; memset(a, 0, 20); if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)//加载winsock版本 { printf("sock init fail!\n"); return (-1); } if (strncmp(InputIP, a, 20) == 0) { printf("请输入连接的主机IP:"); scanf("%s", &InputIP); } //设置地址结构 ServerAddr.sin_family = AF_INET;//AF_INET表示使用IP地址族 ServerAddr.sin_addr.s_addr = inet_addr(InputIP);//指定服务器IP ServerAddr.sin_port = htons(RECV_PORT);//设置端口号 return(1);}//创建套接字 DWORD CreateSocket(){ sockclient = socket(AF_INET, SOCK_STREAM, 0);//当socket函数成功调用时返回一个新的SOCKET(Socket Descriptor) if (sockclient == SOCKET_ERROR) { printf("sockclient create fail! \n"); WSACleanup(); return(-1); } return(1);}DWORD CallServer() //发送连接请求 { CreateSocket(); if (connect(sockclient, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR) {//connect函数创建与指定外部端口的连接 printf("Connect fail \n"); memset(InputIP, 0, 20); return(-1); } return(1);}DWORD TCPSend(char data[]) //发送命令 { int length; length = send(sockclient, data, strlen(data), 0); //send函数通过sockclient接口发送data里面的数据,发送成功返回发送的字节数 if (length <= 0) { printf("send data error ! \n"); closesocket(sockclient); WSACleanup(); return(-1); } return(1);}int main(){ char messge1[10]; //定义输入要处理的文件名 char messge2[20]; //定义输入要处理的文件名 char order[30]; //输入的命令 order[0] = '\0'; char buff[80]; //用以存储经过字串格式化的order FILE *fd; //File协议主要用于访问本地计算机中的文件,fd指针指向要访问的目标文件 FILE *fd2; int count; int sin_size = sizeof(ServerAddr); StartSock(); if (CallServer() == -1) return main(); //发送连接请求失败,返回主函数 printf("\n请输入命令(输入?或help进入帮助菜单):\n"); memset(buff, 0, 80); //清空数组 memset(messge2, 0, 20); memset(order, 0, 30); memset(messge1, 0, 10); memset(rbuff, 0, 1024); memset(sbuff, 0, 1024); scanf("%s", &messge1);//s%输入字符串 if (strncmp(messge1, "get", 3) == 0) scanf("%s", &messge2); if (strncmp(messge1, "put", 3) == 0) scanf("%s", &messge2); if (strncmp(messge1, "cd", 2) == 0) scanf("%s", &messge2); strcat(order, messge1); //把messge1加在order的末尾 strcat(order, " "); //命令中间的空格 strcat(order, messge2); //把messge2加在order的末尾 sprintf(buff, order); //把调整格式的order存入buff //help和? if (strncmp(messge1, "help", 4) == 0) { help(); } if (strncmp(messge1, "?", 1) == 0){ help(); } if (strncmp(messge1, "quit", 4) == 0) { printf(" 欢迎再次进入迷你FTP,谢谢使用!\n"); closesocket(sockclient); WSACleanup(); return 0; } TCPSend(buff);//发送buff里面的数据 recv(sockclient, rbuff, 1024, 0); printf(rbuff); if (strncmp(rbuff, "get", 3) == 0) //get { fd = fopen(messge2, "wb");//使用二进制方式,打开文件,wb只写打开或新 建一个二进制文件;只允许写数据。 if (fd == NULL) { printf("open file %s for weite failed!\n", messge2); return 0; } while ((count = recv(sockclient, rbuff, 1024, 0))>0) { fwrite(rbuff, sizeof(rbuff), count, fd); } //把count个数据长度为size0f()的数据从 rbuff输入到fd指向的目标文件 fclose(fd); //关闭文件 } if (strncmp(rbuff, "put", 3) == 0) //put { strcpy(filename, rbuff + 9); fd2 = fopen(filename, "rb");//rb读写打开一个二进制文件,只允许读写数据。 if (fd2) { if (!SendFile(sockclient, fd2)){ printf("send failed!"); return 0; } fclose(fd2); }//关闭文件 else//打开文件失败 { strcpy(sbuff, "can't open file!\n"); if (send(sockclient, sbuff, 1024, 0)) return 0; } } if (strncmp(rbuff, "dir", 3) == 0) //dir { printf("\n"); list(sockclient); //列出接受到的列表内容 } if (strncmp(rbuff, "pwd", 3) == 0) { list(sockclient); //列出接受到的内容--绝对路径 } if (strncmp(rbuff, "cd", 2) == 0){} //cd closesocket(sockclient); //关闭连接 WSACleanup(); //释放Winsock return main();}
3.2 server.c(服务端代码实现)
#include "Winsock.h" #include "windows.h" #include "stdio.h" #define RECV_PORT 3312 #define SEND_PORT 4302 #pragma comment(lib, "wsock32.lib")SOCKET sockclient, sockserver; struct sockaddr_in ServerAddr;//服务器地址 struct sockaddr_in ClientAddr;//客户端地址 /***********************全局变量***********************/int Addrlen;//地址长度 char filename[20];//文件名 char order[10];//命令 char rbuff[1024];//接收缓冲区 char sbuff[1024];//发送缓冲区 DWORD StartSock() //初始化winsock { WSADATA WSAData; if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0) { printf("socket init fail!\n"); return (-1); } return(1);}DWORD CreateSocket(){ sockclient = socket(AF_INET, SOCK_STREAM, 0); if (sockclient == SOCKET_ERROR) { printf("sockclient create fail ! \n"); WSACleanup(); return(-1); } ServerAddr.sin_family = AF_INET; ServerAddr.sin_addr.s_addr = htonl(INADDR_ANY); ServerAddr.sin_port = htons(RECV_PORT); if (bind(sockclient, (struct sockaddr FAR *)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR) { //bind函数将套接字和地址结构绑定 printf("bind is the error"); return(-1); } return (1);}int SendFileRecord(SOCKET datatcps, WIN32_FIND_DATA *pfd) //用来发送当前文件记录 { char filerecord[MAX_PATH + 32]; FILETIME ft; //文件建立时间 FileTimeToLocalFileTime(&pfd->ftLastWriteTime, &ft); SYSTEMTIME lastwtime; //SYSTEMTIME系统时间数据结构 FileTimeToSystemTime(&ft, &lastwtime); char *dir = pfd->dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY ? "<DIR>" : " "; sprintf(filerecord, "%04d-%02d-%02d %02d:%02d %5s %10d %-20s\n", lastwtime.wYear, lastwtime.wMonth, lastwtime.wDay, lastwtime.wHour, lastwtime.wMinute, dir, pfd->nFileSizeLow, pfd->cFileName); if (send(datatcps, filerecord, strlen(filerecord), 0) == SOCKET_ERROR) { //通过datatcps接口发送filerecord数据,成功返回发送的字节数 printf("Error occurs when sending file list!\n"); return 0; } return 1;}int SendFileList(SOCKET datatcps){ HANDLE hff;//建立一个线程 WIN32_FIND_DATA fd; //搜索文件 //可以通过FindFirstFile()函数根据当前的文件存放路径查找该文件来把待操作文件的相关属性读取到WIN32_FIND_DATA结构中去 if (hff == INVALID_HANDLE_VALUE)//发生错误 { const char *errstr = "can't list files!\n"; printf("list file error!\n"); if (send(datatcps, errstr, strlen(errstr), 0) == SOCKET_ERROR) { printf("error occurs when senging file list!\n"); } closesocket(datatcps); return 0; } BOOL fMoreFiles = TRUE; while (fMoreFiles) {//发送此项文件信息 if (!SendFileRecord(datatcps, &fd)) { closesocket(datatcps); return 0; } //搜索下一个文件 fMoreFiles = FindNextFile(hff, &fd); } closesocket(datatcps); return 1;}int SendFile(SOCKET datatcps, FILE* file){ printf(" sending file data.."); for (;;) //从文件中循环读取数据并发送客户端 { int r = fread(sbuff, 1, 1024, file);//把file里面的内容读到sbuff缓冲区 if (send(datatcps, sbuff, r, 0) == SOCKET_ERROR) { printf("lost the connection to client!\n"); closesocket(datatcps); return 0; } if (r<1024)//文件传送结束 break; } closesocket(datatcps); printf("done\n"); return 1;}//连接 DWORD ConnectProcess(){ Addrlen = sizeof(ClientAddr); if (listen(sockclient, 5)<0) { printf("Listen error"); return(-1); } printf("服务器监听中...\n"); for (;;) { sockserver = accept(sockclient, (struct sockaddr FAR *)&ClientAddr, &Addrlen); //accept函数取出连接队列的第一个连接请求,sockclient是处于监听的套接字ClientAddr 是监听的对象地址, //Addrlen是对象地址的长度 for (;;) { memset(rbuff, 0, 1024); memset(sbuff, 0, 1024); if (recv(sockserver, rbuff, 1024, 0) <= 0) { break; } printf("\n"); printf("获取并执行的命令为:"); printf(rbuff); if (strncmp(rbuff, "get", 3) == 0) { strcpy(filename, rbuff + 4); printf(filename); FILE *file; //定义一个文件访问指针 //处理下载文件请求 file = fopen(filename, "rb");//打开下载的文件,只允许读写 if (file) { sprintf(sbuff, "get file %s\n", filename); if (!send(sockserver, sbuff, 1024, 0)) { fclose(file); return 0; } else {//创建额外数据连接传送数据 if (!SendFile(sockserver, file)) return 0; fclose(file); } }//file else//打开文件失败 { strcpy(sbuff, "can't open file!\n"); if (send(sockserver, sbuff, 1024, 0)) return 0; } //lost }//get if (strncmp(rbuff, "put", 3) == 0) { FILE *fd; int count; strcpy(filename, rbuff + 4); fd = fopen(filename, "wb"); if (fd == NULL) { printf("open file %s for weite failed!\n", filename); return 0; } sprintf(sbuff, "put file %s", filename); if (!send(sockserver, sbuff, 1024, 0)) { fclose(fd); return 0; } while ((count = recv(sockserver, rbuff, 1024, 0))>0)//recv函数返回接受的字节数赋给count fwrite(rbuff, sizeof(char), count, fd); //把count个数据长度为size0f()的数据从rbuff输入到fd指向的目标文件 printf(" get %s succed!\n", filename); fclose(fd); }//put if (strncmp(rbuff, "pwd", 3) == 0){ char path[1000]; GetCurrentDirectory(1000, path);//找到当前进程的当前目录 strcpy(sbuff, path); send(sockserver, sbuff, 1024, 0); }//pwd if (strncmp(rbuff, "dir", 3) == 0){ strcpy(sbuff, rbuff); send(sockserver, sbuff, 1024, 0); SendFileList(sockserver);//发送当前列表 }//dir if (strncmp(rbuff, "cd", 2) == 0) { strcpy(filename, rbuff + 3); strcpy(sbuff, rbuff); send(sockserver, sbuff, 1024, 0); SetCurrentDirectory(filename);//设置当前目录 }//cd closesocket(sockserver); }//for 2 }//for 1 }int main(){ if (StartSock() == -1) return(-1); if (CreateSocket() == -1) return(-1); if (ConnectProcess() == -1) return(-1); return(1);}
4.简单的演示效果如下图:
阅读全文
2 0
- 利用原始socket简单实现FTP的客户端和服务器端程序
- VC写的socket程序实现一个简单Echo服务器端和客户端程序
- 实现服务器端和客户端的Socket通信
- 利用socket实现客户端与服务器端聊天
- socket编程,实现简单的客户端服务器端发送数据
- C++ 简单的 Tcp 实现[socket] 服务器端与客户端通信
- Android 使用socket 实现简单的客户端和服务器端互相通信
- 直播项目,在线聊天功能--socket实现客户端和服务器端通讯的简单案例
- 最简单的FTP客户端、服务器端
- ios socket编程的客户端和服务器端通信简单实例
- 简单的socket通讯方法客户端和服务器端
- Socket 服务器端和客户端简单对话
- Socket实现客户端和服务器端的消息通信
- java-基本的Socket编程-实现服务器端和客户端通信
- 使用 Socket 通信实现 FTP 客户端程序
- 使用 Socket 通信实现 FTP 客户端程序
- 使用 Socket 通信实现 FTP 客户端程序
- 使用 Socket 通信实现 FTP 客户端程序
- Android热修复之Tinker接入流程
- web.xml详解
- 为什么需要auto_ptr_ref
- 这些企业倒闭了?别不信,看数据可视化分析系统还原真相
- Python
- 利用原始socket简单实现FTP的客户端和服务器端程序
- vs2012中多行注释快捷键
- 【前端插件】简单封装WebSocket
- MySQL Memory 存储引擎浅析
- DataSet对象获取相应列值、行列数、列名、取出特定值这些操作的总结
- 应对节日高峰-Web架构实践
- 百度AI开发者大会背后的故事
- vue引入图片问题
- POI读取Excel数据日期时间输出