栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++ socket实现miniFTP

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++ socket实现miniFTP

本文实例为大家分享了C++ socket实现miniFTP的方法,供大家参考,具体内容如下

客户端:

服务端:

建立连接

        连接使用 TCP 连接,服务器和客户端分别创建自己的套接字一端,服务器等待连接,客户端发起连接(并指定服务器 ip)。在两者端口号一致且不被占用的情况下,连接建立。
        在整个过程中,服务器对每一个来访的客户端建立一个连接,在客户未请求与服务器断开时,该连接一直存在,用户可以不断向服务器发出请求。(持久性、流水线型连接 )
        客户端断开后,关闭客户端的套接字部分,服务器继续等待新的连接。服务器一次只能处理一个客户端的连接,不支持并发访问。

PDU 格式

        由于 ftp 应当支持几乎任意类型文件,而几乎所有类型文件都能用二进制来解析,所以我们采用了二进制的格式来读取以及写入文件。在整个过程中,我们并不关心文件的具体内容,也无需在程序中解析文件,而是将其当作数据流看待。
        受到缓存区大小的限制,我们无法一次性传输整个文件,所以我们将文件按缓存区大小拆分成数据包分批发送,我们可以将数据及时从缓存区写入文件,这样就让出了缓存区空间。数据包仅仅包含数据,不包含头部或尾部信息。
        此外,接收文件时,recv()函数将会循环调用,因此,我们需要一个信号来通知什么时候发送完毕。
        一个想法是发送终止信号,这是可行的,但更好的方法是在一开始发送文件总字节数,让接收方根据剩余字节大小判断什么时候接收完毕。因为在写入文件时,我们需要指定写入的字节数,尤其是在发来的数据流字节数不等于缓冲区大小时。写入字节数的错误会导致文件受损。

接收确认

        我们知道 TCP 是可靠传输协议,它采取了一系列措施来保证传输不会出错。所以在使用 TCP 连接时,我们相信数据在链路层上没有出差错,它一定会成功发送到对方手上。但是在客户端接收服务器发来的文件的时候,我们仍然需要服务器发来确认信息。原因在于,虽然我们可以保证链路层不出错,但是我们无法保证应用层不出错。例如,客户端可能会给出错误的文件名,因为接收不到服务器发来的信息,所以会陷入空等状态。

ftpClient.h

#pragma  
#include 
class ftpClient 
{ 
private: 
  enum { 
    SERVER_PORT = 9999, 
    BUFFER_SIZE = 4096 
  }; 
  sockaddr_in serverChannel; 
  char buffer[BUFFER_SIZE]; 
  int serverSocket; 
  int clientSocket; 
  bool isConnect; 
  char name[50]; 
 
  bool getFile(); 
  bool putFile(); 
  bool acknowledge(); 
  bool sendRequest(char* instruction); 
  bool connect2Host(const char* hostName); 
  bool getWorkDir(); 
 
public: 
  ftpClient(); 
  ~ftpClient(); 
  void start(); 
}; 

ftpClient.cpp

#define _CRT_SECURE_NO_WARNINGS 
#include"ftpClient.h" 
#include 
#include 
#include 
#include 
 
ftpClient::ftpClient() 
{ 
  WORD wVersionRequested; 
  WSADATA wsaData; 
  int ret; 
 
  //WinSock初始化: 
  wVersionRequested = MAKEWORd(2, 2);//希望使用的WinSock DLL的版本 
  ret = WSAStartup(wVersionRequested, &wsaData); 
  if (ret != 0) 
  { 
    printf("WSAStartup() failed!n"); 
  } 
  //确认WinSock DLL支持版本2.2: 
  if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) 
  { 
    WSACleanup(); 
    printf("Invalid Winsock version!n"); 
  } 
  isConnect = false; 
} 
 
void ftpClient::start() 
{ 
  char c[100]; 
  char d[100]; 
  printf("这里是FTP客户端,您可以输入help查看操作方法,输入quit退出客户端n"); 
 
  while (1) { 
    scanf("%s", c); 
    if (strcmp(c, "help") == 0) { 
      printf("get [fileName]  --  下载文件n" 
 "put [fileName]  --  上传文件n" 
 "ftp [ip]     --  登录FTPn" 
 "pwd --  显示服务器当前工作文件夹n" 
 "cd [dirName]   --  更改当前文件夹n" 
 "close--  关闭与当前ftp的连接n" 
 "quit--  退出客户端n" 
 ); 
    } 
    else if (strcmp(c, "get") == 0) { 
      scanf("%s", d); 
      strcat(c, " "); 
      strcat(c, d); 
      if (!isConnect) { 
 printf("you haven't connected to any server!n"); 
      } 
      else sendRequest(c); 
    } 
    else if (strcmp(c, "put") == 0) { 
      scanf("%s", d); 
      strcat(c, " "); 
      strcat(c, d); 
      if (!isConnect) { 
 printf("you haven't connected to any server!n"); 
      } 
      else sendRequest(c); 
    } 
    else if (strcmp(c, "ftp") == 0) { 
      scanf("%s", d); 
      if (!isConnect&&connect2Host(d)) { 
 isConnect = true; 
      } 
      else if(isConnect){ 
 printf("you have already connected to servern" 
   "please close the connection before connect to a new servern"); 
      } 
    } 
    else if (strcmp(c, "pwd") == 0) { 
      if (!isConnect) { 
 printf("you haven't connected to any server!n"); 
      } 
      else sendRequest(c); 
    } 
    else if (strcmp(c, "cd") == 0) { 
      scanf("%s", d); 
      strcat(c, " "); 
      strcat(c, d); 
      if (!isConnect) { 
 printf("you haven't connected to any server!n"); 
      } 
      else sendRequest(c); 
    } 
    else if (strcmp(c, "quit") == 0) { 
      if (isConnect) { 
 strcpy(c, "close"); 
 isConnect = false; 
 send(clientSocket, c, strlen(c) + 1, 0); 
 closesocket(clientSocket); 
      } 
      break; 
    } 
    else if (strcmp(c, "close") == 0) { 
      if (isConnect) { 
 isConnect = false; 
 send(clientSocket, c, strlen(c) + 1, 0); 
 closesocket(clientSocket); 
      } 
    } 
    else { 
      printf("syntex errorn"); 
    } 
  } 
} 
 
bool ftpClient::connect2Host(const char* hostName) 
{ 
  //创建socket 
  clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
 
  if (clientSocket < 0) { 
    printf("cannot create socketn"); 
    return false; 
  } 
  else printf("successfully create socketn"); 
  memset(&serverChannel, 0, sizeof(serverChannel));//初始化为0 
 
  serverChannel.sin_family = AF_INET;//channel协议家族AF_INET 
  serverChannel.sin_addr.S_un.S_addr = inet_addr(hostName);//地址 
  serverChannel.sin_port = htons(SERVER_PORT);//服务器端口 
 
   //建立连接 
  serverSocket = connect(clientSocket, (sockaddr*)&serverChannel, sizeof(serverChannel)); 
 
  if (serverSocket < 0) { 
    printf("cannot connect to the hostn"); 
    return false; 
  } 
  else { 
    printf("successfully connect to the hostn"); 
    return true; 
  } 
} 
 
bool ftpClient::sendRequest(char* instruction) 
{ 
  int r = send(clientSocket, instruction, strlen(instruction) + 1, 0); 
  if (r == SOCKET_ERROR) { 
    printf("request failedn"); 
    return false; 
  } 
  else { 
    printf("request successn"); 
    char opt[5]; 
    int i = 0, j = 0; 
    while (instruction[i] != ' '&&instruction[i] != '') { 
      opt[i] = instruction[i]; 
      i++; 
    } 
    opt[i] = ''; 
    i++; 
    while (instruction[i] != '') { 
      name[j] = instruction[i]; 
      i++, j++; 
    } 
    name[j] = ''; 
    if (strcmp(opt, "get") == 0) { 
      if (getFile()) { 
 printf("successfully downloadn"); 
      } 
      else printf("download failedn"); 
    } 
    else if (strcmp(opt, "put") == 0) { 
      if (putFile()) { 
 printf("successfully uploadn"); 
      } 
      else printf("upload failedn"); 
    } 
    else if (strcmp(opt, "pwd") == 0) { 
      if (!getWorkDir()) 
 printf("get work directory failedn"); 
    } 
    else if (strcmp(opt, "cd") == 0) { 
      printf("operation finishedn"); 
    } 
    else { 
      printf("syntex errorn"); 
      return false; 
    } 
    return true; 
  } 
} 
 
bool ftpClient::getFile() 
{ 
  memset(buffer, 0, sizeof(buffer)); 
  int ret; 
  char length[20]; 
  ret = recv(clientSocket, length, sizeof(length), 0); 
  if (ret == SOCKET_ERROR) { 
    return false; 
  } 
  else if (strcmp(length, "NAK") == 0) { 
    return false; 
  } 
  int size = atoi(length); 
  std::ofstream out; 
 
  out.open(name, std::ios::binary); 
  if (!out) { 
    printf("cannot save the filen"); 
    return false; 
  } 
  while (size>0) { 
    ret = recv(clientSocket, buffer, BUFFER_SIZE, 0); 
    int s = size < BUFFER_SIZE ? size : BUFFER_SIZE; 
    if (ret == SOCKET_ERROR) { 
      out.close(); 
      return false; 
    } 
    else if (strcmp(buffer, "NAK") == 0) { 
      out.close(); 
      return false; 
    } 
    else { 
      out.write(buffer, s); 
    } 
    size -= BUFFER_SIZE; 
  } 
  out.close(); 
  return acknowledge(); 
} 
 
bool ftpClient::putFile() 
{ 
  std::ifstream in; 
  //打开文件 
  in.open(name, std::ios::binary); 
  if (!in) { 
    printf("cannot open the filen"); 
    return false; 
  } 
  memset(buffer, 0, sizeof(buffer)); 
  //得到文件的字节数 
  in.seekg(0, std::ios_base::end); 
  int sp = in.tellg(); 
  int total_size = 0; 
  int r; 
  char length[20]; 
  sprintf(length, "%d", sp); 
 
  //发送字节 
  r = send(clientSocket, length, sizeof(length), 0); 
  if (r == SOCKET_ERROR) { 
    return false; 
  } 
  while (sp > 0) { 
    in.clear(); 
    in.seekg(total_size, std::ios_base::beg); 
    memset(buffer, 0, sizeof(buffer)); 
    //读取文件 
    in.read(buffer, sizeof(buffer)); 
    int size = sp < BUFFER_SIZE ? sp : BUFFER_SIZE; 
    total_size += size; 
    //发送文件 
    r = send(clientSocket, buffer, size, 0); 
 
    sp -= size; 
    if (r == SOCKET_ERROR) { 
      in.close(); 
      return false; 
    } 
  } 
  in.close(); 
} 
 
bool ftpClient::getWorkDir() { 
  printf("getWorkDirn"); 
  memset(buffer, 0, sizeof(buffer)); 
  int ret; 
  char length[20]; 
  ret = recv(clientSocket, length, sizeof(length), 0); 
  if (ret == SOCKET_ERROR) { 
    return false; 
  } 
  int size = atoi(length); 
  while (size>0) { 
    ret = recv(clientSocket, buffer, BUFFER_SIZE, 0); 
    if (ret == SOCKET_ERROR) { 
      return false; 
    } 
    else { 
      printf("%s", buffer); 
    } 
    size -= BUFFER_SIZE; 
  } 
  return true; 
} 
 
bool ftpClient::acknowledge() 
{ 
  int ret = recv(clientSocket, buffer, BUFFER_SIZE, 0); 
  if (ret > 0) { 
    if (strcmp(buffer, "NAK") == 0)return false; 
    else if (strcmp(buffer, "ACK") == 0)return true; 
  } 
} 
 
ftpClient::~ftpClient() 
{ 
  if (isConnect) { 
    isConnect = false; 
    char c[6]; 
    strcpy(c, "close"); 
    send(clientSocket, c, strlen(c) + 1, 0); 
    closesocket(clientSocket); 
  } 
} 

main.cpp

#define _CRT_SECURE_NO_WARNINGS 
#define _WINSOCK_DEPRECATED_NO_WARNINGS 
#pragma(lib,"ws2_32.lib") 
#include"ftpClient.h" 
#include 
 
int main() 
{ 
  ftpClient a; 
  a.start(); 
  return 0; 
} 

ftpServer.h

#pragma once 
#include 
 
class ftpServer 
{ 
private: 
  enum { 
    SERVER_PORT = 9999, 
    BUFFER_SIZE = 4096, 
    QUEUE_SIZE = 10 
  }; 
  char buffer[BUFFER_SIZE]; 
  sockaddr_in serverChannel; 
  char name[50]; 
  char workDir[100]; //store like C:Users MARK:字符串末没有斜线!! 
  int serverSocket; //socket 
  int clientSocket; 
  bool sendFile(); 
  bool receiveFile(); 
  bool doPwd(); 
  bool doCd(); 
  bool isValidPath(char* path); 
public: 
  ftpServer(); 
  bool start();//开启服务器 
}; 

ftpServer.cpp

#define _CRT_SECURE_NO_WARNINGS 
 
#include"ftpServer.h" 
#include 
#include 
#include 
#include 
 
ftpServer::ftpServer() 
{ 
  WORD wVersionRequested; 
  WSADATA wsaData; 
  int ret; 
 
  //WinSock初始化: 
  wVersionRequested = MAKEWORd(2, 2);//希望使用的WinSock DLL的版本 
  ret = WSAStartup(wVersionRequested, &wsaData); 
  if (ret != 0) 
  { 
    printf("WSAStartup() failed!n"); 
  } 
  //确认WinSock DLL支持版本2.2: 
  if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) 
  { 
    WSACleanup(); 
    printf("Invalid Winsock version!n"); 
  } 
  //workDir初始化为当前路径 
  system("cd > tempFile"); 
  std::ifstream in("tempFile", std::ifstream::in); 
  in >> workDir; 
  in.close(); 
} 
 
bool ftpServer::start() 
{ 
  int on = 1; 
 
  //初始化服务器 
  memset(&serverChannel, 0, sizeof(serverChannel)); 
  serverChannel.sin_family = AF_INET; 
  serverChannel.sin_addr.s_addr = htonl(INADDR_ANY); 
  serverChannel.sin_port = htons(SERVER_PORT); 
 
  //创建套接字 
  this->serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
  if (serverSocket < 0) { 
    printf("cannot create socketn"); 
    return false; 
  } 
  else printf("successfully create socketn"); 
  setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, 
    (char*)&on, sizeof(on)); 
 
  //绑定 
  int b = bind(serverSocket, (sockaddr*)&serverChannel, 
    sizeof(serverChannel)); 
  if (b < 0) { 
    printf("bind errorn"); 
    return false; 
  } 
  else printf("successfully bindn"); 
  //监听 
  int l = listen(serverSocket, QUEUE_SIZE); 
  if (l < 0) { 
    printf("listen failedn"); 
    return false; 
  } 
  else printf("successfully listenn"); 
  int len = sizeof(serverChannel); 
  //服务器等待连接 
  while (1) { 
    printf("waiting for connection...n"); 
    //接受一个连接 
    clientSocket = accept(serverSocket, (sockaddr*)&serverChannel, 
      &len); 
    if (clientSocket < 0) { 
      printf("accept failedn"); 
    } 
    else { 
      printf("successfully connectn"); 
      while (1) { 
 memset(buffer, 0, sizeof(buffer)); 
 int ret; 
 
 ret = recv(clientSocket, buffer, BUFFER_SIZE, 0); 
 
 if (ret == SOCKET_ERROR) { 
   printf("receive failedn"); 
 } 
 else { 
   char opt[50]; 
   printf("successfully receiven"); 
   int i = 0, j = 0; 
   printf("buffer = %sn", buffer); 
   while (buffer[i] != ' '&&buffer[i] != '') { 
     opt[i] = buffer[i]; 
     i++; 
   } 
   opt[i] = ''; 
   if (buffer[i] != '') { 
     i++; 
   } 
   while (buffer[i] != '') { 
     name[j] = buffer[i]; 
     i++, j++; 
   } 
   name[j] = ''; 
 
   if (strcmp(opt, "get") == 0) { 
     char ret[4]; 
     if (!sendFile()) { 
strcpy(ret, "NAK"); 
send(clientSocket, ret, sizeof(ret), 0); 
     } 
     else { 
strcpy(ret, "ACK"); 
send(clientSocket, ret, sizeof(ret), 0); 
     } 
   } 
   else if (strcmp(opt, "put") == 0) { 
     receiveFile(); 
   } 
   else if (strcmp(opt, "pwd") == 0) { 
     doPwd(); 
   } 
   else if (strcmp(opt, "cd") == 0) { 
     doCd(); 
   } 
   else if (strcmp(opt, "close") == 0) { 
     break; 
   } 
   else { 
     printf("syntex errorn"); 
   } 
 } 
      } 
    } 
  } 
  return true; 
} 
 
bool ftpServer::sendFile() 
{ 
  std::ifstream in; 
  char path[100]; 
  strcpy(path, workDir); 
  strcat(path, "\"); 
  strcat(path, name); 
 
  in.open(path, std::ios::binary); 
  if (!in) { 
    printf("cannot open the filen"); 
    return false; 
  } 
  memset(buffer, 0, sizeof(buffer)); 
  in.seekg(0, std::ios_base::end); 
  int sp = in.tellg(); 
  int total_size = 0; 
  int r; 
  char length[20]; 
  sprintf(length, "%d", sp); 
   
  r = send(clientSocket, length, sizeof(length), 0); 
 
  if (r == SOCKET_ERROR) { 
    printf("send failedn"); 
    return false; 
  } 
  else { 
    printf("send successn"); 
  } 
 
  while (sp > 0) { 
    in.clear(); 
    in.seekg(total_size, std::ios_base::beg); 
    memset(buffer, 0, sizeof(buffer)); 
    in.read(buffer, sizeof(buffer)); 
    int size = sp < BUFFER_SIZE ? sp : BUFFER_SIZE; 
    total_size += size; 
    r = send(clientSocket, buffer, size, 0); 
 
    sp -= size; 
    if (r == SOCKET_ERROR) { 
      printf("send failedn"); 
      return false; 
    } 
    else { 
      printf("send successn"); 
    } 
  } 
  in.close(); 
  return true; 
} 
 
bool ftpServer::receiveFile() 
{ 
  char path[100]; 
  strcpy(path, workDir); 
  strcat(path, "\"); 
  strcat(path, name); 
  memset(buffer, 0, sizeof(buffer)); 
  int ret; 
  char length[20]; 
  ret = recv(clientSocket, length, sizeof(length), 0); 
  if (ret == SOCKET_ERROR) { 
    printf("receive failedn"); 
    return false; 
  } 
  else { 
    printf("successfully receiven"); 
  } 
  int size = atoi(length); 
  std::ofstream out; 
 
  out.open(path, std::ios::binary); 
  if (!out) { 
    printf("cannot save the filen"); 
    return false; 
  } 
  while (size>0) { 
    int s = size < BUFFER_SIZE ? size : BUFFER_SIZE; 
    ret = recv(clientSocket, buffer, BUFFER_SIZE, 0); 
    if (ret == SOCKET_ERROR) { 
      printf("receive failedn"); 
      break; 
    } 
    else { 
      printf("successfully receiven"); 
      out.write(buffer, s); 
    } 
    size -= BUFFER_SIZE; 
  } 
  out.close(); 
  return true; 
} 
 
bool ftpServer::doPwd() { 
  char temCMD[150]; 
  memset(temCMD, 0, sizeof(temCMD)); 
  strcat(temCMD, "echo "); 
  strcat(temCMD, workDir); 
  strcat(temCMD, " > tempFile"); 
  system(temCMD); 
  memset(temCMD, 0, sizeof(temCMD)); 
  strcat(temCMD, "dir /b "); 
  strcat(temCMD, workDir); 
  strcat(temCMD, " >> tempFile"); 
  system(temCMD); 
 
  std::ifstream in("tempFile", std::fstream::in); 
  if (!in) { 
    printf("cannot open the filen"); 
    return false; 
  } 
  memset(buffer, 0, sizeof(buffer)); 
  in.seekg(0, std::ios_base::end); 
  int sp = in.tellg(); 
  int total_size = 0; 
  int r; 
  char length[20]; 
  sprintf(length, "%d", sp); 
  r = send(clientSocket, length, sizeof(length), 0); 
 
  if (r == SOCKET_ERROR) { 
    printf("send failedn"); 
    return false; 
  } 
  else { 
    printf("send successn"); 
  } 
  while (sp > 0) { 
    in.clear(); 
    in.seekg(total_size, std::ios_base::beg); 
    memset(buffer, 0, sizeof(buffer)); 
    in.read(buffer, sizeof(buffer)); 
    int size = sp < BUFFER_SIZE ? sp : BUFFER_SIZE; 
    total_size += size; 
    printf("transfer size = %dn", total_size); 
    r = send(clientSocket, buffer, size, 0); 
 
    sp -= size; 
    if (r == SOCKET_ERROR) { 
      printf("send failedn"); 
      return false; 
    } 
    else { 
      printf("send successn"); 
    } 
  } 
  in.close(); 
  return true; 
} 
 
bool ftpServer::isValidPath(char* path) { 
  char temCMD[100]; 
  memset(temCMD, 0, sizeof(temCMD)); 
  strcat(temCMD, "cd "); 
  strcat(temCMD, path); 
  int res = system(temCMD); 
  return res == 0; 
} 
 
bool ftpServer::doCd() { 
  for (int i = 0; name[i] != ''; ++i) { 
    if (name[i] == '/') 
      name[i] = '\'; 
  } 
  if (name[0] == '.'&&name[1] == '.') { 
    char temDir[100]; 
    strcpy(temDir, workDir); 
    for (int i = sizeof(temDir); i >= 0; --i) { 
      if (temDir[i] == '\') { 
 temDir[i] = ''; 
 break; 
      } 
    } 
    strcat(temDir, name + 2); 
    if (isValidPath(temDir)) { 
      strcpy(workDir, temDir); 
    } 
    else { 
      return false; 
    } 
  } 
  else if (name[0] == '.'&&name[1] != '.') { 
    char temDir[100]; 
    strcpy(temDir, workDir); 
    strcat(temDir, name + 1); 
    if (isValidPath(temDir)) { 
      strcpy(workDir, temDir); 
    } 
    else { 
      return false; 
    } 
  } 
  else if (name[1] == ':') { 
    if (isValidPath(name)) { 
      strcpy(workDir, name); 
    } 
    else { 
      return false; 
    } 
  } 
  else { 
    char temDir[100]; 
    strcpy(temDir, workDir); 
    strcat(temDir, "\"); 
    strcat(temDir, name); 
    if (isValidPath(temDir)) { 
      strcpy(workDir, temDir); 
    } 
    else { 
      return false; 
    } 
  } 
  return true; 
} 

main.cpp

#include"ftpServer.h" 
#pragma(lib,"ws2_32.lib") 
int main() 
{ 
 ftpServer f; 
 f.start(); 
} 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持考高分网。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/64078.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号