① 如何搭建ftp服务器实现文件共享
这里以windows系统和linux系统为例,简单介绍一下如何在这2种系统下搭建ftp服务器,整个过程非常简单,感兴趣的朋友可以自己尝试一下:
windows
windows系统自带有ftp服务器,只需要在控制面板的“程序和功能”模块中开启一下就行,下面我简单介绍一下操作过程:
1.首先,打开控制面板,依次点击“程序”->“启用或关闭windows功能”,在弹出的windows功能窗口中勾选“ftp服务器”和“iis管理控制台”,如下,等待程序安装完成:
2.接着在搜毕键索栏打开“iis控制器”,右键左侧的“网站”条目,在弹出的功能列表中选择“添加ftp站点...”,这时我们就可以直接设置ftp服务器根目录了(也就是需要共享的文件夹),如下:
3.然后就是设置ftp服务器ip地址和端口号,这里可以设置为内网ip,也可以设置为外网ip,根据自己需求设置就行,如下:
4.接着就是设置访问用户及读写权限,这里可以是匿名用户、指定用户、所有用户、用户组等,如下:
5.最后设置完成后,在浏览器输入“ftp://ftp服务器ip地址”就可以直接访问ftp服务器了,如下,所有文件都已列出,可以直接进行下载:
linux
这里需要先安装vsftp这个工具包,然后启动ftp服务,之后就可以直接访问ftp服务器上的文件了,下面我简单介绍一下操作过程:
1.首先,安装vsftpd工具包,这个直接在终端输入命令“yuminstall-yvsftpd”就行,或者手桐巧(“aptinstall-yvsftpd”),如下:
2.安装完成后,这里你可以对/etc/vsftpd/vsftpd.conf文件进行进行简单配置,设置用户访问策略等,官方文档有详细说明,修改对应参数就行,如下:
3.接着就是启动ftp服务,直接运行“systemctlstartvsftpd”命令(或者“servicevsftpdstart”命令)就行,如下,ftp服务已经正常运行:
4.最后就可以直接使用sftp或者ftp命令连接ftp服务器了,效果如下,输入用户password,成功验证后就可以直接上传下载文件了:
至此,我们就完成了在windows系统和linux系统下搭建ftp服务器。总的来说,整个过轮橡程非常简单,只要你熟悉一下上面的操作过程,很快就能掌握的,当然,你也可以借助现有的ftp软件来搭建ftp服务器,都行,网上也有相关教程和资料,介绍的非常详细,感兴趣的话,可以搜一下,希望以上分享的内容能对你有所帮助吧,也欢迎大家评论、留言进行补充。
② 怎么用Java实现FTP上传
sun.net.ftp.FtpClient.,该类库主要提供了用于建立FTP连接的类。利用这些类的方法,编程人员可以远程登录到FTP服务器,列举该服务器上的目录,设置传输协议,以及传送文件。FtpClient类涵盖了几乎所有FTP的功能,FtpClient的实例变量保存了有关建立"代理"的各种信息。下面给出了这些实例变量:
public static boolean useFtpProxy
这个变量用于表明FTP传输过程中是否使用了一个代理,因此,它实际上是一个标记,此标记若为TRUE,表明使用了一个代理主机。
public static String ftpProxyHost
此变量只有在变量useFtpProxy为TRUE时才有效,用于保存代理主机名。
public static int ftpProxyPort此变量只有在变量useFtpProxy为TRUE时才有效,用于保存代理主机的端口地址。
FtpClient有三种不同形式的构造函数,如下所示:
1、public FtpClient(String hostname,int port)
此构造函数利用给出的主机名和端口号建立一条FTP连接。
2、public FtpClient(String hostname)
此构造函数利用给出的主机名建立一条FTP连接,使用默认端口号。
3、FtpClient()
此构造函数将创建一FtpClient类,但不建立FTP连接。这时,FTP连接可以用openServer方法建立。
一旦建立了类FtpClient,就可以用这个类的方法来打开与FTP服务器的连接。类ftpClient提供了如下两个可用于打开与FTP服务器之间的连接的方法。
public void openServer(String hostname)
这个方法用于建立一条与指定主机上的FTP服务器的连接,使用默认端口号。
public void openServer(String host,int port)
这个方法用于建立一条与指定主机、指定端口上的FTP服务器的连接。
打开连接之后,接下来的工作是注册到FTP服务器。这时需要利用下面的方法。
public void login(String username,String password)
此方法利用参数username和password登录到FTP服务器。使用过Intemet的用户应该知道,匿名FTP服务器的登录用户名为anonymous,密码一般用自己的电子邮件地址。
下面是FtpClient类所提供的一些控制命令。
public void cd(String remoteDirectory):该命令用于把远程系统上的目录切换到参数remoteDirectory所指定的目录。
public void cdUp():该命令用于把远程系统上的目录切换到上一级目录。
public String pwd():该命令可显示远程系统上的目录状态。
public void binary():该命令可把传输格式设置为二进制格式。
public void ascii():该命令可把传输协议设置为ASCII码格式。
public void rename(String string,String string1):该命令可对远程系统上的目录或者文件进行重命名操作。
除了上述方法外,类FtpClient还提供了可用于传递并检索目录清单和文件的若干方法。这些方法返回的是可供读或写的输入、输出流。下面是其中一些主要的方法。
public TelnetInputStream list()
返回与远程机器上当前目录相对应的输入流。
public TelnetInputStream get(String filename)
获取远程机器上的文件filename,借助TelnetInputStream把该文件传送到本地。
public TelnetOutputStream put(String filename)
以写方式打开一输出流,通过这一输出流把文件filename传送到远程计算机
package myUtil;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import sun.net.TelnetInputStream;
import sun.net.TelnetOutputStream;
import sun.net.ftp.FtpClient;
/**
* ftp上传,下载
*
* @author why 2009-07-30
*
*/
public class FtpUtil {
private String ip = "";
private String username = "";
private String password = "";
private int port = -1;
private String path = "";
FtpClient ftpClient = null;
OutputStream os = null;
FileInputStream is = null;
public FtpUtil(String serverIP, String username, String password) {
this.ip = serverIP;
this.username = username;
this.password = password;
}
public FtpUtil(String serverIP, int port, String username, String password) {
this.ip = serverIP;
this.username = username;
this.password = password;
this.port = port;
}
/**
* 连接ftp服务器
*
* @throws IOException
*/
public boolean connectServer() {
ftpClient = new FtpClient();
try {
if (this.port != -1) {
ftpClient.openServer(this.ip, this.port);
} else {
ftpClient.openServer(this.ip);
}
ftpClient.login(this.username, this.password);
if (this.path.length() != 0) {
ftpClient.cd(this.path);// path是ftp服务下主目录的子目录
}
ftpClient.binary();// 用2进制上传、下载
System.out.println("已登录到\"" + ftpClient.pwd() + "\"目录");
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/**
* 断开与ftp服务器连接
*
* @throws IOException
*/
public boolean closeServer() {
try {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
if (ftpClient != null) {
ftpClient.closeServer();
}
System.out.println("已从服务器断开");
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/**
* 检查文件夹在当前目录下是否存在
*
* @param dir
*@return
*/
private boolean isDirExist(String dir) {
String pwd = "";
try {
pwd = ftpClient.pwd();
ftpClient.cd(dir);
ftpClient.cd(pwd);
} catch (Exception e) {
return false;
}
return true;
}
/**
* 在当前目录下创建文件夹
*
* @param dir
* @return
* @throws Exception
*/
private boolean createDir(String dir) {
try {
ftpClient.ascii();
StringTokenizer s = new StringTokenizer(dir, "/"); // sign
s.countTokens();
String pathName = ftpClient.pwd();
while (s.hasMoreElements()) {
pathName = pathName + "/" + (String) s.nextElement();
try {
ftpClient.sendServer("MKD " + pathName + "\r\n");
} catch (Exception e) {
e = null;
return false;
}
ftpClient.readServerResponse();
}
ftpClient.binary();
return true;
} catch (IOException e1) {
e1.printStackTrace();
return false;
}
}
/**
* ftp上传 如果服务器段已存在名为filename的文件夹,该文件夹中与要上传的文件夹中同名的文件将被替换
*
* @param filename
* 要上传的文件(或文件夹)名
* @return
* @throws Exception
*/
public boolean upload(String filename) {
String newname = "";
if (filename.indexOf("/") > -1) {
newname = filename.substring(filename.lastIndexOf("/") + 1);
} else {
newname = filename;
}
return upload(filename, newname);
}
/**
* ftp上传 如果服务器段已存在名为newName的文件夹,该文件夹中与要上传的文件夹中同名的文件将被替换
*
* @param fileName
* 要上传的文件(或文件夹)名
* @param newName
* 服务器段要生成的文件(或文件夹)名
* @return
*/
public boolean upload(String fileName, String newName) {
try {
String savefilename = new String(fileName.getBytes("GBK"),
"GBK");
File file_in = new File(savefilename);// 打开本地待长传的文件
if (!file_in.exists()) {
throw new Exception("此文件或文件夹[" + file_in.getName() + "]有误或不存在!");
}
if (file_in.isDirectory()) {
upload(file_in.getPath(), newName, ftpClient.pwd());
} else {
uploadFile(file_in.getPath(), newName);
}
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
return true;
} catch (Exception e) {
e.printStackTrace();
System.err.println("Exception e in Ftp upload(): " + e.toString());
return false;
} finally {
try {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 真正用于上传的方法
*
* @param fileName
* @param newName
* @param path
* @throws Exception
*/
private void upload(String fileName, String newName, String path)
throws Exception {
String savefilename = new String(fileName.getBytes("ISO-8859-1"), "GBK");
File file_in = new File(savefilename);// 打开本地待长传的文件
if (!file_in.exists()) {
throw new Exception("此文件或文件夹[" + file_in.getName() + "]有误或不存在!");
}
if (file_in.isDirectory()) {
if (!isDirExist(newName)) {
createDir(newName);
}
ftpClient.cd(newName);
File sourceFile[] = file_in.listFiles();
for (int i = 0; i < sourceFile.length; i++) {
if (!sourceFile[i].exists()) {
continue;
}
if (sourceFile[i].isDirectory()) {
this.upload(sourceFile[i].getPath(), sourceFile[i]
.getName(), path + "/" + newName);
} else {
this.uploadFile(sourceFile[i].getPath(), sourceFile[i]
.getName());
}
}
} else {
uploadFile(file_in.getPath(), newName);
}
ftpClient.cd(path);
}
/**
* upload 上传文件
*
* @param filename
* 要上传的文件名
* @param newname
* 上传后的新文件名
* @return -1 文件不存在 >=0 成功上传,返回文件的大小
* @throws Exception
*/
public long uploadFile(String filename, String newname) throws Exception {
long result = 0;
TelnetOutputStream os = null;
FileInputStream is = null;
try {
java.io.File file_in = new java.io.File(filename);
if (!file_in.exists())
return -1;
os = ftpClient.put(newname);
result = file_in.length();
is = new FileInputStream(file_in);
byte[] bytes = new byte[1024];
int c;
while ((c = is.read(bytes)) != -1) {
os.write(bytes, 0, c);
}
} finally {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
}
return result;
}
/**
* 从ftp下载文件到本地
*
* @param filename
* 服务器上的文件名
* @param newfilename
* 本地生成的文件名
* @return
* @throws Exception
*/
public long downloadFile(String filename, String newfilename) {
long result = 0;
TelnetInputStream is = null;
FileOutputStream os = null;
try {
is = ftpClient.get(filename);
java.io.File outfile = new java.io.File(newfilename);
os = new FileOutputStream(outfile);
byte[] bytes = new byte[1024];
int c;
while ((c = is.read(bytes)) != -1) {
os.write(bytes, 0, c);
result = result + c;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
/**
* 取得相对于当前连接目录的某个目录下所有文件列表
*
* @param path
* @return
*/
public List getFileList(String path) {
List list = new ArrayList();
DataInputStream dis;
try {
dis = new DataInputStream(ftpClient.nameList(this.path + path));
String filename = "";
while ((filename = dis.readLine()) != null) {
list.add(filename);
}
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
public static void main(String[] args) {
FtpUtil ftp = new FtpUtil("192.168.11.11", "111", "1111");
ftp.connectServer();
boolean result = ftp.upload("C:/Documents and Settings/ipanel/桌面/java/Hibernate_HQL.docx", "amuse/audioTest/music/Hibernate_HQL.docx");
System.out.println(result ? "上传成功!" : "上传失败!");
ftp.closeServer();
/**
* FTP远程命令列表 USER PORT RETR ALLO DELE SITE XMKD CDUP FEAT PASS PASV STOR
* REST CWD STAT RMD XCUP OPTS ACCT TYPE APPE RNFR XCWD HELP XRMD STOU
* AUTH REIN STRU SMNT RNTO LIST NOOP PWD SIZE PBSZ QUIT MODE SYST ABOR
* NLST MKD XPWD MDTM PROT
* 在服务器上执行命令,如果用sendServer来执行远程命令(不能执行本地FTP命令)的话,所有FTP命令都要加上\r\n
* ftpclient.sendServer("XMKD /test/bb\r\n"); //执行服务器上的FTP命令
* ftpclient.readServerResponse一定要在sendServer后调用
* nameList("/test")获取指目录下的文件列表 XMKD建立目录,当目录存在的情况下再次创建目录时报错 XRMD删除目录
* DELE删除文件
*/
}
}
③ Java应用程序开发包实现FTP服务器端程序,提供文件传输服务和相应的统计数据。简单的用户界面和统计功能
用Java实现FTP服务器
2004-03-10 02:09 来源:eNet论坛
【简 介】
FTP(File Transfer Protocol 文件传输协议)是Internet 上用来传送文件的协议。在Internet上通过FTP 服务器可以进行文件的上传(Upload)或下载(Download)。FTP是实时联机服务,在使用它之前必须是具有该服务的一个用户(用户名和口令),工作时客户端必须先登录到作为服务器一方的计算机上,用户登录后可以进行文件搜索和文件传送等有关操作,如改变当前工作目录、列文件目录、设置传输参数及传送文件等。使用FTP可以传送所有类型的文件,如文本文件、二进制可执行文件、图象文件、声音文件和数据压缩文件等。
加入收藏 设为首页
--------------------------------------------------------------------------------
FTP 命令
FTP 的主要操作都是基于各种命令基础之上的。常用的命令有:
◆ 设置传输模式,它包括ASCⅡ(文本) 和BINARY 二进制模式;
◆ 目录操作,改变或显示远程计算机的当前目录(cd、dir/ls 命令);
◆ 连接操作,open命令用于建立同远程计算机的连接;close命令用于关闭连接;
◆ 发送操作,put命令用于传送文件到远程计算机;mput 命令用于传送多个文件到远程计算机;
◆ 获取操作,get命令用于接收一个文件;mget命令用于接收多个文件。
编程思路
根据FTP 的工作原理,在主函数中建立一个服务器套接字端口,等待客户端请求,一旦客户端请求被接受,服务器程序就建立一个服务器分线程,处理客户端的命令。如果客户端需要和服务器端进行文件的传输,则建立一个新的套接字连接来完成文件的操作。
编程技巧说明
1.主函数设计
在主函数中,完成服务器端口的侦听和服务线程的创建。我们利用一个静态字符串变量initDir 来保存服务器线程运行时所在的工作目录。服务器的初始工作目录是由程序运行时用户输入的,缺省为C盘的根目录。
具体的代码如下:
public class ftpServer extends Thread{
private Socket socketClient;
private int counter;
private static String initDir;
public static void main(String[] args){
if(args.length != 0) {
initDir = args[0];
}else{ initDir = "c:";}
int i = 1;
try{
System.out.println("ftp server started!");
//监听21号端口
ServerSocket s = new ServerSocket(21);
for(;;){
//接受客户端请求
Socket incoming = s.accept();
//创建服务线程
new ftpServer(incoming,i).start();
i++;
}
}catch(Exception e){}
}
2. 线程类的设计
线程类的主要设计都是在run()方法中实现。用run()方法得到客户端的套接字信息,根据套接字得到输入流和输出流,向客户端发送欢迎信息。
3. FTP 命令的处理
(1) 访问控制命令
◆ user name(user) 和 password (pass) 命令处理代码如下:
if(str.startsWith("USER")){
user = str.substring(4);
user = user.trim();
out.println("331 Password");}
if(str.startsWith("PASS"))
out.println("230 User "+user+" logged in.");
User 命令和 Password 命令分别用来提交客户端用户输入的用户名和口令。
◆ CWD (CHANGE WORKING DIRECTORY) 命令处理代码如下:
if(str.startsWith("CWD")){
String str1 = str.substring(3);
dir = dir+"/"+str1.trim();
out.println("250 CWD command succesful");
}
该命令改变工作目录到用户指定的目录。
◆ CDUP (CHANGE TO PARENT DIRECTORY) 命令处理代码如下:
if(str.startsWith("CDUP")){
int n = dir.lastIndexOf("/");
dir = dir.substring(0,n);
out.println("250 CWD command succesful");
}
该命令改变当前目录为上一层目录。
◆ QUIT命令处理代码如下:
if(str.startsWith("QUIT")) {
out.println("GOOD BYE");
done = true;
}
该命令退出及关闭与服务器的连接,输出GOOD BYE。
(2) 传输参数命令
◆ Port命令处理代码如下:
if(str.startsWith("PORT")) {
out.println("200 PORT command successful");
int i = str.length() - 1;
int j = str.lastIndexOf(",");
int k = str.lastIndexOf(",",j-1);
String str1,str2;
str1="";
str2="";
for(int l=k+1;l
str1 = str2 + str.charAt(l);
}
for(int l=j+1;l<=i;l++){
str2 = str2 + str.charAt(l);
}
tempPort = Integer.parseInt(str1) * 16 *16 +Integer.parseInt(str2);
}
使用该命令时,客户端必须发送客户端用于接收数据的32位IP 地址和16位 的TCP 端口号。这些信息以8位为一组,使用十进制传输,中间用逗号隔开。
◆ TYPE命令处理代码如下:
if(str.startsWith("TYPE")){
out.println("200 type set");
}
TYPE 命令用来完成类型设置。
(3) FTP 服务命令
◆ RETR (RETEIEVE) 和 STORE (STORE)命令处理的代码
if(str.startsWith("RETR")){
out.println("150 Binary data connection");
str = str.substring(4);
str = str.trim();
RandomAccessFile outFile = new
RandomAccessFile(dir+"/"+str,"r");
Socket tempSocket = new Socket(host,tempPort);
OutputStream outSocket
= tempSocket.getOutputStream();
byte byteBuffer[]= new byte[1024];
int amount;
try{
while((amount = outFile.read(byteBuffer)) != -1){
outSocket.write(byteBuffer, 0, amount);
}
outSocket.close();
out.println("226 transfer complete");
outFile.close();
tempSocket.close();
}
catch(IOException e){}
}
if(str.startsWith("STOR")){
out.println("150 Binary data connection");
str = str.substring(4);
str = str.trim();
RandomAccessFile inFile = new
RandomAccessFile(dir+"/"+str,"rw");
Socket tempSocket = new Socket(host,tempPort);
InputStream inSocket
= tempSocket.getInputStream();
byte byteBuffer[] = new byte[1024];
int amount;
try{
while((amount =inSocket.read(byteBuffer) )!= -1){
inFile.write(byteBuffer, 0, amount);
}
inSocket.close();
out.println("226 transfer complete");
inFile.close();
tempSocket.close();
}
catch(IOException e){}
}
文件传输命令包括从服务器中获得文件RETR和向服务器中发送文件STOR,这两个命令的处理非常类似。处理RETR命令时,首先得到用户要获得的文件的名称,根据名称创建一个文件输入流,然后和客户端建立临时套接字连接,并得到一个输出流。随后,将文件输入流中的数据读出并借助于套接字输出流发送到客户端,传输完毕以后,关闭流和临时套接字。
STOR 命令的处理也是同样的过程,只是方向正好相反。
◆ DELE (DELETE)命令处理代码如下:
if(str.startsWith("DELE")){
str = str.substring(4);
str = str.trim();
File file = new File(dir,str);
boolean del = file.delete();
out.println("250 delete command successful");
}
DELE 命令用于删除服务器上的指定文件。
◆ LIST命令处理代码如下:
if(str.startsWith("LIST")) {
try{
out.println("150 ASCII data");
Socket tempSocket = new Socket(host,tempPort);
PrintWriter out2= new PrintWriter(tempSocket.getOutputStream(),true);
File file = new File(dir);
String[] dirStructure = new String[10];
dirStructure= file.list();
String strType="";
for(int i=0;i
if( dirStructure[i].indexOf(".") == -1) {
strType = "d ";}
else
{strType = "- ";}
out2.println(strType+dirStructure[i]);
}
tempSocket.close();
out.println("226 transfer complete");
}
catch(IOException e){}
LIST 命令用于向客户端返回服务器中工作目录下的目录结构,包括文件和目录的列表。处理这个命令时,先创建一个临时的套接字向客户端发送目录信息。这个套接字的目的端口号缺省为1,然后为当前工作目录创建File 对象,利用该对象的list()方法得到一个包含该目录下所有文件和子目录名称的字符串数组,然后根据名称中是否含有文件名中特有的“.”来区别目录和文件。最后,将得到的名称数组通过临时套接字发送到客户端。
④ 如何建立一个属于自己的FTP
如何建立一个FTP服务器(SERV-U使用教程)
在网上做过软件下载的人都知道,建立一个FTP下载服务器相对比较简单,一般用WIN2000下自带的IIS就可以,但IIS在功能上好多都不尽人如意,下面我就介绍一款功能非常强大,但使用简单的FTP服务器构建软件-Serv-U FTP Server,让我们也来体验一下自己DIYFTP服务器的快乐!
在说明使用之前,让我先大致介绍一下Serv-U(本文中提到的Serv-U版本为3.0.0.17,使用笔者所做的汉化程序):
Serv-U 是一个可以运行于Windows 95/98/2000/ME 和 Windows NT 4.0下的FTP服务器程序
有了它,你的个人电脑就可以模拟为一个FTP服务器,也就是说,你所连接的网络中的计算机用户可以访问你的个人电脑,通过FTP协议(文件传输协议)复制、移动、删除你的电脑中的文件或文件夹,可以做一切权限所允许的事情。FTP协议规定了计算机之间的标准通讯方式,使所有不同类型,不同操作系统,不同格式的电脑之间得以互换文件。它可以用最简单的方式创建用户帐号,并且在硬盘空间上划分一定的区域用以存放文件,让用户以各种FTP客户端软件(如CuteFTP、WS_FTP等)上传或下载所需要的文件。
有许多FTP服务器和客户端软件可用于不同的系统中,Serv-U是用于运行MS-Windows 并且已安装了WinSock 版本 1.1 兼容 TCP/IP 协议的个人电脑中的,这几乎包括了所有的Windows操作系统。
Serv-U由两大部分组成,引擎和用户界面。Serv-U引擎(ServUDaemon.exe)其实是一个常驻后台的程序,也是Serv-U整个软件的心脏部分,它负责处理来自各种FTP客户端软件的FTP命令,也是负责执行各种文件传送的软件。在运行Serv-U引擎也就是ServUDaemon.exe文件后,我们看不到任何的用户界面,它只是在后台运行,通常我们无法影响它,但在ServUAdmin.exe中我们可以停止和开始它。Serv-U引擎可以在任何Windows平台下作为一个本地系统服务来运行,系统服务随操作系统的启动而开始运行,而后我们就可以运行用户界面程序了。在Win NT/2000系统中,Serv-U会自动安装为一个系统服务,但在Win 9x/Me中,你需要在“服务器”面板中选择“自动开始”,才能让它转为系统服务。Serv-U用户界面(ServUAdmin.exe)也就是Serv-U管理员,它负责与Serv-U引擎之间的交互。它可以让用户配置Serv-U,包括创建域、定义用户、并告诉服务器是否可以访问。启动Serv-U管理员最简单的办法就是直接点接系统栏的“U”形图标,当然,你也可以从开始菜单中运行它。
在此有必要把Serv-U中的一些重要的概念给大家讲清楚:每个正在运行的Serv-U引擎可以被用来运行多个“虚拟”的FTP服务器,在管理员程序中,每个“虚拟”的FTP服务器都称为“域”,因此,对于服务器来说,不得不建立多个域时是非常有用的。每个域都有各自的“用户”、“组”和设置。一般说来,“设置向导”会在你第一次运行应用程序时设置好一个最初的域和用户帐号。服务器、域和用户之间的关系大家可以参考下表:
*Serv-U 服务器
*域 1
*用户帐号 1
*用户帐号 2
*用户帐号 3
*域 2
*用户帐号 1
*用户帐号 2
*域 3
*用户帐号 1
*用户帐号 1
这个表有点类似与Serv-U管理员中服务器、域和用户的排列。
Serv-U FTP Server 是试用软件,安装后三十天内,你可以作为“专业版本”使它,但试用期过后,你就只能作为免费的“个人版本”使用了,只有基本功能了。
好了,说了这么多,还没到关键部分-如何自己来建立FTP服务器。下面我就一步一步来说明。
一、 安装原版软件和汉化补丁,这个过程就不多说了,想必没人不会的。
二、 建立第一个本地FTP服务器
安装完成后程序会自动运行,你也可以在菜单中选择运行。
1、 第一次运行程序,它会弹出设置向导窗口
将会带你完成最初的设置,
2、 单击“下一步”,出现“显示菜单图像”的窗口,问你是否在菜单中显示小图像,看各人喜欢了;
3、 单击“下一步”,这个窗口是让你在本地第一次运行FTP服务器,只要“下一步”就行了。
4、 接下来要你输入你的IP地址
如果你自己有服务器,有固定的IP,那就请输入IP地址,如果你只是在自己电脑上建立FTP,而且又是拨号用户,有的只是动态IP,没有固定IP,那这一步就省了,什么也不要填,Serv-U 会自动确定你的IP地址,“下一步”;
5、 在这儿要你输入你的域名
如果你有的话,如:ftp.abc.com,没有的话,就随便填一个;
6、 “下一步”,询问你是否允许匿名访问
一般说来,匿名访问是以Anonymous为用户名称登录的,无需密码,当然如果你想成立一个会员区什么的,就应该选择“否”,不让随便什么人都可以登录,只有许可用户才行,在此我们填“是”;
7、 “下一步”,问你匿名用户登录到你的电脑时的目录
你可以自己指定一个硬盘上已存在的目录,如F:\temp\xyz;
8、 “下一步”,询问你是否要锁定该目录,锁定后,匿名登录的用户将只能认为你所指定的目录(F:\temp\xyz)是根目录,也就是说他只能访问这个目录下的文件和文件夹,这个目录之外就不能访问,对于匿名用户一般填“是”;
9、 “下一步”,询问你是否创建命名的帐号,也就是说可以指定用户以特定的帐号访问你的FTP,这对于办会员区可很有用哦,你可以对于每个人都创建一个帐号,每个帐号的权限不同,就可以不同程序地限制每个人的权利,方法将在后面讲到,这里选择“是”;
10、 “下一步”,请你填入所要建立的帐号的名称,如:ldr,
11、 “下一步”,请输入密码,如:123,
12、 “下一步”,询问登录目录是什么,这一步与第7步一样,如:F:\temp
13、 “下一步”,询问你是否要锁定该目录,同第8步,这里选择“否”;
14、 接下来询问你这次创建的用户的管理员权限,
有几项选择:无权限,组管理员,域管理员,只读管理员和系统管理员,每项的权限各不相同;这里选择“系统管理员”;
15、 最后一步,点击“完成”就OK了,你有什么需要修改的,可以点“上一步”,或者进入Serv-U管理员直接修改。
至此,我们建立了一个域ftp.abc.com,两个用户,一个Anonymous,一个ldr。
三、 既然我们已经建立好FTP服务器,那么我们就应该可以用FTP客户端软件来尝试登录。
怎么办呢?其实很简单,我们不用上网,就可以测试。我们知道,不上网时,本地机的IP地址默认就为127.0.0.1,FTP端口号为21。打开FTP客户端软件,我就用FlashFXP来说明,打开快速连接,填入相应内容,
然后连接,可以看到,我左边窗格以Anonymous登录,右边窗格以ldr登录,由于是本地机,所以速度奇快,上网后,假如我要让你登录到我的电脑上,我只要把我的上网时的IP地址给你,你就可以匿名访问我的电脑了(注意不要开防火墙),是不是很方便?
四、Serv-U管理员中的各项设置
在设置完成后,将会进入Serv-U管理员的主界面,
左边窗格中显示各个栏目,右边窗格中显示各个栏目的具体选项,下面就大概讲一讲设置内容。
1、 在图11中,我们可以人为地控制Serv-U引擎的运行或停止,记住,在Win 9x/Me 中,我们就要在此选择“系统服务”,才会运行Serv-U引擎。
2、 “许可”,如果你花美元买了注册号,就可以在此输入。
3、 “设置”,这个设置是对于“本地服务器”来说的。“常规”设置中,
可以限制服务器的最大速度,可以拦截FXP(站点到站点传送),也可以限制用户的数量,这样不至于你的服务器被拖跨。“目录缓存”设置中,
允许你自己确定目录列表的个数以及超时时间,在Windows 95 和 NT下,目录列表默认设置为25,当缓存满了之后,新的请求将替换老的请求。“高级”设置中,可以让你自己定义服务器、Socket、文件的上传和下载的各项设置。
4、 “活动”,在这里记录了用户的活动日志,已封锁的IP的活动日志,以及任务日志;任务日志中显示的就是你开始停止的各项操作记录,你可以点击右击,选择一此过滤文本,使其只显示你所想见的内容。
5、 “域”,这里包含了你一开始根据向导所建立的用户、设置、域等。“域--设置”中所设置的内容其实与第3步差不多,只是它更加具体,可以对于每一个不同域定制。“域--活动”中记载了这个域下所有用户的活动情况。
6、 “域--组”,我们可以自己建立一些便于管理的组,然后把一类的用户归到一个组中。
7、 “域--用户”中,大家可以看到一开始我们建立的两个帐号,一个Anonymous,一个ldr。现在就帐号ldr来对其中的细节设置说明一下。
A、“帐号”栏:
对于一些不守规则的人,我们可以选择“禁用帐号”,虽然有帐号,但可以使用户一时间无法登录;你也可以设置让程序到达某个日期后自动删除某个帐号;下面几栏是这个帐号的基本信息,我们都可以在此更改,其中密码改过后并不显示,而是统一显示<<Encrypted>>,特别要注意选项“锁定用户于主目录”,什么意思呢?大家应该碰到,每次我们登录到FTP服务器上后,在根目录下只显示“/”,选择这项选项后,就是这样,如果不选,会出现什么情况呢?你可以做一下试验,在根目录下将显示“/f:/temp/”,也就是说显示了你硬盘中的绝对地址,这在某些情况下是很危险的,有不怀好意的高手,你就麻烦了!
B、“常规”栏:
你可以隐藏属性为隐藏的文件,可以限制同一IP的登录个数,是否允许用户更改密码(这需要客户端软件的支持),最大上传下载的速度,超时时间以及空闲时间,你也可以限制最大用户数量,如20,说明同时只能有20个用户登录。
C、“目录访问”栏:
在此你可以控制用户对于文件目录的权限,对文件有读取、写入、删除、追加、执行等操作,对于文件夹有列表、创建、删除,以及是否继承子目录;
如果觉得目录不够,你也可以添加可访问的目录。
D、“IP访问”栏:
在这里你可以规定某个IP是否可以访问你的FTP服务器,你可以拒绝它的访问,只要填上相应的IP地址,以后由这个IP的访问通通被拦下。
E、“上传/下载率”栏:
在这里你可以设置上传和下载之间的比值,控制好上传和下载之间的数据流量关系。
F、“配额”栏:
这里你可以为每个FTP用户设置磁盘空间,点击“计算当前”,可以知道当前目前下的所有空间大小,在“最大”一栏中填入你想要限制的容量。
最后有一点,改过设置后一定要点击右键,选择“应用”使设置生效才行,否则一切都白做了!!
到此,想必大家对于如何建立属于自己的FTP有点眉目了吧?看着自己可以随意限制并监视访问者的上传、下载,以及用户的空间大小,是不是有点飘飘然的感觉?好象自己也是个无所不能的网管了 :-)
⑤ 关于如何实现FTP上传或者下载带进度和速率的实现方法
在这里需要说明的是,该方式是通过其他代码进行改进的。 首先我们需要定义一个委托,用来实现传输过程中传递文件的总数,已完成的字节数和速度,方便客户端界面上调用。 public delegate void TransferProcess(long total,long finished,double speed); 调用代码就不举例了 接下来我们建立一个FTPClient类,该类基于socket和FTP协议实现了连接FTP服务,建立目录,上传文件,下载文件等主要方法。结构如下: 需要注意的是,我们需要定一个事件event TransferProcess OnTransferProcess;该事件在实例化FTPClient之后需要调用,这个事件对实现进度条和速率是非常重要的。为了实现速率我们还需要定义个公开的成员startTime(开始时间)。我们现在主要是看一下如何上传的。 /// /// 上传一个文件 /// /// 本地文件名 public void Put(string strFileName) { //连接服务器 if (!bConnected) { Connect(); } UpdateStatus = true; //建立socket连接 Socket socketData = CreateDataSocket(); //向FTP服务器发生存储命令 SendCommand("STOR " + Path.GetFileName(strFileName)); //如何服务器返回的信息不是我们所需要的,就抛出异常 if (!(iReplyCode == 125 || iReplyCode == 150)) { throw new IOException(strReply.Substring(4)); } //建立本地文件的数据流 FileStream input = new FileStream(strFileName, FileMode.Open); int iBytes = 0; long total = input.Length;//该成员主要记录文件的总字节数,注意这里使用长整型,是为了突破只能传输2G左右的文件的限制 long finished = 0;//该成员主要记录已经传输完成的字节数,注意这里使用长整型,是为了突破只能传输2G左右的文件的限制 double speed = 0;//记录传输的速率 while ((iBytes = input.Read(buffer, 0, buffer.Length)) > 0)//循环从本地数据流中读取数据到缓冲区 { //Console.WriteLine(startTime.ToString()); socketData.Send(buffer, iBytes, 0);//将缓冲区的数据发送到FTP服务器 DateTime endTime = DateTime.Now;//每次发送数据的结束时间 TimeSpan ts = endTime - startTime;//计算每次发送数据的时间间隔 finished += iBytes;//计算完成的字节数. Console.WriteLine(ts.Milliseconds); //计算速率,注意finished是字节,所以需要换算冲K字节 if (ts.Milliseconds > 0) { speed = (double)(finished / ts.TotalMilliseconds); speed = Math.Round(speed * 1000 / 1024, 2); } //这里是必不可少的,否则你无法实现进度条 //如果传输进度事件被实例化,而且从本地数据流中读取数据不是空的并完成的字节数也不为空的话,则实现委托. if (OnTransferProcess != null&&iBytes>0&&finished>0) { OnTransferProcess(total, finished,speed); } } UpdateStatus = false; finished = 0; input.Close();//当传输完成之后需要关闭数据流,以便下次访问. if (socketData.Connected) { socketData.Close();//关闭当前的socket } if (!(iReplyCode == 226 || iReplyCode == 250)) { ReadReply(); if (!(iReplyCode == 226 || iReplyCode == 250)) { UpdateStatus = false; throw new IOException(strReply.Substring(4)); } } } 上面代码中注释写得比较详细,这里就不再一一讲解了,关于下载中实现进度条和速率的问题可以参考以上代码进行修改. 完整的代码如下: using System; using System.net; using System.IO; using System.Text; using System.net.Sockets; namespace MMSEncoder { public delegate void TransferProcess(long total,long finished,double speed); /// /// FTP Client /// public class FTPClient { public event TransferProcess OnTransferProcess; public bool UpdateStatus = true; public DateTime startTime; private bool IsAbortConnect = false; #region 构造函数 /// /// 缺省构造函数 /// public FTPClient() { strRemoteHost = ""; strRemotePath = ""; strRemoteUser = ""; strRemotePass = ""; strRemotePort = 21; bConnected = false; } /// /// 构造函数 /// /// FTP服务器IP地址 /// 当前服务器目录 /// 登录用户账号 /// 登录用户密码 /// FTP服务器端口 public FTPClient(string remoteHost, string remotePath, string remoteUser, string remotePass, int remotePort) { strRemoteHost = remoteHost; strRemotePath = remotePath; strRemoteUser = remoteUser; strRemotePass = remotePass; strRemotePort = remotePort; Connect(); } #endregion #region 登陆字段、属性 /// /// FTP服务器IP地址 /// private string strRemoteHost; public string RemoteHost { get { return strRemoteHost; } set { strRemoteHost = value; } } /// /// FTP服务器端口 /// private int strRemotePort; public int RemotePort { get { return strRemotePort; } set { strRemotePort = value; } } /// /// 当前服务器目录 /// private string strRemotePath; public string RemotePath { get { return strRemotePath; } set { strRemotePath = value; } } /// /// 登录用户账号 /// private string strRemoteUser; public string RemoteUser { set { strRemoteUser = value; } } /// /// 用户登录密码 /// private string strRemotePass; public string RemotePass { set { strRemotePass = value; } } /// /// 是否登录 /// private Boolean bConnected; public bool Connected { get { return bConnected; } } #endregion #region 链接 /// /// 建立连接 /// public void Connect() { //if (IsAbortConnect) throw new IOException("用户强制终止了FTP"); socketControl = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint ep = new IPEndPoint(IPAddress.Parse(RemoteHost), strRemotePort); // 链接 try { socketControl.Connect(ep); } catch (Exception) { throw new IOException("无法连接到远程服务器!"); } // 获取应答码 ReadReply(); if (iReplyCode != 220) { DisConnect(); throw new IOException(strReply.Substring(4)); } // 登陆 SendCommand("USER " + strRemoteUser); if (!(iReplyCode == 331 || iReplyCode == 230)) { CloseSocketConnect();//关闭连接 throw new IOException(strReply.Substring(4)); } if (iReplyCode != 230) { SendCommand("PASS " + strRemotePass); if (!(iReplyCode == 230 || iReplyCode == 202)) { CloseSocketConnect();//关闭连接 throw new IOException(strReply.Substring(4)); } } bConnected = true; // 切换到初始目录 if (!string.IsNullOrEmpty(strRemotePath)) { ChDir(strRemotePath); } } /// /// 关闭连接 /// public void DisConnect() { if (socketControl != null) { SendCommand("QUIT"); } CloseSocketConnect(); } public void AbortConnect() { if (socketControl != null) { SendCommand("ABOR"); } IsAbortConnect = true; //CloseSocketConnect(); } #endregion #region 传输模式 /// /// 传输模式:二进制类型、ASCII类型 /// public enum TransferType { Binary, ASCII }; /// /// 设置传输模式 /// /// 传输模式 public void SetTransferType(TransferType ttType) { if (ttType == TransferType.Binary) { SendCommand("TYPE I");//binary类型传输 } else { SendCommand("TYPE A");//ASCII类型传输 } if (iReplyCode != 200) { throw new IOException(strReply.Substring(4)); } else { trType = ttType; } } /// /// 获得传输模式 /// /// 传输模式 public TransferType GetTransferType() { return trType; } #endregion #region 文件操作 /// /// 获得文件列表 /// /// 文件名的匹配字符串 /// public string[] Dir(string strMask) { // 建立链接 if (!bConnected) { Connect(); } //建立进行数据连接的socket Socket socketData = CreateDataSocket(); //传送命令 SendCommand("NLST " + strMask); //分析应答代码 if (!(iReplyCode == 150 || iReplyCode == 125 || iReplyCode == 226)) { throw new IOException(strReply.Substring(4)); } //获得结果 strMsg = ""; while (true) { int iBytes = socketData.Receive(buffer, buffer.Length, 0); strMsg += GB2312.GetString(buffer, 0, iBytes); if (iBytes < buffer.Length) { break; } } char[] seperator = { '
' }; string[] strsFileList = strMsg.Split(seperator); socketData.Close();//数据socket关闭时也会有返回码 if (iReplyCode != 226) { ReadReply(); if (iReplyCode != 226) { throw new IOException(strReply.Substring(4)); } } return strsFileList; } /// /// 获取文件大小 /// /// 文件名 /// 文件大小 public long GetFileSize(string strFileName) { if (!bConnected) { Connect(); } SendCommand("SIZE " + Path.GetFileName(strFileName)); long lSize = 0; if (iReplyCode == 213) { lSize = Int64.Parse(strReply.Substring(4)); } else { throw new IOException(strReply.Substring(4)); } return lSize; } /// /// 删除 /// /// 待删除文件名 public void Delete(string strFileName) { if (!bConnected) { Connect(); } SendCommand("DELE " + strFileName); if (iReplyCode != 250) { throw new IOException(strReply.Substring(4)); } } /// /// 重命名(如果新文件名与已有文件重名,将覆盖已有文件) /// /// 旧文件名 /// 新文件名 public void Rename(string strOldFileName, string strNewFileName) { if (!bConnected) { Connect(); } SendCommand("RNFR " + strOldFileName); if (iReplyCode != 350) { throw new IOException(strReply.Substring(4)); } // 如果新文件名与原有文件重名,将覆盖原有文件 SendCommand("RNTO " + strNewFileName); if (iReplyCode != 250) { throw new IOException(strReply.Substring(4)); } } #endregion #region 上传和下载 /// /// 下载一批文件 /// /// 文件名的匹配字符串 /// 本地目录(不得以\结束) public void Get(string strFileNameMask, string strFolder) { if (!bConnected) { Connect(); } string[] strFiles = Dir(strFileNameMask); foreach (string strFile in strFiles) { if (!strFile.Equals(""))//一般来说strFiles的最后一个元素可能是空字符串 { if (strFile.LastIndexOf(".") > -1) { Get(strFile.Replace("\r", ""), strFolder, strFile.Replace("\r", "")); } } } } /// /// 下载一个文件 /// /// 要下载的文件名 /// 本地目录(不得以\结束) /// 保存在本地时的文件名 public void Get(string strRemoteFileName, string strFolder, string strLocalFileName) { if (!bConnected) { Connect(); } SetTransferType(TransferType.Binary); if (strLocalFileName.Equals("")) { strLocalFileName = strRemoteFileName; } if (!File.Exists(strLocalFileName)) { Stream st = File.Create(strLocalFileName); st.Close(); } FileStream output = new FileStream(strFolder + "\\" + strLocalFileName, FileMode.Create); Socket socketData = CreateDataSocket(); SendCommand("RETR " + strRemoteFileName); if (!(iReplyCode == 150 || iReplyCode == 125 || iReplyCode == 226 || iReplyCode == 250)) { throw new IOException(strReply.Substring(4)); } while (true) { int iBytes = socketData.Receive(buffer, buffer.Length, 0); output.Write(buffer, 0, iBytes); if (iBytes <= 0) { break; } } output.Close(); if (socketData.Connected) { socketData.Close(); } if (!(iReplyCode == 226 || iReplyCode == 250)) { ReadReply(); if (!(iReplyCode == 226 || iReplyCode == 250)) { throw new IOException(strReply.Substring(4)); } } } /// /// 上传一批文件 /// /// 本地目录(不得以\结束) /// 文件名匹配字符(可以包含*和?) public void Put(string strFolder, string strFileNameMask) { string[] strFiles = Directory.GetFiles(strFolder, strFileNameMask); foreach (string strFile in strFiles) { //strFile是完整的文件名(包含路径) Put(strFile); } } /// /// 上传一个文件 /// /// 本地文件名 public void Put(string strFileName) { if (!bConnected) { Connect(); } UpdateStatus = true; Socket socketData = CreateDataSocket(); SendCommand("STOR " + Path.GetFileName(strFileName)); if (!(iReplyCode == 125 || iReplyCode == 150)) { throw new IOException(strReply.Substring(4)); } FileStream input = new FileStream(strFileName, FileMode.Open); int iBytes = 0; long total = input.Length; long finished = 0; //DateTime startTime = DateTime.Now; double speed = 0; while ((iBytes = input.Read(buffer, 0, buffer.Length)) > 0) { Console.WriteLine(startTime.ToString()); socketData.Send(buffer, iBytes, 0); DateTime endTime = DateTime.Now; TimeSpan ts = endTime - startTime; finished += iBytes; Console.WriteLine(ts.Milliseconds); if (ts.Milliseconds > 0) { speed = (double)(finished / ts.TotalMilliseconds); speed = Math.Round(speed * 1000 / 1024, 2); } if (OnTransferProcess != null&&iBytes>0&&finished>0) { OnTransferProcess(total, finished,speed); } } UpdateStatus = false; finished = 0; input.Close(); if (socketData.Connected) { socketData.Close(); } if (!(iReplyCode == 226 || iReplyCode == 250)) { ReadReply(); if (!(iReplyCode == 226 || iReplyCode == 250)) { UpdateStatus = false; throw new IOException(strReply.Substring(4)); } } } #endregion #region 目录操作 /// /// 创建目录 /// /// 目录名 public void MkDir(string strDirName) { if (!bConnected) { Connect(); } SendCommand("MKD " + strDirName); if (iReplyCode != 257) { throw new IOException(strReply.Substring(4)); } } /// /// 删除目录 /// /// 目录名 public void RmDir(string strDirName) { if (!bConnected) { Connect(); } SendCommand("RMD " + strDirName); if (iReplyCode != 250) { throw new IOException(strReply.Substring(4)); } } /// /// 改变目录 /// /// 新的工作目录名 public void ChDir(string strDirName) { if (strDirName.Equals(".") || strDirName.Equals("")) { return; } if (!bConnected) { Connect(); } SendCommand("CWD " + strDirName); if (iReplyCode != 250) { throw new IOException(strReply.Substring(4)); } this.strRemotePath = strDirName; } #endregion #region 内部变量 /// /// 服务器返回的应答信息(包含应答码) /// private string strMsg; /// /// 服务器返回的应答信息(包含应答码) /// private string strReply; /// /// 服务器返回的应答码 /// private int iReplyCode; /// /// 进行控制连接的socket /// private Socket socketControl; /// /// 传输模式 /// private TransferType trType; /// /// 接收和发送数据的缓冲区 /// private static int BLOCK_SIZE = Int16.MaxValue; Byte[] buffer = new Byte[BLOCK_SIZE]; /// /// 编码方式(为防止出现中文乱码采用 GB2312编码方式) /// Encoding GB2312 = Encoding.Default ;//Encoding.GetEncoding("gb2312"); #endregion #region 内部函数 /// /// 将一行应答字符串记录在strReply和strMsg /// 应答码记录在iReplyCode /// private void ReadReply() { strMsg = ""; strReply = ReadLine(); iReplyCode = Int32.Parse(strReply.Substring(0, 3)); } /// /// 建立进行数据连接的socket /// /// 数据连接socket private Socket CreateDataSocket() { SendCommand("PASV"); if (iReplyCode != 227) { throw new IOException(strReply.Substring(4)); } int index1 = strReply.IndexOf('('); int index2 = strReply.IndexOf(')'); string ipData = strReply.Substring(index1 + 1, index2 - index1 - 1); int[] parts = new int[6]; int len = ipData.Length; int partCount = 0; string buf = ""; for (int i = 0; i < len && partCount <= 6; i++) { char ch = Char.Parse(ipData.Substring(i, 1)); if (Char.IsDigit(ch)) buf += ch; else if (ch != ',') { throw new IOException("Malformed PASV strReply: " + strReply); } if (ch == ',' || i + 1 == len) { try { parts[partCount++] = Int32.Parse(buf); buf = ""; } catch (Exception) { throw new IOException("Malformed PASV strReply: " + strReply); } } } string ipAddress = parts[0] + "." + parts[1] + "." + parts[2] + "." + parts[3]; int port = (parts[4] << 8) + parts[5]; Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint ep = new IPEndPoint(IPAddress.Parse(ipAddress), port); try { s.Connect(ep); } catch (Exception) { throw new IOException("无法连接服务器"); } return s; } /// /// 关闭socket连接(用于登录以前) /// private void CloseSocketConnect() { if (socketControl != null) { socketControl.Close(); socketControl = null; } bConnected = false; } /// /// 读取Socket返回的所有字符串 /// /// 包含应答码的字符串行 private string ReadLine() { while (true) { int iBytes = socketControl.Receive(buffer, buffer.Length, 0); strMsg += GB2312.GetString(buffer, 0, iBytes); if (iBytes < buffer.Length) { break; } } char[] seperator = { '
' }; string[] mess = strMsg.Split(seperator); if (strMsg.Length > 2) { strMsg = mess[mess.Length - 2]; //seperator[0]是10,换行符是由13和0组成的,分隔后10后面虽没有字符串, //但也会分配为空字符串给后面(也是最后一个)字符串数组, //所以最后一个mess是没用的空字符串 //但为什么不直接取mess[0],因为只有最后一行字符串应答码与信息之间有空格 } else { strMsg = mess[0]; } if (!strMsg.Substring(3, 1).Equals(" "))//返回字符串正确的是以应答码(如220开头,后面接一空格,再接问候字符串) { return ReadLine(); } return strMsg; } /// /// 发送命令并获取应答码和最后一行应答字符串 /// /// 命令 private void SendCommand(String strCommand) { Byte[] cmdBytes = GB2312.GetBytes((strCommand + "\r
").ToCharArray()); socketControl.Send(cmdBytes, cmdBytes.Length, 0); ReadReply(); } #endregion } }
⑥ 用C语言写一个FTP的客户端程序,需要了解哪些知识
一、需要的知识点:
1、SOCKET技术,网络编程的基本功能
2、FTP
3、如果需要自己写,可能需要熟悉各个网络框架
二、编写FTP所需要掌握的框架
1、wininet
2、libcurl
⑦ 如何搭建ftp服务器实现文件共享
实现文件双向传输搭建FTP服务器
FTP(FileTransferProtocol),是文件传输协议的简称。用于Internet上的控制文件的双向传输。同时,它也是一个应用程序(Application)。用户可以通过它把自己的PC机与世界各地所有运行FTP协议的服务器相连,访问服务器上的大量程序和信息。
FTP协议
TCP/IP协议中,FTP标准命令TCP端口号为21,Port方式数据端口为20。FTP协议的任务是从一台计算机将文件传送到另一台计算机,它与这两台计算机所处的位置、联接的方式、甚至是是否使用相同的操作系统无关。假设两台计算机通过ftp协议对话,并且能访问Internet,你可以用ftp命令来传输文件。
每种操作余山系统使用上有某一些细微差别,但是每种协议基本的命令结构是相同的。
FTP的传输有两种方式:ASCII传输模式和二进制数据传输模式。
1.ASCII传输方式:假定用户正在拷贝的文件包含的简单ASCII码文本,如果在远程机器上运行的不是UNIX,当文件传输时ftp通常会自动地调整文件的内容以便于把文件解释成另外那台计算机存储文本文件的格式。
但是常常有这样的情况,用户正在传输的文件包含的不是文本文件,它们可能是程序,数据库或孝,字处理文件或者压缩文件(尽管字处理文件包含的大部分是文本,其中也包含有指示页尺寸,字库等信息的非打印字符)。在拷贝任何非文本文件之前,用binary命令告诉ftp逐字拷贝,不要对这些文件进行处理,这也是下面要讲的二进制传输。
2.二进制传输模式:在二进制传输中,保存文件的位序,以便原始和拷贝的是逐位一一对应的。即使目的地机器上包含位序列的文件是没意义的。例如,macintosh以二进制方式传送可执行文件到Windows系统,在对方系统上,此文件不能执行。
如果你在ASCII方式下传输二进制文件,即使不需要也仍会转译。
这会使传输稍微变慢,也会损坏数据,使文件变得不能用。(在大多数计算机上,ASCII方式一般假设每一字符的第一有效位无意义,因为ASCII字符组合不使用它。如果你传输二进制文件,所有的位都是重要的。)如果你知道这两台机器是同样的,则二进制方式对文本文件和数据文件都是有效的。
FTP的工作方式
FTP支持两种模式,一种方式叫做Standard(也就是PORT方式,主动方式),一种是Passive(也就是PASV,被动方式)。Standard模式FTP的客户端发送PORT命令到FTP服务器。Passive模式FTP的客户端发送PASV命令到FTPServer。
下面介绍一个这两种方式的工作原理:
Port模式FTP客户端首先和FTP服务器的TCP21端口建立连接,通过这个通道发送命令,客户端需要接收数据的时候在这个通道上发送PORT命令。PORT命令包含了客户端用什么端口接收数据。在传送数据的时候,服务器端通过自己的TCP20端口连接至客户端的指定端口发送数据。
FTPserver必须和客户端建立一个新的连接用来传送数据。
Passive模式在建立控制通道的时候和Standard模式类似,但建立连接后发送的不是Port命令,而是Pasv命令。FTP服务器收到Pasv命令后,随机打开一个高端端口(端口号大于1024)并且通知客户端在这个端口上传送数据的请求,客户端连接FTP服务器此端口,然后FTP服务器将通过这个端口进行数据的传送,这个时候FTPserver不再需要建立一个新的和客户端之间的连接。
很多防火墙在设置的时候都是不允许接受外部发起的连接的,所竖团中以许多位于防火墙后或内网的FTP服务器不支持PASV模式,因为客户端无法穿过防火墙打开FTP服务器的高端端口;而许多内网的客户端不能用PORT模式登陆FTP服务器,因为从服务器的TCP20无法和内部网络的客户端建立一个新的连接,造成无法工作。
⑧ Linux下用C语言写一个FTP系统程序,基于客户/服务器模式
在绝大多数的LINUX发行版本中都选用的是WashingtonUniversity
FTP,它是一个着名的FTP服务器软件,一般简称为wu-ftp。它功能强大,能够很好地运行于众多的UNIX操作系统,例如:IBM
AIX、FreeBSD、HP-UX、NeXTstep、Dynix、SunOS、Solaris等。所以Internet上的FTP服务器,一大半以上采用了它。wu-ftp拥有许多强大的功能,很适于吞吐量较大的FTP服务器的管理要求:
1) 可以在用户下载文件的同时对文件做自动的压缩或解压缩操作;
2)
可以对不同网络上的机器做不同的存取限制;
3) 可以记录文件上载和下载时间;
4)
可以显示传输时的相关信息,方便用户及时了解目前的传输动态;
5) 可以设置最大连接数,提高了效率,有效地控制了负载。
& 2.2 所需资源
&1.2.1
所需包
RedHat6.2 服务器安装
&1.2.2
所需配置文件
/etc/ftpusers
/etc/ftpaccess
/var/run/ftp.pids
/etc/ftpconversions
/var/log/xferlog
/etc/ftpgroups
/etc/ftphosts
&1.2.3 相关命令
ftpd FTP服务器程序
ftpshut 用于关闭FTP服务器程序
ftpcount 显示目前在线人数
ftpwho
查看目前FTP服务器的连接情况
ckconfig 检查FTP服务器的设置是否正确
ftprestart
重新启动FTP服务
&1.2.4 相关目录
/home/ftpd/bin
存放一些供FTP用户使用的可执行文件
/home/ftpd/etc
存放一些供FTP用户使用的配置文件
/home/ftpd/pub 存放供下载的信息
/home/ftpd/incoming 存放供上载信息的空间
配置方案
1.
/etc/ftpaccess
说明: ftp权限配置文件
源文件:
guestuser weboa
# FTP用户
class all real,guest,anonymous
*
class weboa guest *
# 格式:class [类名]
[real/guest/anonymous]
[IP地址]
功能:
这个指令的功能设定FTP服务器上用户的类别。并可对客户端的IP地址进行限制,允许某部分的IP地址或全部的IP地址访问。而在FTP
服务器上的用户基本上可以分为以下三类:
real 在该FTP服务器有合法帐号的用户;
guest 有记录的匿名用户;
anonymous 权限最低的匿名用户
email [email protected]
loginfails 5
# 格式:loginfails [次数]
功能:设定当用户登录到FTP服务器时,允许用户输错密码的次数。
readme README* login
readme README* cwd=*
message /welcome.msg
login
message .message cwd=*
#
格式:message [文件名称] [指令]
功能:当用户执行所指定的指令时,系统将指定的文件内容显示出来。
compress yes all
# 格式:compress
[yes/no] [类别]
功能:设置哪一个类别的用户可以使用compress(压缩)功能。
tar
yes all
# 格式:tar [yes/no] [类别]
功能:设置哪一个类别的用户可以使用tar(归档)功能。
chmod no
guest,anonymous
# 格式:chmod [yes/no] [real/anonymous/guest]
功能:
设置是否允许指定用户使用chmod命令更改文件权限。默认是
允许。
delete yes all
# 格式:delete [yes/no]
[real/anonymous/guest]
功能:
设置是否允许指定用户使用delete命令删除文件。默认是允许。
overwrite yes guest
#
格式:overwrite [yes/no] [real/anonymous/guest]
功能:设置是否允许指定用户覆盖同名文件。默认是允许。
rename yes guest
#
格式:rename [yes/no] [real/anonymous/guest]
功能:设置是否允许指定用户使用rename命令来为文件改名。默认
是允许。
log
transfers anonymous,real inbound,outbound
# 格式:log transfers
[real/guest/anonymous] [inbound/outbound]
功能:
设置哪些用户的上载(inbound)和下载(outbound)操作做日志。
shutdown
/etc/shutmsg
# 格式:shutdown [文件名]
功能:
FTP服务器关闭的时间可以设置在后面所指定的文件中,当设
置的时间一到,便无法登录FTP服务器了,要恢复的话只有将
这个文件删掉。而这个文件必
须由指令/bin/ftpshut来生成。
passwd-check rfc822 warn
#
格式:passwd-check [none/trivial/rfc822] [enforce/warn]
功能:设定对匿名用户anonymous的密码使用方式。
none 表示不做密码验证,任何密码都可以登录;
trival 表示只要输入的密码中含有字符“@ ” "Times New Roman"'>就可以登录;
rfc822 表示密码一定要符合RFC822中所规定的E-Mail格式才
能登录;
enfore 表示输入的密码不符合以上指定的格式就不让登录;
warn
表示密码不符合规定时只出现警告信息,仍然能够登录。
limit remote 32 Any
/etc/ftpd/toomany.msg
# 格式:limit [类别] [人数] [时间] [文件名]
功能:这个指令的功能为设置指定的时间内指定的类别允许连接的
指定人数上限。当达到上限的时候,显示指定文件的内容。
upload /home/ftpd * no
upload /home/ftpd /pub yes anonymous 0644 dirs
# 格式:upload [根目录]
[上载目录] [yes/no] [用户] [权限]
[dirs/nodirs]
功能:对可以上载的目录进行更加详细的设置。
alias incoming
/home/ftp/incoming
# 格式:alias [目录别名] [目录名]
功能:给指定目录设置一个别名,在切换目录时就可以使用较短的
目录别名。
2.
/etc/ftpusers
说明:FTP用户黑名单,为了安全考虑,需要禁止以下用户使用FTP
源文件:
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
news
uucp
operator
games
nobody
在众多的网络应用中,FTP(File Transfer
porotocol)有着非常重要的地位。在Internet中一个十分重要的资源就是软件资源。而各种各样的软件资源大多数都是放在FTP服务器中的。可以说,FTP与WEB服务几乎占据了整个Internet应用的80%以上。
FTP服务可以根据服务对象的不同分为两类:一类是系统FTP服务器,它只允许系统上的合法用户使用;另一类是匿名FTP服务器,Anonymous
FTP Server,它使用任何人都可以登录到FTP服务器上去获取文件。
如果你在安装LINUX系统的时候,在选择启动进程的时候选择了“ftpd”这一项的话,安装完LINUX系统后,它已经将一个默认的FTP服务器安装到系统中去了。我们已经可以利用它来实现系统FTP服务器的功能了。我们只需在此基础上根据我们的需要进行一些个性化设定就可以了。
⑨ Linux下用C语言写一个FTP系统程序,包含server和client两部分
我觉得你可能没讲清楚吧,是写一个类似FTP功能的程序(包括server和client)?还是要实现一个FTP的server和client?前者很简单,先网络linux socket编程,再网络linux下文件读写,之后无非就是调通server和client的tcp连接之后,把读出来的东西发过去就是了。后者要实现完整的ftp协议,如果你只是本科的话,我觉得这个确实够难的,但这也是有开源代码的,http://sourceforge.net/projects/libftp/,反正是大作业,慢慢看吧。不过我感觉你的需求多半是前者,否则你们老师也太BT了,这年头谁还会自己开发ftp协议啊。。。