xxftp:写了一个功能比较全面的FTP服务器小程序

新版本链接:再次400多行Python代码实现了一个FTP服务器

xxftp WIN32可执行文件及源代码下载地址:xxftp20110217

如有需要,可自行编译Linux版本!

笔记:
已经写了很多个FTPServer了。。。可以说是滚瓜烂熟,代码都可以背出来!
记得上次那个是用C#写的,不怎么好用,又吃内存,又吃CPU!
这次采用多线程写的xxftp,体积不到64KB,运行一段时间之后才占用几MB的内存,而且很好用!
对于像我这样做免费服务又节约资源的站长,适合的才是最好的!

每写一次FTPServer,较之前都有很大的,思路一次比一次清晰,代码一次比一次好看,功能一次比一次强大!
这次增加了OPTS,FEAT,EPSV,EPRT,MTDM等命令,详见源代码中的ftp.h。

这次的服务器模型跟之前写homeserver是不同的,这次不是很注重并发响应能力。之前的homeserver在启动的时候就初始化了足够的线程来等待用户请求,避免响应迟钝的现象。而xxftp服务器运行时候,启动一个守护线程用来回收超时或者已经结束的FTP连接,启动一个监听线程等待用户连接。当有连接请求时,创建一个connection对象和对应的线程去处理用户请求。

这次读取FTP命令,用了一个字节一个字节读取的方法,写起来比较简单易懂,不过代码也不是很短。

	int read_cmd = 1;
	char cmd[16+4];
	char arg[1024+4];
	int pos = 0;
	for(; !conn->conn_end; ){
		char ch;
		int ret = recv(conn->conn_fd, &ch, 1, 0);
		if(ret <= 0){
			if(ret == 0){
				closesocket(conn->conn_fd);
				conn->conn_fd = 0;
			}
			conn->conn_end = 1;
			break;
		}
		if(read_cmd){
			switch(ch){
			case ' ':
				cmd[pos] = '\0';
				read_cmd = 0;
				pos = 0;
				break;
			case '\r':
				break;
			case '\n':
				cmd[pos] = '\0';
				pos = 0;
				conn_command(conn, cmd, NULL);
				break;
			default:
				if(pos < 16)
					cmd[pos++] = toupper(ch);
			}
		}else{
			switch(ch){
			case '\r':
				break;
			case '\n':
				arg[pos] = '\0';
				read_cmd = 1;
				conn_command(conn, cmd, arg);
				pos = 0;
				break;
			default:
				if(pos < 1024)
					arg[pos++] = ch;
			}
		}
	}

输出到FTP客户端的消息,需要进行格式化,对于多行的消息要做特别的处理。
格式化后字符串空间会变大,必须要保证有足够的空间来容纳,以免内存溢出。
例如状态码为220的欢迎消息

Hi, xiaoxia!
Welcome!
Enjoy it!

格式化之后变为:

220-Hi, xiaoxia!
220-Welcome!
220 Enjoy it!

代码如下:

int ftpmsg_format(int code, char* src, char* dst, int dst_len)
{
	char *p, *pv, *q = dst;
	for(p = src; pv = strchr(p, '\n'); p = pv+1)
		if((q-dst) + 10 + (pv-p) < dst_len)
			q += sprintf(q, "%d-%.*s\n", code, (int)(pv-p), p);
			
	if((q-dst) + 10 + strlen(p) < dst_len)
		q += sprintf(q, "%d %s\r\n", code, p);
	return q - dst;
}

readme.txt:

xxftp is a free FTP server.
You can get the latest version at www.xiaoxia.org or contact me
by [email protected]!

To use it, you should

1. Create a root directory to hold the user directories. 
   Configure it in config.xml.
2. Create user directories under the root directory. 
   If you want to specify a password, create a directory named ".xxftp",
   under which create a text file named "password" containing the MD5 
   code of the password.
3. If you want to specify the welcome and goodbye message, write it in 
   xxftp.welcome and xxftp.goodbye under the root directory.
4. Configure config.xml.

The structure of your FTP server root may be like:

-/root
	-xxftp.welcome
	-xxftp.goodbye

	-user1
		-.xxftp
			-password
		-...
	-user2
		-.xxftp
			-password
		-...
	-anonymous
		-...

xxftp:写了一个功能比较全面的FTP服务器小程序》有30个想法

  1. suess

    小虾,这个程序在linux 有些问题,例如在成功传输了一个或者几个文件成功之后,就会提示段错误了。
    控制台输出:
    listdir(46): listing home/anonymous/
    conn_sendmsg(21): >> 226 list ok.
    conn_command(98): <> 200 PORT command successful.
    conn_command(98): <> 150 Opening BINARY mode data connection for file transfer.
    conn_sendmsg(21): >> 226 ok.
    conn_command(98): <> 200 PORT command successful.
    conn_command(98): <> 150 here comes the directory listing.
    listdir(46): listing home/anonymous/
    conn_sendmsg(21): >> 226 list ok.
    段错误

    回复
    1. Xiaoxia 文章作者

      我之前在conn.c处理cmd, argv的变量的时候修正了一处内存访问错误,不知道有没有更新到博客上!

      回复
  2. Pingback引用通告: 自己收藏的经典软件集合 | 好豆饼

  3. Ean

    foreach(QFileInfo my_info,dir.entryInfoList())
    {

    QString info;
    QString isF,isR,isW,siZ,inFo;
    QDateTime modyf;
    isF = my_info.isFile()?”-“:”d”;
    isR = my_info.isReadable()?”r”:”-“;
    isW = my_info.isWritable()?”w”:”-“;
    siZ = my_info.size();

    modyf = my_info.lastModified();
    QString moditime = modyf.toString();

    inFo = my_info.fileName();
    info = QString(“%1%2%3——- %4 %5 %6 %7 %8 %9\r\n”).arg(isF).arg(isR).arg(isW)
    .arg(1).arg(‘0’).arg(‘0’).arg(siZ).arg(moditime).arg(inFo);
    qDebug()<write(info.toAscii());

    }

    回复
  4. Ean

    请问,上面那样我wirte发送数据发送不过去,,是我的格式不对?还是发送数据类型部队。。。。谢谢

    回复
  5. youzi

    请教xiaoxia,我建立好了数据连接,发送目录应该用什么格式客户端才能够处理呢?我写的服务器其他客户端都不能获取目录,急求答案!

    回复
  6. Pingback引用通告: 自己收藏的经典软件集合 | 星期七

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据