Python实现小型FTP服务

相比于BaseHTTPServer,Python中基于TCP协议的SocketServer显得更加底层,也有更多的灵活性来实现自己的功能。这里记录下练习这个模块写的一个小型的FTP服务器。

编程中我也遇到了一个问题,就是recv循环接收的阻塞问题,如果直接setblocking(0),那么最后一次接收的时候还是会抛出异常。这里我想的方法是通信双发约定好发送结尾的flag,通过这个flag去鉴定是否是接收完毕,程序中我使用file_end来标示,基本实现了recv的循环接收。

下面就是直接贴下代码了:

服务器端源码:

#coding=utf-8
'''
使用SocketServer编写FTP服务功能
'''
import SocketServer
from SocketServer import ThreadingMixIn
from SocketServer import TCPServer
import os
import time

class MyTCPHandler(SocketServer.BaseRequestHandler):
    
    def confirm(self,username,password):
        if username == 'root' and password == 'root':
            return True
        else:
            return False

    def handle(self):
        while True:
            print 'Connected by %s' % self.client_address[0]
            self.username = self.request.recv(1024)
            self.password = self.request.recv(1024)

            self.username = self.username.strip()
            self.password = self.password.strip()
            print 'recv: %s %s' % (self.username,self.password)

            '''登录验证'''
            if not (self.username and self.password):
                break
            if not self.confirm(self.username,self.password):
                self.request.send('Auth Failed!')
                break
            
            '''认证成功,开启功能'''
            self.request.send('Welcome, %s !' % self.username)
            while True:
                self.cmd = self.request.recv(1024).strip()
                if not self.cmd or self.cmd == 'quit':
                    break
                #返回help信息
                elif self.cmd == 'help':
                    helpinfo = '''
                        Help Info\n[+]downloadfile [filename] [path]\n[+]uploadfile [filename] [path]\n[+]ls\n[+]quit\n
                    '''
                    self.request.sendall(helpinfo)
                #执行dir命令
                elif self.cmd.startswith('dir'):
                    cmd_res = os.popen('dir').read()
                    self.request.sendall(cmd_res + '\0\n')

                #下载文件
                elif self.cmd.startswith('downloadfile'):
                    downloadinfo = self.cmd.split(' ')
                    filepath = downloadinfo[1]
                    f = open(filepath,'rb')
                    if not f: break
                    data = f.read()
                    data = data + 'file_end'
                    self.request.sendall(data)
                    f.close()

                #上传文件
                elif self.cmd.startswith('uploadfile'):
                    uploadinfo = self.cmd.split(' ')
                    filepath = uploadinfo[2]
                    data = ''
                    f = open(filepath,'w')
                    while True:
                        a = self.request.recv(1024)
                        data = data + a
                        if a.endswith('file_end'):
                            f.write(a.replace('file_end',''))
                            break
                        f.write(data)
                    f.close()
                    print 'RECV file:%s' % filepath                    
                else:
                    pass




class ThreadingSocketServer(ThreadingMixIn,TCPServer):
    pass


if __name__ == '__main__':
    serveraddr = ('127.0.0.1',8000)
    ftpserver = TCPServer(serveraddr,MyTCPHandler)
    ftpserver.serve_forever()


客户端源码:

#coding=utf-8
'''
FTP服务器的客户端
'''
import socket
import getpass
import sys,time

print 'Welcome to FTP client!'
serveraddr = ('127.0.0.1',8000)
clientfd  = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
clientfd.connect(serveraddr)


username = raw_input('User :')
clientfd.sendall(username.strip() + '\n')
password = getpass.getpass('Pass :')
clientfd.sendall(password.strip() + '\n')
infos = clientfd.recv(1024).strip()
print infos


if infos == 'Auth Failed!':
    clientfd.close()
    print 'Exit!'
    sys.exit()


while True:
    cmd = raw_input('ftp>')
    if not cmd:
        continue
    elif cmd.startswith('dir'):
        clientfd.send(cmd)
        #设置socket为非阻塞
        clientfd.setblocking(0)
        while True:
            try:
                #防止出错,做一个假的阻塞
                time.sleep(0.3)
                a = clientfd.recv(1024)
                print a
                if not len(a):break
            except:
                break
        #将socket还原为阻塞,否则下面的recv和send会报错
        clientfd.setblocking(1)
        # print clientfd.recv(1024).strip() 

    elif cmd.startswith('help'):
        clientfd.send(cmd)
        print clientfd.recv(1024).strip()

    elif cmd.startswith('downloadfile'):
        filepath = cmd.split(' ')[2]
        clientfd.sendall(cmd)
        f = open(filepath,'a')
        data = ''
        while True:
            a = clientfd.recv(1024).strip()
            data = data + a
            if a.endswith('file_end'):
                f.write(a.replace('file_end',''))
                break
            f.write(data)
        f.close()


        print 'Downloadfile Success! %s' % filepath

    elif cmd.startswith('uploadfile'):
        filepath = cmd.split(' ')[1]
        clientfd.sendall(cmd)
        f = open(filepath,'rb')
        data = f.read()
        data = data + 'file_end'
        clientfd.sendall(data)
        f.close()
        print 'Uploadfile Success! %s' % filepath
    else:
        print 'Unknown Service!'
        continue

clientfd.close()



©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页