Python网络编程--通过fork、tcp并发完成ftp文件服务器

ftp文件服务器
 一、项目功能
     1.服务端和客户端两部分,要求启动一个服务端可以同时处理多个客户端请求
     2.功能:1).可以查看服务端文件库中所有的普通文件
                   2).从客户端可以下载文件库的文件到本地
                   3).可以将本地文件上传到服务端文件库
                  4).退出
     3. 客户端使用print在终端打印简单的命令提示,通过命令提示发起请求

二、技术分析

    1.技术分析-(fork,tcp并发)
    2.每个功能要单独封装,整体功能写在一个类中
    3.如何搭建整体架构,完成网络通讯

三、功能分析

获取文件列表
    客户端:  *发送请求
                     *得到回复判断能否获取列表
                     *接收文件名称列表打印
    服务端: * 接收请求
                     * 判断请求类型
                    * 判断能否满足请求,回复信息确认
                    * 执行请求发送文件列表

-------------------------------------------------------------------------------------华丽分割线  ~_~

  • 服务端程序
'''
ftp 文件服务器
'''
from socket import *
import time
import os,sys
import signal

#文件库路径
file_path = '/home/file/ftp/'
HOST = ''
PORT = 5000
ADDR = (HOST,PORT)

#将文件服务器功能写在类中
class FtpServer(object):
    def __init__(self,c):
        self.c = c
    def do_list(self):
        #获取文件列表
        file_list = os.listdir(file_path)
        if not file_list:
            self.c.send('文件库为空'.encode())
            return
        else:
            self.c.send(b'OK')
            time.sleep(0.1)
        files = ''
        for file in file_list:
            if file[0] != '.' and os.path.isfile(file_path+file):
                files = files + file + '#'
        self.c.sendall(files.encode())

    def do_get(self,filename):
        try:
            fd = open(file_path + filename,'rb')
        except:
            self.c.send('文件不存在'.encode())
            return
        self.c.send(b'OK')
        time.sleep(0.1)
        #发送文件
        while True:
            data = fd.read(1024)
            if not data:
                time.sleep(0.1)
                self.c.send(b'##')
                break
            self.c.send(data)
        print('文件发送完毕')
        fd.close()

    def do_upload(self,filename):
        try: 
            fd = open(file_path+filename,'wb')
        except:
            self.c.send('文件上传失败'.encode())
            return
        self.c.send(b'OK')    
        while True:
            data = self.c.recv(1024)
            if data == b'##':
                break
            fd.write(data)
        fd.close()
        print('%s上传完毕'%filename)

#创建套接字,接收客户端连接,创建新的流程
def main():
    sockfd = socket()
    sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
    sockfd.bind(ADDR)
    sockfd.listen(5)

    #处理子进程退出
    signal.signal(signal.SIGCHLD,signal.SIG_IGN)
    print('listen the port 5000...')

    while True:
        try:
            c,addr = sockfd.accept()
        except KeyboardInterrupt:
            sockfd.close()
            sys.exit('服务器退出')
        except Exception as e:
            print('服务器异常:',e)
            continue
        print('已连接客户端:',addr)

        #创建子进程
        pid = os.fork()
        #子进程处理具体请求
        if pid == 0:
            sockfd.close()
            ftp=FtpServer(c)
            #判断客户请求
            while True:
                data=c.recv(1024).decode()
                if not data:
                    c.close()
                    sys.exit('客户端退出')
                elif data[0]=='L':
                    ftp.do_list()
                elif data[0]=='G':
                    filename=data.split(' ')[-1]
                    ftp.do_get(filename)
                elif data[0]=='U':
                    filename=data.split(' ')[-1]
                    ftp.do_upload(filename)
            
        #父进程或者创建失败,都继续等待下个客户端连接
        else:
            c.close()
            continue

if __name__ == '__main__':
    main()
  • 客户端程序
  • from socket import *
    from menu import show_menu
    import sys
    import time
    
    #基本文件操作功能写在类里
    class FtpClient(object):
        def __init__(self,sockfd):
            self.sockfd=sockfd
    
        def do_list(self):
            self.sockfd.send(b'L')#发送请求
            #等待回复
            data = self.sockfd.recv(1024).decode()
            if data == 'OK':
                data = self.sockfd.recv(4096).decode()
                files = data.split('#')
                for file in files:
                    print(file)
                print('文件列表展示完毕\n')
            else:
                #由服务器发送请求失败原因
                print(data)
    
        def do_get(self,filename):
            self.sockfd.send(('G '+filename).encode())
            data = self.sockfd.recv(1024).decode()
            if data == 'OK':
                fd = open(filename,'wb')
                while True:
                    data=self.sockfd.recv(1024)
                    if data==b'##':
                        break
                    fd.write(data)
                fd.close()
                print('%s下载完毕\n'%filename)
            else:
                print(data)
    
        def do_upload(self,filename):       
            try:
                fd=open(filename,'rb')
            except:
                print('文件打开失败')
                return
            self.sockfd.send(('U '+filename).encode())
            data=self.sockfd.recv(1024).decode()
            if data=='OK':
                while True:
                    data=fd.read(1024)
                    if not data:
                        time.sleep(0.1)
                        self.sockfd.send(b'##')
                        break
                    self.sockfd.send(data)
                fd.close()
                print('%s上传完毕'%filename)
            else:
                print(data)
           
    #网络连接
    def main():
        if len(sys.argv) < 3:
            print('argv is error')
            return
        HOST = sys.argv[1]
        PORT = int(sys.argv[2])
        ADDR = (HOST,PORT)#文件服务器地址/服务端地址
    
        #创建套接字,跟服务端相同
        sockfd=socket()
        try:
            sockfd.connect(ADDR)
        except:
            print('连接服务器失败')
            return 
    
        ftp = FtpClient(sockfd) #功能类对象
        while True:
            show_menu()        
            cmd = input('请输入命令>>:')
            if not cmd:
                break
            elif cmd.strip()== '1' :
                ftp.do_list()
            elif cmd.strip()[0] =='2':
                filename=cmd.split(' ')[-1]
                ftp.do_get(filename)
            elif cmd.strip()[0]=='3':
                filename=cmd.split(' ')[-1]
                ftp.do_upload(filename)
            elif cmd.strip()[0]=='4':
                sys.exit(0)
            else:
                print('请输入正确命令!!!')
                continue
    
        # #关闭套接字
        # sockfd.close()
    
    if __name__ == '__main__':
        main()

猜你喜欢

转载自blog.csdn.net/sinat_34246179/article/details/82765528