题目

简单FTP客户端软件开发(100分)网络环境中的一项基本应用就是将文件从一台计算机中复制到另一台可能相距很远的计算机中。而文件传送协议FTP是因特网上使用得最广泛的文件传送协议。FTP使用客户服务器方式。
设计要求:
1)以命令行形式运行
2)该FTP客户端程序具有以下基本功能:能完成FTP链接的打开和关闭操作;能执行文件的上传和下载;能完成目录的创建、删除等有关操作。
3)设计中加入新的功能:登录,进入上级或下级目录
要求可以传输简单的文本文件。

设计思路

1、分为两个端口,指令交流端口,数据交换端口
2、指令端口连接后一直保持通信,直到获得退出信号
3、数据交换端口在获得相关指令后重新建立连接

使用方法

1、分别创建两个C++项目
2、复制代码进入即可
3、若两个都在本地,使用本地回环测试IP,127.0.0.1
4、登录的部分在客户端中被注释掉了没有开启

Tips:

目前登录以及help部分仍有两个小bug,系由端口的命令断开以及连接部分引起,交由读者自己研究,若不想管可以不使用这两个功能

服务端——>Server

#include "Winsock2.h"
#include "windows.h"
#include <iostream>
#include <string>
using namespace std;#define RECV_PORT 3312  //接收端口
#define SEND_PORT 4302  //发送端口
#define DATA_PORT 3313  //数据发送端口
#pragma comment(lib, "wsock32.lib")SOCKET sockClient, sockServer;
SOCKET dataClient, dataServer;sockaddr_in dataAddr;
sockaddr_in severAddr;//服务器地址
sockaddr_in ClientAddr;//客户端地址
sockaddr_in dataClientAddr;//数据地址int addrLen;       //地址长度
char fileName[20];  //文件名
char order[20];     //命令
char rbuff[1024];   //接收缓冲区
char sbuff[1024];   //发送缓冲区char namePassword[1024] = "user 123456";  //用户名和密码//***************函数声明***************DWORD startSock();
DWORD createSocket();
int sendFileRecord(SOCKET datatcps, WIN32_FIND_DATA *pfd);
int sendFileList(SOCKET datatcps);
int sendFile(SOCKET datatcps, FILE* file);
DWORD connectProcess();//***************函数声明***************
DWORD startSock() {//初始化winsockWSADATA WSAData;if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0) {cout << "初始化失败" << endl;return -1;}return 1;
}
DWORD createSocket() {sockClient = socket(AF_INET, SOCK_STREAM, 0);dataClient = socket(AF_INET, SOCK_STREAM, 0);if (sockClient == SOCKET_ERROR||dataClient == SOCKET_ERROR) {cout << "创建失败" << endl;WSACleanup();return -1;}dataAddr.sin_family = AF_INET;severAddr.sin_family = AF_INET;dataAddr.sin_addr.s_addr = htonl(INADDR_ANY);//监听任意地址dataAddr.sin_port = htons(DATA_PORT);severAddr.sin_addr.s_addr = htonl(INADDR_ANY);//监听任意地址//cout<<htonl(INADDR_ANY)<<endl;severAddr.sin_port = htons(RECV_PORT);if (bind(sockClient, (struct sockaddr FAR*)&severAddr, sizeof(severAddr)) == SOCKET_ERROR||bind(dataClient, (struct sockaddr FAR*)&dataAddr, sizeof(dataAddr)) == SOCKET_ERROR) {//bind函数用于将socket和地址结构绑定==cout << "绑定失败" << endl;return -1;}return 1;
}DWORD mkdir(char fileName[]){char path[1000];GetCurrentDirectory(sizeof(path), path);//找到当前进程的当前目录strcat(path,"\\");strcat(path,fileName);cout<<path<<endl;bool flag = CreateDirectory(path,NULL);if (flag)cout<<"创建文件:"<<fileName<<"成功"<<endl;elsecout<<"创建文件:"<<fileName<<"失败"<<endl;}DWORD delFile(char fileName[]){char path[1000];GetCurrentDirectory(sizeof(path), path);//找到当前进程的当前目录strcat(path,"\\");strcat(path,fileName);// cout<<path<<endl;bool flag = RemoveDirectory(path);if (flag)cout<<"删除文件:"<<fileName<<"成功"<<endl;elsecout<<"删除文件:"<<fileName<<"失败"<<endl;
}
DWORD connectProcess() {addrLen = sizeof(ClientAddr);//addrLen是对象地址的长度if (listen(sockClient, 10) < 0|| listen(dataClient, 10)<0) {//让套接字进入被动监听状态,参数2为请求队列的最大长度cout << "监听失败" << endl;return -1;}cout << "服务器正在监听中…" << endl;while (1) {//accept取出队列头部的连接请求//sockclient是处于监听的套接字//ClientAddr 是监听的对象地址sockServer = accept(sockClient, (struct sockaddr FAR*)&ClientAddr, &addrLen);while (1) {memset(rbuff, 0, sizeof(rbuff));memset(sbuff, 0, sizeof(sbuff));if (recv(sockServer, rbuff, sizeof(rbuff), 0) <= 0) {continue;}cout << endl << "获取并执行的命令:" << rbuff << endl;if (strncmp(rbuff, "get", 3) == 0) {//将文件发给客户端strcpy(fileName, rbuff + 4);FILE* file;//定义一个文件访问指针//处理下载文件请求file = fopen(fileName, "rb");//二进制打开文件,只允许读if (file) {sprintf(sbuff, "get %s", fileName);if (!send(sockServer, sbuff, sizeof(sbuff), 0)) {cout<<"发送失败"<<endl;fclose(file);return 0;}else {//创建额外数据连接传送数据if (!sendFile(dataClient, file)) {return 0;}fclose(file);}}else {strcpy(sbuff, "无法打开文件\n");cout<<"无法打开文件"<<endl;if (!send(sockServer, sbuff, sizeof(sbuff), 0)) {return 0;}}}//getelse if (strncmp(rbuff, "put", 3) == 0) {//从客户端上传上来文件cout<<"debug1"<<endl;FILE* fd;int cnt;strcpy(fileName, rbuff + 4);fd = fopen(fileName, "wb");if (fd == NULL) {cout << "无法打开文件" << fileName << endl;return 0;}sprintf(sbuff, "put %s", fileName);if (!send(sockServer, sbuff, sizeof(sbuff), 0)) {fclose(fd);return 0;}memset(sbuff, '\0', sizeof(rbuff));int dataAddLen = sizeof (dataClientAddr);dataServer = accept(dataClient, (struct sockaddr FAR*)&dataClientAddr, &dataAddLen);while ((cnt = recv(dataServer, rbuff, sizeof(rbuff), 0)) > 0) {fwrite(rbuff, sizeof(char), cnt, fd);//把cnt个数据长度为char的数据从rbuff输入到fd指向的文件}cout << "成功获得文件" << fileName << endl;closesocket(dataServer);fclose(fd);}//putelse if (strncmp(rbuff, "pwd", 3) == 0) {char path[1000];GetCurrentDirectory(sizeof(path), path);//找到当前进程的当前目录strcpy(sbuff, path);send(sockServer, sbuff, sizeof(sbuff), 0);}//pwdelse if (strncmp(rbuff, "ls", 2) == 0) {strcpy(sbuff, rbuff);send(sockServer, sbuff, sizeof(sbuff), 0);sendFileList(dataClient);}//direlse if(strncmp(rbuff, "mkdir", 5)==0){strcpy(fileName, rbuff + 6);strcpy(sbuff,rbuff);send(sockServer, sbuff, sizeof (sbuff),0);//发送回信息mkdir(fileName);}//mkdirelse if(strncmp(rbuff,"del", 3)==0){strcpy(fileName, rbuff + 4);//获得要删的文件名strcpy(sbuff,rbuff);send(sockServer, sbuff, sizeof (sbuff),0);//发送回信息delFile(fileName);}//delelse if (strncmp(rbuff, "cd", 2) == 0) {strcpy(fileName, rbuff + 3);strcpy(sbuff, rbuff);send(sockServer, sbuff, sizeof(sbuff), 0);char path[1000];GetCurrentDirectory(sizeof(path), path);//找到当前进程的当前目录strcat(path,"\\");strcat(path,fileName);SetCurrentDirectory(path);//设置当前目录}//cdelse if (strncmp(rbuff, "user", 4) == 0) {char tbuff[1024];strcpy(tbuff, rbuff + 5);strcat(tbuff, " ");memset(rbuff, '\0', sizeof(rbuff));strcpy(sbuff, "成功获取用户名\0");send(sockServer, sbuff, sizeof(sbuff), 0);recv(sockServer, rbuff, sizeof(rbuff), 0);cout << endl << "获取并执行的命令:" << rbuff << endl;strcat(tbuff, rbuff + 5);if (strcmp(tbuff, namePassword) == 0) {//验证是否正确并返回数据给客户端send(sockServer, "right\0", sizeof(sbuff), 0);}else {send(sockServer, "wrong\0", sizeof(sbuff), 0);}}//user pass}closesocket(sockServer);}
}
int sendFile(SOCKET datatcps, FILE* file) {int dataAddLen = sizeof (dataClientAddr);dataServer = accept(datatcps, (struct sockaddr FAR*)&dataClientAddr, &dataAddLen);cout << "正在发送文件…" << endl;memset(sbuff, '\0', sizeof(sbuff));while(1) {//从文件中循环读取数据并发送至客户端int len = fread(sbuff, 1, sizeof(sbuff), file);//把file指针指向的文件中的内容读取到sbuff中//cout<<"sbuff内容:"<<sbuff<<endl;if (send(dataServer, sbuff, len, 0) == SOCKET_ERROR) {cout << "连接失败" << endl;closesocket(dataServer);return 0;}if (len < sizeof(sbuff)) {//文件传送结束break;}}closesocket(dataServer);cout << "发送成功" << endl;return 1;
}
int sendFileList(SOCKET datatcps) {int dataAddLen = sizeof (dataClientAddr);dataServer = accept(datatcps, (struct sockaddr FAR*)&dataClientAddr, &dataAddLen);HANDLE hff;                             //建立一个线程WIN32_FIND_DATA fd;                     //搜索文件hff = FindFirstFile("*", &fd);         //查找文件来把待操作文件的相关属性读取到WIN32_FIND_DATA结构中去if (hff == INVALID_HANDLE_VALUE) {        //发生错误const char *errStr = "列出文件列表时发生错误\n";cout << *errStr << endl;if (send(dataServer, errStr, strlen(errStr), 0) == SOCKET_ERROR) {cout << "发送失败" << endl;}closesocket(dataServer);return 0;}BOOL flag = TRUE;while (flag) {//发送文件信息if (!sendFileRecord(dataServer, &fd)) {closesocket(dataServer);return 0;}flag = FindNextFile(hff, &fd);//查找下一个文件}closesocket(dataServer);return 1;
}
int sendFileRecord(SOCKET datatcps, WIN32_FIND_DATA *pfd) {//发送当前的文件记录char fileRecord[MAX_PATH + 32];FILETIME ft;                      //文件的建立时间FileTimeToLocalFileTime(&pfd -> ftLastWriteTime, &ft);//Converts a file time to a local file time.SYSTEMTIME lastWriteTime;FileTimeToSystemTime(&ft, &lastWriteTime);const char *dir = pfd -> dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? "<DIR>" : " ";sprintf(fileRecord, "%04d-%02d-%02d %02d:%02d %5s %10d   %-20s\n",lastWriteTime.wYear,lastWriteTime.wMonth,lastWriteTime.wDay,lastWriteTime.wHour,lastWriteTime.wMinute,dir,pfd -> nFileSizeLow,pfd -> cFileName);if (send(datatcps, fileRecord, strlen(fileRecord), 0) == SOCKET_ERROR) {//通过datatcps接口发送fileRecord数据,成功返回发送的字节数cout << "发送失败" << endl;return 0;}return 1;
}
int main(){if (startSock() == -1 || createSocket() == -1 || connectProcess() == -1) {return -1;}return 1;
}

客户端——>Client

#include <Winsock.h>
#include <windows.h>
#include <time.h>
#include <stdio.h>
#include <iostream>
using namespace std;#define RECV_PORT 3312  //接收端口
#define SEND_PORT 4302  //发送端口
#define DATA_PORT 3313  //数据接受端口#pragma comment(lib, "wsock32.lib")   //加载ws2_32.dll,它是Windows Sockets应用程序接口, 用于支持Internet和网络应用程序。SOCKET sockClient;        //客户端对象
sockaddr_in serverAddr; //服务器地址
sockaddr_in dataAddr;
SOCKET dataClient;      //数据对象char inputIP[20];     //存储输入的服务器IP
char fileName[20];      //文件名
char rbuff[1024];       //接收缓冲区
char sbuff[1024];       //发送缓冲区
bool checkFlag = false;            //标志是否通过登陆//***********************函数声明***********************
DWORD startSock();                          //启动winsock并初始化
DWORD createSocket(SOCKET &mySocket);                       //创建socket
DWORD callServer(SOCKET &mySocket,sockaddr_in addr);                            //发送连接请求int command();                             //执行命令
void help();                                //菜单
void list(SOCKET &sockfd);                  //列出远方当前目录
DWORD sendTCP(char data[]);                 //发送要执行的命令至服务端
int user();                                 //上传用户名
int pass();                                 //上传密码
int sendFile(SOCKET &datatcps, FILE* file); //put 传送给远方一个文件
//***********************函数声明***********************//***********************函数定义***********************
DWORD startSock() { //启动winsock并初始化WSADATA WSAData;char a[20];memset(a, 0, sizeof(a));if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0) { //加载winsock版本cout << "sock初始化失败" << endl;return -1;}if (strncmp(inputIP, a, sizeof(a)) == 0) {cout << "请输入要连接的服务器IP:";cin >> inputIP;}//设置地址结构serverAddr.sin_family = AF_INET;                    //表明底层是使用的哪种通信协议来递交数据的,AF_INET表示使用 TCP/IPv4 地址族进行通信serverAddr.sin_addr.s_addr = inet_addr(inputIP); //指定服务器IP,十进制转化成二进制IPV4地址serverAddr.sin_port = htons(RECV_PORT);                //设置端口号,htons用于将主机字节序改为网络字节序dataAddr.sin_family = AF_INET;dataAddr.sin_addr.s_addr = inet_addr(inputIP);dataAddr.sin_port = htons(DATA_PORT);//数据端口和控制端口不一样return 1;
}
DWORD createSocket(SOCKET &mySocket) { //创建socket//要使用套接字,首先必须调用socket()函数创建一个套接字描述符,就如同操作文件时,首先得调用fopen()函数打开一个文件。mySocket = socket(AF_INET, SOCK_STREAM, 0);//当scoket函数成功调用时返回一个新的SOCKET(Socket Descriptor) //SOCK_STREAM(流式套接字):Tcp连接,提供序列化的、可靠的、双向连接的字节流。支持带外数据传输if (mySocket == SOCKET_ERROR) {cout << "创建socket失败" << endl;WSACleanup();//终止Ws2_32.dll 的使用return -1;}return 1;
}
DWORD callServer(SOCKET &mySocket,sockaddr_in addr) { //发送连接请求createSocket(mySocket);if (connect(mySocket, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {//connect()创建与指定外部端口的连接cout << "连接失败" << endl;memset(inputIP, 0, sizeof(inputIP));return -1;}return 1;
}
void help() { //帮助菜单cout << "        ___________________________________________  " << endl<< "       |                FTP帮助菜单                 |   " << endl<< "       | 1、get 下载文件 [输入格式: get 文件名 ]       |   " << endl<< "       | 2、put 上传文件 [输入格式:put 文件名]         |   " << endl<< "       | 3、pwd 显示当前文件夹的绝对路径                |    " << endl<< "       | 4、ls 显示远方当前目录的文件                 |   " << endl<< "       | 5、mkdir 新建文件夹 [输入格式:mkdir 文件名]   |   " << endl<< "       | 6、del 删除文件夹 [输入格式:del 文件名]       |   " << endl<< "       | 7、cd  改变远方当前目录和路径                 |   " << endl<< "       |         进入下级目录: cd 路径名              |   " << endl<< "       |         进入上级目录: c ..                  |   " << endl<< "       | 8、? 或者 help 进入帮助菜单                  |   " << endl<< "       | 9、quit 退出FTP                            |   " << endl<< "       |___________________________________________|    " << endl;
}
DWORD sendTCP(char data[]) { //发送要执行的命令至服务端int length = send(sockClient, data, strlen(data), 0);if (length <= 0) {cout << "发送命令至服务端失败" << endl;closesocket(sockClient);//当不使用socket()创建的套接字时,应该调用closesocket()函数将它关闭,就如同调用fclose()函数关闭一个文件,用来进行套接字资源的释放。WSACleanup();return -1;}return 1;
}
int sendFile(SOCKET &datatcps, FILE* file) { //put 传送给远方一个文件callServer(datatcps,dataAddr);cout << "正在传输文件…" << endl;memset(sbuff, '\0', sizeof(sbuff));while (1) { //从文件中循环读取数据并发送int len = fread(sbuff, 1, sizeof(sbuff), file); //fread从file文件读取sizeof(sbuff)长度的数据到sbuff,返回成功读取的数据个数if (send(datatcps, sbuff, sizeof(rbuff), 0) == SOCKET_ERROR) {cout << "与客户端的连接中断" << endl;closesocket(datatcps);return 0;}if (len < sizeof(sbuff)) {break;}}closesocket(datatcps);cout << "传输完成" << endl;return 1;
}
void list(SOCKET &sockfd) { //列出远方当前目录callServer(sockfd,dataAddr);int nRead;memset(sbuff, '\0', sizeof(sbuff));while (1) {nRead = recv(sockfd, rbuff, sizeof(rbuff), 0);//recv通过sockClient套接口接受数据存入rbuff缓冲区,返回接收到的字节数if (nRead == SOCKET_ERROR) {cout << "读取时发生错误" << endl;exit(1);}if (nRead == 0) { //数据读取结束break;}cout<<"nRead长度"<<nRead<<endl;//显示数据rbuff[nRead] = '\0';cout << rbuff << endl;}cout<<"读取结束"<<endl;closesocket(sockfd);
}
int  user() {char operation[10], name[20];      //操作与文件名char order[30] = "\0";               //输入的命令char buff[80];                       //用来存储经过字符串格式化的ordercout << "请输入用户名指令(user 用户名):";strcpy(operation,"user");cin >> name;strcat(order, operation), strcat(order, " "), strcat(order, name);sprintf(buff, order);sendTCP(buff);                                 //发送指令recv(sockClient, rbuff, sizeof(rbuff), 0);        //接收信息cout << rbuff << endl;return 1;
}
int pass() {char operation[10], name[20];       //操作与文件名char order[30] = "\0";               //输入的命令char buff[80];                       //用来存储经过字符串格式化的ordercout << "请输入密码指令(pass 密码):" ;strcpy(operation,"pass");cin >> name;strcat(order, operation), strcat(order, " "), strcat(order, name);sprintf(buff, order);sendTCP(buff);                                  //发送指令recv(sockClient, rbuff, sizeof(rbuff), 0);        //接收信息cout << rbuff << endl;if (strcmp(rbuff, "wrong") == 0) {return 0;}return 1;
}
//***********************函数定义***********************int command(){char operation[10], name[20];        //操作与文件名char order[30] = "\0";                //输入的命令char buff[80];                        //用来存储经过字符串格式化的orderFILE *fd1, *fd2;                    //File协议主要用于访问本地计算机中的文件,fd指针指向要访问的目标文件int cnt;//发送连接请求成功,初始化数据memset(operation, 0, sizeof(operation));memset(name, 0, sizeof(name));memset(order, 0, sizeof(order));memset(buff, 0, sizeof(buff));memset(rbuff, 0, sizeof(rbuff));memset(sbuff, 0, sizeof(sbuff));cout << endl << "请输入要执行的指令: ";cin >> operation;
//        cout<<"why:"<<operation<<endl;if (strncmp(operation, "get", 3) == 0 || strncmp(operation, "put", 3) == 0 ||strncmp(operation, "cd", 2) == 0 || strncmp(operation, "mkdir", 5) == 0 || strncmp(operation, "del", 3) ==0){ ///需要输入文件名的功能cin >> name;} else if (strncmp(operation, "quit", 4) == 0) { ///退出功能cout << "感谢您的使用" << endl;return 1;} else if (strncmp(operation, "?", 1) == 0 || strncmp(operation, "help", 4) == 0) { ///帮助菜单功能help();}else if(strncmp(operation,"ls",2)==0|| strncmp(operation,"pwd",3)==0){}else{cout<<"非法输入"<<endl;return 0;}//将指令整合进order,并存放进buffstrcat(order, operation), strcat(order, " "), strcat(order, name);sprintf(buff, order);sendTCP(buff);                                    //发送指令recv(sockClient, rbuff, sizeof(rbuff), 0);        //接收信息cout << rbuff << endl;                            //pwd功能在这里已经实现if (strncmp(rbuff, "get", 3) == 0) {            ///下载功能callServer(dataClient,dataAddr);fd1 = fopen(name, "wb");                    //用二进制的方式打开文件,wb表示打开或新建一个二进制文件(只允许写数据)if (fd1 == NULL) {cout << "打开或者新建 " << name << "文件失败" << endl;return 1;}memset(rbuff, '\0', sizeof(rbuff));while ((cnt = recv(dataClient, rbuff, sizeof(rbuff), 0)) > 0) {// cout<<"缓冲区"<<rbuff<<endl<<"长度"<<cnt<<endl;fwrite(rbuff, sizeof(rbuff), 1, fd1);    //C 库函数 size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 把 ptr 所指向的数组中的数据写入到给定流 stream 中。}closesocket(dataClient);fclose(fd1);                                //关闭文件}//getelse if (strncmp(rbuff, "put", 3) == 0) { ///上传功能//  cout<<"执行"<<endl;strcpy(fileName, rbuff + 4);fd2 = fopen(fileName, "rb");                //打开一个二进制文件,文件必须存在,只允许读if (fd2) { //成功打开// cout<<"debug0"<<endl;if (!sendFile(dataClient, fd2)) {cout << "发送失败" << endl;return 1;}fclose(fd2);} else {strcpy(sbuff, "无法打开文件\n");if (!send(sockClient, sbuff, sizeof(sbuff), 0)) {return 1;}}}//putelse if (strncmp(rbuff, "ls", 2) == 0) { ///ls功能list(dataClient);}//dirreturn 0;}int main() {while (1) {startSock();                //启动winsock并初始化if (callServer(sockClient,serverAddr) == -1) {    //发送连接请求失败continue;}cout << "发送连接请求成功" << endl;//        if (checkFlag == false) {//登陆
//            if (user() && pass()) {//                checkFlag = true;
//            }
//            continue;
//        }checkFlag = true;if(checkFlag){help();}while(checkFlag){if(command()){break;}}cout<<"命令输入结束"<<endl;closesocket(sockClient);    //关闭连接WSACleanup();                //释放Winsockreturn 0;}
}
/*
192.168.0.100
user gyc
pass 123456
pwd
cd Debug
get 110.txt
*/

C++ 简单FTP客户端软件开发相关推荐

  1. 计算机网络 简单FTP客户端软件的实现

    一.原理概述 1.1 FTP原理概述 文件传送协议FTP(File Transfer Protocol)是TCP/IP体系的一个重要协议,它采用Internet标准文件传输协议FTP的用户界面,向用户 ...

  2. 基于java的ftp客户端_基于Java的FTP客户端软件的设计

    基于的FTP客户端软件的设计(含选题审批表,任务书,开题报告,中期检查表,毕业论文8600字,答辩记录) 摘 要:FTP 是File Transfer Protocol(文件传输协议)的英文简称,而中 ...

  3. 手机网络应用客户端软件开发实践简介

    网络应用与客户端软件 说到移动网络应用,前几年大家首先想到的就是WAP应用.最近随着市场上手机的可编程能力越来越强,手机软件开发平台和产业链的逐渐成熟,手机上的网络应用软件逐渐多了起来,如移动QQ.P ...

  4. 手机网络应用客户端软件开发实践简介(摘自www.j2medev.com)

    网络应用与客户端软件 说到移动网络应用,前几年大家首先想到的就是WAP应用.最近随着市场上手机的可编程能力越来越强,手机软件开发平台和产业链的逐渐成熟,手机上的网络应用软件逐渐多了起来,如移动QQ.P ...

  5. ftp客户端软件,8款最受欢迎的ftp客户端软件

    对于ftp客户端软件,你了解多少?其实一般人也接触不到这种软件.ftp客户端软件主要是针对从事网站管理的工作人员比较有利的一款工具.可以帮助他们快速的解决工作中的问题.方便.简单.快捷又明了的解决问题 ...

  6. 手机上安装FTP客户端软件(AndFTP),实现通过手机访问计算机FTP服务器

    服务器连接工具: IIS7服务器管理工具是一款windows全系下用于连接并操控基于windows和linux系统的VPS.VNC.FTP等远程服务器.云服务器的管理工具. 界面简单明了,操作易上手, ...

  7. ftp客户端软件有哪些,有哪些ftp客户端软件值得推荐?

    不知道大家对于ftp客户端软件的要求普遍是什么,但是我的要求是很简单的,主要就是好用,方便容易上手,使用起来很容易,不要太复杂的.其实我对于ftp软件的要求应该是大部分网站工作者的基本要求吧.下面是我 ...

  8. ftp客户端软件,3款值得推荐的ftp客户端软件

    对于ftp客户端软件,你了解多少?其实一般人也接触不到这种软件.ftp客户端软件主要是针对从事网站管理的工作人员比较有利的一款工具.可以帮助他们快速的解决工作中的问题.方便.简单.快捷又明了的解决问题 ...

  9. ftp客户端软件,什么是ftp客户端软件?对于它,你知道些什么?

    对于ftp客户端软件,你了解多少?其实一般人也接触不到这种软件.ftp客户端软件主要是针对从事网站管理的工作人员比较有利的一款工具.可以帮助他们快速的解决工作中的问题.方便.简单.快捷又明了的解决问题 ...

最新文章

  1. Java IO Serialization
  2. 模板:后缀数组(SA)
  3. php mysql html标签_HTML标签格式化PHP和MySQL
  4. 并发、并行、线程、进程与CPU基本概念
  5. 初学者python笔记(字符串用法解析)
  6. 人工智能发展中面临的问题有哪些?
  7. java运行环境安装及配置教程
  8. WordPress整站轻松开启HTTPS 1
  9. html img的点击事件,js给img添加点击事件无效
  10. mysql分区替换,MySQL交换分区的实例详解
  11. MYSQL LEFT JOIN 的怪异行为
  12. java 去系统运行时间_java 如何获取应用的运行时间
  13. 北京中医药大学《计算机基础》平时作业1
  14. 深入理解内存:原理简介
  15. 双通道5.2GSPS(或单通道10.4GSPS)射频采样FMC+模块
  16. 第一章-算法在计算中的作用
  17. 往届学生软件工程作业参考-需求分析
  18. 2020年个人计划总结和2021年个人计划
  19. input常见输入限制及金额转货币
  20. tuned-adm性能优化的配置文件详解

热门文章

  1. 基于STM32的TFDU4101红外通信IRDA+串口DMA方式
  2. vulnstack内网渗透环境靶场-1 大全
  3. php 正则匹配img标签中的自定义属性值
  4. 批量下载百度贴吧帖子图片
  5. 月活超1.5亿背后,张一鸣在用资本催熟抖音
  6. java毕业生设计学生学籍信息管理系统计算机源码+系统+mysql+调试部署+lw
  7. Html代码写得个人简历
  8. 办公自动化打卡 task01
  9. 什么是 TPMS(轮胎压力监视系统)系统
  10. Android进度条样式问号,DLNA上线后,粉粉们是否有许多问号,相信这篇帖子可以帮大家解决...