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 }//getif (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.简单的演示效果如下图:

利用原始socket简单实现FTP的客户端和服务器端程序相关推荐

  1. 利用python发送邮件_利用python实现简单的邮件发送客户端示例

    脚本过于简单,供学习和参考.主要了解一下smtplib库的使用和超时机制的实现.使用signal.alarm实现超时机制. #!/usr/bin/env python # -*- coding: ut ...

  2. python实现邮件客户端_利用python实现简单的邮件发送客户端示例

    脚本过于简单,供学习和参考.主要了解一下smtplib库的使用和超时机制的实现.使用signal.alarm实现超时机制. #!/usr/bin/env python # -*- coding: ut ...

  3. python客户端与服务器端_Python实现的FTP通信客户端与服务器端功能示例

    本文实例讲述了Python实现的FTP通信客户端与服务器端功能.分享给大家供大家参考,具体如下: 一 代码 1.服务端代码 import socket import threading import ...

  4. Socket和ServerSocket(建立客户端和服务器端)

    网络编程(c/s)与网站编程(b/s)的区别? 网站编程是编写网页html,jsp,servelet等,只需要编写一端(server端),不需要编写client端,已经编写好了 网络编程相对底层一些, ...

  5. ftp客户端与服务器传文件在哪里,中国大学MOOC: FTP在客户端和服务器端传输文件时,使用的是...

    摘要: 仍不任工能胜作的,中国或者工作岗位培训经过调整,合同解除用人劳动单位随时可以,任工能胜者不作劳动.功率也适用于的计算,客户于电不仅流和叠加定律电压的计适用算.服务向正中电极流极源内由负部的不一 ...

  6. 【Java】Socket多客户端Client-Server聊天程序

    文章目录 任务要求 实现代码 工具类 服务器端线程 客户端线程 服务器端程序 客户端程序 运行说明 任务要求 编写一个简单的Socket多客户端聊天程序: 客户端程序,从控制台输入字符串,发送到服务器 ...

  7. python应用系列教程——python使用socket创建tcp服务器和客户端

    全栈工程师开发手册 (作者:栾鹏) python教程全解 python使用socket创建tcp服务器和客户端. 服务器端为一个时间戳服务器,在接收到客户端发来的数据后,自动回复. 客户端,等待用户输 ...

  8. 客户端到服务器端的通信过程及原理(很清晰,保证看后顿悟)

    学习任何东西,我们只要搞清楚其原理,就会触类旁通.现在结和我所学,我想总结一下客户端到服务器端的通信过程.只有明白了原理,我们才会明白当我们程序开发过程中错误的问题会出现在那,才会更好的解决问题. 我 ...

  9. 客户端到服务器端的通信过程及原理(由浅入深,轻松理解)

    学习任何东西,我们只要搞清楚其原理,就会触类旁通.现在结和我所学,我想总结一下客户端到服务器端的通信过程.只有明白了原理,我们才会明白当我们程序开发过程中错误的问题会出现在那,才会更好的解决问题. 我 ...

最新文章

  1. “饶毅举报”事件尘埃落定,裴钢表示未发现裴钢造假。网友:我有信心一年发20篇SCI...
  2. php mpdf html 转pdf,使用 MPDF 将HTML转为PDF,然后将该PDF转为PNG图片的时候,中文报错... ......
  3. Java 转换流 简介
  4. django如何给上传的图片重命名(给上传文件重命名)
  5. makefile与stm32工程皮毛了解
  6. javascript指南_熟练掌握JavaScript的指南
  7. AI 会替代程序员?超好用的自动补全代码工具 Deep TabNine!
  8. java bsh介绍_BeanShell简介
  9. VAX 经常Parsing 整个项目/CPU负载过高解决办法
  10. 航空公司系统是怎样炼成的
  11. 夏季室内甲醛净化 A.O.史密斯数显甲醛净化器让用户更放心
  12. 微信二维码没有扫描id
  13. java 是什么_java中是什么意思?
  14. Ubuntu Xfce桌面系统设置项
  15. 杨思卓:黑钻VS蓝石(2)
  16. 【codecs】视频显示分辨率格式分析
  17. Xgboost近似分位数算法
  18. DebugView 使用技巧
  19. 电商后台设计——搜索
  20. SRAM的工作原理图解

热门文章

  1. Saltstack_使用指南04_数据系统-Grains
  2. python如何封装成exe
  3. Mysql数据库连接出现1129错误
  4. android7.0模拟器调试,android - 为什么在android 7.0及更高版本上出现模拟器错误? - 堆栈内存溢出...
  5. Android Wear书签
  6. zencart刷淘宝信誉 被骗了 多情自古空余恨
  7. 发现一款非常好用的项目管理软件
  8. VUE浅拷贝和深拷贝
  9. matlab模拟三体运动_matlab三体运动
  10. HDU4856 Tunnels 状压DP