新版本链接:再次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 -...
sofa
eat ib!
mark = =
小虾,我看不懂。小虾,梨子好想你。
可以说是滚瓜烂熟,代码都可以背出来!
—
这么厉害啊。
夸张手法~!
这个不错,我刚好使用
小虾,fox2好像又不行了
因为换windows服务器了,未配置fox2.
原来如此。估计什么时候可以配置好呢
已经配置好!!!可以使用了!
支持中文目录?
支持utf8,可以支持中文目录!
这个给力!!!!!
小虾,这个程序在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.
段错误
我之前在conn.c处理cmd, argv的变量的时候修正了一处内存访问错误,不知道有没有更新到博客上!
不过还是谢谢你的提醒!改天我更新一下。
恩,谢谢小虾
Pingback引用通告: 自己收藏的经典软件集合 | 好豆饼
客户端在哪下,谢谢!
本页附带的链接,谢谢!
linux版的客户端,在哪,我没找到,谢谢!
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());
}
请问,上面那样我wirte发送数据发送不过去,,是我的格式不对?还是发送数据类型部队。。。。谢谢
好像要建立另外一个传输数据用的socket,你建立了么?
请教xiaoxia,我建立好了数据连接,发送目录应该用什么格式客户端才能够处理呢?我写的服务器其他客户端都不能获取目录,急求答案!
你可以抓包看一下别人什么格式的,然后学习他。。。
请问.mk和.project怎么用?我想重新编译链接运行一遍。谢谢。
代码很少,可以自己写一个Makefile 😀
Pingback引用通告: 自己收藏的经典软件集合 | 星期七