ftp和并发

 

进程和线程的区别和联系:
1.两者都是多任务编程方式,都能够使用计算机的多核
2.进程的创建和删除消耗的计算机资源比线程要多
3.进程空间独立,数据互不干扰,有专门的通信方法,而线程使用全局变量进行通信
4.一个进程可以创建多个线程分支,两者之间存在包含关系
5.多个线程公用进程资源,在共享资源操作时往往需要同步互斥操作
6.进程线程都在系统中有自己的特有属性标志,如ID,代码段,命令集等

使用场景:
* 某个任务中并发比较多,此时多线程消耗资源较少
* 不同的独立的任务模块,用多线程相对空间比较好管理
* 在通信上考虑可行性如果数据逻辑复杂需要的同步互斥较多,这时使用线程同步互斥可能容易出错

要求:
1.进程线程的区别
2.进程间通信都知道哪些?有什么特点
3.什么是同步互斥,你在什么情况下使用
4.给一个情形,分析用进程还是线程为什么?
5.问一些概念和处理方法,僵尸进程,进程状态,线程效率

网络通信模型
服务器:
软件服务器:编写的服务器端应用程序,在硬件服务器上运行,提供一定的完整的后端服务
硬件服务器:主机  集群
httpsever------> 处理http请求
websever--------> 网站的后端服务程序
邮箱服务器-------> 邮件处理
ftp服务器------>文件处理

前端    用户端    客户端    前台应用
特征:与用户直接交互,提供给用户使用
要求:良好的用户体验

后端    服务端    后台应用
特征:提供逻辑处理,数据处理
要求:更高的并发量,更快的处理速度,更强的安全性

服务器模型
服务器的基本结构:  c/s    客户端服务器模型
 b/s 浏览器服务器模型

网络通信模型
循环服务器模型:循环接收客户端请求,处理请求,同一时刻只能处理一个请求,处理完毕后在处理下一个
优点:实现简单,占用资源少
缺点:无法同时处理多个客户端请求
适用情况:处理的任务可以很快完成,不需要建立并发,udp比tcp更适合循环模型

并发服务器模型:能够同时处理多个客户端的请求
IO并发:io 多路复用
优点:资源消耗少,能同时处理多个io
缺点:只能监控io事件,当多个任务都是cpu计算时无法同时处理

多进程多线程并发:为每个客户端创建单独的进程或者线程处理客户端请求
优点:每个客户端都可以长期占有服务器,能使用多核资源处理IO或者cpu计算
缺点:资源消耗较高

多进程并发
基于fork完成多进程网络并发
1.创建套接字,绑定,监听
2.等待接收客户端连接请求  accept
3.当有新的客户端连接时,创建新的进程处理客户端请求
4.原有进程继续等待其他客户端连接,新的进程处理客户端具体请求
5.如果客户端退出,则销毁对应的进程

ftp 文件服务器

功能:1.服务器和客户端两部分,要求启动服务器后可以有多个客户端同时操作
 2.客户端可以查看服务器文件库中有什么文件(只有普通文件,不算隐藏文件)
3.客户端可以选择文件库中的文件进行下载,下载到本地
4.客户端还可以上传本地文件到服务器文件夹(不设权限)
5.使用print打印一定的格式,作为命令的输入界面提示
技术分析: fork()并发,tcp传输,如何查看一个文件夹中的文件列表(os.listdir)
 如何判断是一个普通文件(os.path.isfile)

结构设计:使用类将功能封装

工作步骤:先搭建网络连接
设计类
将功能函数写在类中,逐一实现并测试
具体功能: 1.搭建网络连接
服务端:创建fork并发服务端程序
客户端:创建套接字,进行网络连接,连接成功后打印
命令选项界面等待输入命令
 2.设计类

 3.查看文件列表
客户端:发送请求
 接收服务端确认
 循环接收服务器发来的文件名并打印
服务端:接收请求
 判断可否执行反馈结果
 发送文件名称
4.下载文件
客户端:发送请求:G filename
接收服务端确认
接收文件
服务端:接收请求
 判断文件是否存在,反馈结果
 发送文件

多线程并发
基于threading模块
1.创建套接字,绑定监听
2.接收客户端请求
3.创建新的线程处理客户端请求
4.主线程继续等待其他客户端连接,分支线程处理其他具体请求
5.当客户端退出则线程退出

 

'''
FTP文件传输服务器
流式套接字
'''
from socket import *
import time,sys,os
HOST = '0.0.0.0'
PORT = 2505
ADDR = (HOST,PORT)
FILE_PATH ='/home/tarena/aid1808/linux/pythonnet/day08/ftp/'

class FtpServer():
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 += file +'#'
# 将拼接好的文件列表字符串发送给客户端
self.c.sendall(files.encode())
 
def do_get(self,filename):
try:
f = open(FILE_PATH+filename,'rb')
except:
f.close()
self.c.send("文件不存在".encode())
return
else:
self.c.send("OK".encode())
time.sleep(0.1)
while True:
data = f.read(1024)
if not data:
time.sleep(0.1)
self.c.send(b'##')
break
self.c.send(data)
f.close()
def do_put(self,filename):
# print("wait")
try:
f = open(FILE_PATH+filename,'wb')
# print("open")
except:
self.c.send("文件上传服务器失败".encode())
f.close()
return
else:
self.c.send(b"OK")
time.sleep(0.1)
while True:
# print("***")
data = self.c.recv(1024)
if data == b"##":
break
f.write(data)
f.close()
print("接收完毕")
 
 

 
 



def main():

#创建套接字
s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(ADDR)
s.listen(5)
print("wait for connect...")
while True:
try:
c,addr = s.accept()
except KeyboardInterrupt:
s.close()
sys.exit("服务器退出")
except Exception as err:
print('Error',err)
continue
print("连接到客户端",addr)
#创建子进程,子进程去处理客户端请求,主进程继续等待其他客户端的连接
pid = os.fork()
if pid == 0:
# 创建二级子进程,一级子进程退出,主进程回收一级子进程,二级子进程执行请求,防止僵尸进程
p = os.fork()
if p == 0:
s.close() #防止子进程拥有主进程全部代码,误操作
#在二级子进程中,先将收到的请求分类,将处理的请求在类中封装处理..
# 创建对象
ftp = FtpServer(c)
# 循环接收用户的请求
while True:
data = c.recv(1024).decode()
if not data or data[0].strip().upper()=='Q':
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] == 'P':
filename = data.split(' ')[-1]
ftp.do_put(filename)



else:
os._exit(0) # 创建二级子进程失败后,程序跳出循环,重新等待连接

else:
c.close()
os.wait() #因为一级子程序很快就会结束,所以主进程回收一级子进程
continue


# 测试代码
if __name__=='__main__':
main()
 
'''
FTP文件传输客户端
'''
from socket import *
import time
import sys

class FtpClient():
def __init__(self,s):
self.s = s
 
def do_list(self):
self.s.send(b'L')
data = self.s.recv(128).decode()
if data == 'OK':
files = self.s.recv(4096).decode()
file_list = files.split('#')
for file in file_list:
print(file,end=' ')
print()
print("文件展示完毕")
else:
print(data)
def do_quit(self):
self.s.send(b'Q')
self.s.close()
sys.exit('谢谢使用')
 
def do_get(self,filename):
self.s.send(('G ' + filename).encode())
data = self.s.recv(128).decode()
if data == "OK":
try:
f = open(filename,'wb')
except:
print("打开文件失败")
return
else:
while True:
data1 = self.s.recv(1024)
if data1 == b'##':
break
f.write(data1)
f.close()
print('%s下载完毕'%filename)
else:
print(data)
def do_put(self,filename):
try:
f = open(filename,'rb')
# print("open")
except:
print("上传文件失败")
f.close()
return
self.s.send(('P '+filename).encode())
data = self.s.recv(128).decode()
if data == "OK":
while True:
data1 = f.read(1024)
if not data1:
time.sleep(0.1)
self.s.send(b'##')
break
self.s.send(data1)
f.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)
# 创建套接字
s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
try:
s.connect(ADDR)
except Exception as err:
print("连接服务器失败",err)
return
 
# 创建对象
ftp = FtpClient(s)

while True:
print('============命令选项============')
print('1)****** list ******')
print('2)****** get file ******')
print('3)****** put file ******')
print('4)****** quit ******')
#用户输入选择
cmd = input(">>>")
if cmd.strip() == 'list':
ftp.do_list()
elif cmd.strip() == 'quit':
ftp.do_quit()
elif cmd[:3] == 'get':
filename = cmd.split(' ')[-1]
ftp.do_get(filename)
elif cmd[:3] == "put":
filename = cmd.split(' ')[-1]
ftp.do_put(filename)
else:
print("请重新输入命令")






# 测试代码
if __name__=='__main__':
main()
 


from socket import *
import os,sys

def client_handler(c):
print('客户端:',c.getpeername())
while True:
data = c.recv(1024)
if not data:
break
print(data.decode())
c.send(b'Receive your message')
c.close()
sys.exit(0) #将子进程销毁

#创建套接字
HOST = '0.0.0.0'
PORT = 2505
ADDR = (HOST,PORT)

s = socket() #tcp套接字
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(ADDR)
s.listen(5)

#循环等待客户端连接
print('Listen to the port 2505....')
while True:
try:
c,addr = s.accept()
except KeyboardInterrupt:
sys.exit("退出服务器")
except Exception as e:
print('Error:',e)
continue
 
#创建新的进程处理客户端请求
pid = os.fork()

#子进程处理客户端请求
if pid == 0:
p = os.fork()
if p==0:
s.close()
client_handler(c) #客户端处理函数
else:
os._exit(0)
# 父进程或者创建进程失败都继续等待下个客户端连接
else:
c.close()
os.wait()
continue



'''
基于Process多进程服务器
'''

from multiprocessing import *
from socket import *
import sys

HOST = '0.0.0.0'
PORT = 2505
ADDR = (HOST,PORT)

def handler():
print('Connect from ',c.getpeername())
while True:
data = c.recv(1024)
if not data:
break
print(data.decode())
c.send(b'Receive')
c.close()
sys.exit(0)

# 创建套接字
s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(ADDR)
s.listen(5)

# 接收客户端请求
while True:
try:
c,addr = s.accept()
except KeyboardInterrupt:
s.close()
sys.exit('服务器退出')
except Exception as err:
print(err)
continue
# 创建新的线程
t = Process(target = handler)
t.daemon=True
t.start()



 

转载于:https://www.cnblogs.com/yuzhoudiyishuai/p/10720372.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值