本文实例为大家分享了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] -- 登录FTP\n"

"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 server\n"

"please close the connection before connect to a new server\n");

}

}

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 error\n");

}

}

}

bool ftpClient::connect2Host(const char* hostName)

{

//创建socket

clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if (clientSocket < 0) {

printf("cannot create socket\n");

return false;

}

else printf("successfully create socket\n");

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 host\n");

return false;

}

else {

printf("successfully connect to the host\n");

return true;

}

}

bool ftpClient::sendRequest(char* instruction)

{

int r = send(clientSocket, instruction, strlen(instruction) + 1, 0);

if (r == SOCKET_ERROR) {

printf("request failed\n");

return false;

}

else {

printf("request success\n");

char opt[5];

int i = 0, j = 0;

while (instruction[i] != ' '&&instruction[i] != '\0') {

opt[i] = instruction[i];

i++;

}

opt[i] = '\0';

i++;

while (instruction[i] != '\0') {

name[j] = instruction[i];

i++, j++;

}

name[j] = '\0';

if (strcmp(opt, "get") == 0) {

if (getFile()) {

printf("successfully download\n");

}

else printf("download failed\n");

}

else if (strcmp(opt, "put") == 0) {

if (putFile()) {

printf("successfully upload\n");

}

else printf("upload failed\n");

}

else if (strcmp(opt, "pwd") == 0) {

if (!getWorkDir())

printf("get work directory failed\n");

}

else if (strcmp(opt, "cd") == 0) {

printf("operation finished\n");

}

else {

printf("syntex error\n");

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 file\n");

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 file\n");

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("getWorkDir\n");

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 socket\n");

return false;

}

else printf("successfully create socket\n");

setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR,

(char*)&on, sizeof(on));

//绑定

int b = bind(serverSocket, (sockaddr*)&serverChannel,

sizeof(serverChannel));

if (b < 0) {

printf("bind error\n");

return false;

}

else printf("successfully bind\n");

//监听

int l = listen(serverSocket, QUEUE_SIZE);

if (l < 0) {

printf("listen failed\n");

return false;

}

else printf("successfully listen\n");

int len = sizeof(serverChannel);

//服务器等待连接

while (1) {

printf("waiting for connection...\n");

//接受一个连接

clientSocket = accept(serverSocket, (sockaddr*)&serverChannel,

&len);

if (clientSocket < 0) {

printf("accept failed\n");

}

else {

printf("successfully connect\n");

while (1) {

memset(buffer, 0, sizeof(buffer));

int ret;

ret = recv(clientSocket, buffer, BUFFER_SIZE, 0);

if (ret == SOCKET_ERROR) {

printf("receive failed\n");

}

else {

char opt[50];

printf("successfully receive\n");

int i = 0, j = 0;

printf("buffer = %s\n", buffer);

while (buffer[i] != ' '&&buffer[i] != '\0') {

opt[i] = buffer[i];

i++;

}

opt[i] = '\0';

if (buffer[i] != '\0') {

i++;

}

while (buffer[i] != '\0') {

name[j] = buffer[i];

i++, j++;

}

name[j] = '\0';

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 error\n");

}

}

}

}

}

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 file\n");

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 failed\n");

return false;

}

else {

printf("send success\n");

}

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 failed\n");

return false;

}

else {

printf("send success\n");

}

}

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 failed\n");

return false;

}

else {

printf("successfully receive\n");

}

int size = atoi(length);

std::ofstream out;

out.open(path, std::ios::binary);

if (!out) {

printf("cannot save the file\n");

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 failed\n");

break;

}

else {

printf("successfully receive\n");

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 file\n");

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 failed\n");

return false;

}

else {

printf("send success\n");

}

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 = %d\n", total_size);

r = send(clientSocket, buffer, size, 0);

sp -= size;

if (r == SOCKET_ERROR) {

printf("send failed\n");

return false;

}

else {

printf("send success\n");

}

}

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] != '\0'; ++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] = '\0';

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();

}

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

c语言socket实现ftp,C++ socket实现miniFTP相关推荐

  1. php socket 实现ftp,用socket实现FTP教程

    1.用户加密认证 2.允许同时多用户登录 3.每个用户有自己的家目录 ,且只能访问自己的家目录 4.对用户进行磁盘配额,每个用户的可用空间不同 5.允许用户在ftp server上随意切换目录 6.允 ...

  2. c语言实现ftp网络应用程序,使用C语言socket实现windows pc与ftp服务器通信---socket实现ftp客户端...

    code // Client.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include #include #include #pra ...

  3. 基于socket实现FTP服务器

    基于socket实现FTP服务器 前言 基于socket完成了一个FTP服务器,实现了其基本功能 环境 操作系统:Windows 10企业版 LTSC 开发语言:C++ 开发工具:Visual Stu ...

  4. js ftpclient linux server,Node.JS用Socket实现FTP Server服务器和Client客户端

    通信过程 FTP协议其实就是主机和服务通过Socket进行固定格式的通信过程,当某客户端连接到FTP 服务器后,客户端发送指令: [参数] 服务会按以下格式返回: [参数或说明] 例如以下是FileZ ...

  5. day34 异常处理、断言、socket之ftp协议

    Python之路,Day20 = 异常处理.断言.socket之ftp协议 参考博客:http://www.cnblogs.com/metianzing/articles/7148191.html 1 ...

  6. TCP/UDP,SOCKET,HTTP,FTP协议简析

    (一)TCP/UDP,SOCKET,HTTP,FTP简析 TCP/IP是个协议组,可分为三个层次:网络层.传输层和应用层: 网络层:IP协议.ICMP协议.ARP协议.RARP协议和BOOTP协议 传 ...

  7. c语言程序开发中连接是,C语言中等待socket连接和对socket定位的方法

    C语言listen()函数:等待连接头文件: #include 定义函数: int listen(int s,int backlog); 函数说明:listen()用来等待参数s 的socket 连线 ...

  8. c语言linux TCP长连接 socket收发范例 断开自动重连

    原文链接:https://blog.csdn.net/chenhao0568/article/details/103420615 c语言linux TCP长连接 socket收发范例 断开自动重连 改 ...

  9. C语言实现网络聊天室 socket的简单应用

    C语言实现网络聊天室 socket的简单应用 前言:环境是Linux ,使用了 socket和pthread,主要分为服务器端和客户端两部分,服务器端监听端口发来的请求,收到后向客户端发送一个消息,客 ...

最新文章

  1. [翻译]帮助文档-jQuery 选择器
  2. RTP:实时应用程序传输协议
  3. asm 查看 数据文件 修改 时间_更高效的GMX分段模拟方法:修改tpr文件
  4. 图灵原版计算机科学系列,图灵原版计算科学系列
  5. 解决模拟MOSS用户调用WebService打开个人站点进行操作
  6. [计算机网络]httpserver--如何解析HTTP请求报文
  7. python中{%%}在HTML中的用法
  8. MongoDB中的索引操作
  9. java 判断当前时间是否为节假日_浅谈Java8日期时间处理
  10. android滚动悬停布局,android布局滑动到顶端悬浮,录音
  11. 织云Lite发布:详解包管理核心能力
  12. Git 下载与安装教程
  13. 新手学习电脑知识的一些方法
  14. js中对象属性、面向对象、面向过程、类、继承、以及原型原型链
  15. 金属铣床行业现状调研及趋势分析报告
  16. 为淘宝网店免费使用流量统计教程
  17. stm32f407探索者开发板(一)——资源介绍(顺便说下无人机的进度状况)
  18. bzoj3875 【Ahoi2014】骑士游戏 spfa处理后效性动规
  19. 初一年级上学期计算机课知识总结,精选七年级上册信息技术教案范文3篇
  20. ajax无刷新kesion,KesionCMS V9.04 UTF-8版本无法自动获取关键字的修改

热门文章

  1. FEMS:广东生态所孙蔚旻组利用DNA-SIP宏基因组揭示锑氧化微生物及其代谢途径...
  2. MPB:湖南师大尹佳组-乳酸菌的耐热实验
  3. 东北农业大学农学院程晓非教授荣获植物病毒学国家“优青”资助
  4. QIIME 2用户文档. 22Python命令行模式(2019.7)
  5. arcgis 中label feature太长换行_MapGIS转换为ArcGIS小结
  6. R语言ggplot2可视化、在可视化区域中自定义添加多个大小不同矩形阴影区域、自定义配置大小不同矩形阴影区域的颜色(Adding multiple shadows/rectangles)
  7. R语言构建xgboost模型:使用xgb.DMatrix保存、加载数据集、使用getinfo函数抽取xgb.DMatrix结构中的数据
  8. 机器学习特征筛选:方差选择法VarianceThreshold
  9. R语言广义线性模型Logistic回归模型C Statistics计算
  10. 启动R环境并执行R脚本