PYTHON2.day08

前情回顾

1. 进程间通信
    共享内存 : 在内存中开辟空间,只能存一组数据,效率
                高
         Value() --> 单一数据
         Array() --> 存放数组,字符串等
   
    信号量 : Semaphore() 创建信号量
              acquire() 消耗信号量
              release() 增加信号量
2.  什么是线程:
     线程特点
     创建多线程
        threading --> Thread

           Thread()  创建线程对象
        start()   启动线程
        join()    回收线程
    
     线程对象属性
        t.name  名称
        t.daemon 主线程退出后分支线程是否退出
        t.is_alive()  查看状态
        currentThread() 获取线程对象
    
     自定义线程类
        1. 继承Thread
        2. 编写自己的__init__
        3. 重写run

线程通信
     1.通信方法:全局变量
     2. 同步互斥方法
        Event()
         e.set()  e.wait() e.clear()  e.is_set()

       Lock()
             acquire()   release()

4.线程的GIL问题
       全局解释器锁:同一时刻只有一个线程被解释,直接导致python线程效率低下
      

一.测试
     1.结论:在无阻塞状态下,多线程程序和单线程程序执行效率几乎差不多,甚至还不如单线程效率
             但是多线程运行相同的内容却可以有明显的效率提升
            
     2.python线程的GIL问题(全局解释器锁)
       【1】什么是GIL问题
            由于python 解释器设计中加入了解释器锁,
            导致python解释器同一时刻只能解释一个线程,大大降低了执行效率
       【2】导致后果,因为遇到阻塞时线程会让出解释器,去解释其他线程,
            所以python多线程在执行多阻塞高延迟IO时可以提升程序效率,
            其他情况并不能对效率有所提升
       【3】*尽量使用进程完成无阻塞的并发行为
            *不使用c作为解释器(java c#)
           
           
二.进程线程的区别联系
     【1】区别和联系
         1.两者都是多任务编程方式,都能使用多核资源
         2.进程的创建删除消耗的计算机资源比线程多
         3.进程的空间多,数据不相干扰,有专门通信的方法:线程使用那些局部变量通信
         4.有个进程可以有多个分支线程,两者有包含关系
         5.多个线程共享进程资源,在共享资源操作时往往需要同步互斥处理
         6.进程线程在系统中都有自己的特有属性标志,如ID,代码段命令集等
      【2】使用场景
           1.任务场景:如果是相对独立的任务模块,可能使用多进程,
                       如果是多个分支共同形成一个整体任务可能用多线程
           2.项目结构:多种编程语言实现不同任务模块,可能是多进程,或者后端分离应该各自为一个进程
           3.难易程度:通信难度,数据处理的复杂度来判断进程间通信还是同步互斥
      【3】要求:1.对进程线程怎么理解/说说进程线程的差异
                 2.进程间通信有哪些,有什么特点
                 3.什么是同步互斥,什么情况下使用,用什么
                 4.给一个情形,说说用进程还是线程,为什么
                 5.同一个概念,僵尸进程的处理,GIL问题,进程状态。
                
三.网络通信模型   
         1.通信模型分类
            
             【1】循环服务器模型:
                 循环接收客户端请求,处理请求,同一时刻只能处理一个请求,
                 处理完毕再处理下一个
                
                 优点:实现简单占有资源少
                 缺点:无法同时处理多个客户端请求
                
                 适用情况:处理的任务可以很快完成,客户端无需长期占用服务端程序,
                           udp比tcp更适合循环
                          
             【2】IO并发模型:利用IO多路复用技术可以同时处理多个客户端IO请求
                
                 优点:资源消耗少,能同时高效处理多个IO行为
                 缺点:只能处理并发的IO事件,无法处理cpu计算
                
                 适用情况:HTTP请求,网络传输等都是IO行为,都可以充分可利用IO多路复用
                
            【3】多进程/线程的网络并发模型:
                 每当一个客户端连接服务器,就创建一个新的进程/线程我该客户服务,
                 客户端退出时销毁该进程/线程

                缺点:资源消耗较大
                 使用情况:客户点同时连接量较少,需要处理行为较复杂情况。
                
         2.层多进程网络并发模型
             【1】基于fork的并发模型
                 1.创建监听套接字
                 2.等待接收客户端请求
                 3.客户端连接创建新的进程处理客户端请求
                 4.原来进程继续等待其他客户端连接
                 5.如果客户端退出,则销毁的对应的进程
                
四.ftp文件服务器
     1.功能:
             【1】分为服务端和客户端,要求可以有多个客户端同时操作
             【2】客户端可以查看文件库中有什么样的文件
             【3】客户端可以从文件库中下载文件到本地
             【4】客户端可以上传文件到文件库
             【5】使用print客户端打印输入提示,引导操作
     2.技术分析
       (1)使用fork多进程并发
       (2)tcp套接字传输
       (3)获取文件列表os.listdir()
          判断普通文件os.path.isfile()
     3.结构设计(操作流程)
       (1)客户端启动后打印界面
       (2)客户端发起请求后服务器要判断能否处理将结果反馈给客户端
       (3)若不能处理则终止请求行为,能处理子具体操作
       (4)将文件的具体功能封装为类
     4.具体功能分析      
       (1)搭建网络连接
       (2)查看文件列表
       (3)下载文件
       (4)上传文件
       (5)客户端退出
      

  1 #服务端
  2 '''ftp文件服务器
  3 fork server训练
  4 '''
  5 from socket import *
  6 import os,sys
  7 from time import sleep
  8 import signal
  9 import time
 10 
 11 #全局变量
 12 HOST = '0.0.0.0'
 13 PORT = 8888
 14 ADDR = (HOST,PORT)
 15 FILE_PATH = '/home/tarena/wenjan/'
 16 
 17 class FtpServer(object):
 18     def __init__(self,connfd):
 19         self.connfd = connfd
 20 
 21     def do_list(self):
 22         #获取文件列表
 23         file_list = os.listdir(FILE_PATH)
 24         if not file_list:
 25             self.connfd.send("文件库问空".encode())
 26             return
 27         else:
 28             self.connfd.send(b'OK')
 29             time.sleep(0.1)
 30 
 31         files = ""
 32         for file in file_list:
 33             if file[0] != '.' and os.path.isfile(FILE_PATH+file):
 34                 files = files + file + ','
 35 
 36         #将拼接好的字符串传给客户端
 37         self.connfd.send(files.encode())
 38 
 39 
 40 
 41     def do_get(self,filename):
 42         try:
 43             fd = open(FILE_PATH+filename,'rb')
 44         except IOError:
 45             self.connfd.send("文件不存在".encode())
 46             return
 47         else:
 48             self.connfd.send(b'OK')
 49             time.sleep(0.1)
 50         #发送文件内容
 51         while True:
 52             data = fd.read(1024)
 53             if not data:
 54                 time.sleep(0.1)
 55                 self.connfd.send(b'##')
 56                 break
 57             self.connfd.send(data)
 58 
 59 
 60     def do_put(self,filename):
 61         if os.path.exists(FILE_PATH + filename):
 62             self.connfd.send('文件存在'.encode())
 63             return
 64         try:
 65             fd = open(FILE_PATH+filename,'wb')
 66         except:
 67             self.connfd.send('上传失败'.encode())
 68             return
 69         self.connfd.send(b'OK')
 70         #接收文件
 71         while True:
 72             data = self.connfd.recv(1024)
 73             if data == b'##':
 74                 break
 75             fd.write(data)
 76         fd.close()
 77 
 78 
 79 
 80 def do_request(connfd):
 81     ftp = FtpServer(connfd)
 82     while True:
 83         data = connfd.recv(1024).decode()
 84         if not data or data[0] =='Q':
 85             connfd.close()
 86             return
 87         elif data[0] == 'L':
 88             ftp.do_list()
 89         elif data[0] =='G':
 90             filename = data.split(" ")[-1]
 91             ftp.do_get(filename)
 92         elif data[0] == 'P':
 93             filename = data.split(' ')[-1]
 94             ftp.do_put(filename)
 95 
 96 
 97 
 98 
 99 
100 #网络搭建
101 def main():
102     #连接网络
103     #创建套接字
104     sockfd = socket()
105     sockfd.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)#循环
106     sockfd.bind(ADDR)#绑定
107     sockfd.listen(5)#监听
108     print("Listen to the port 8888 ...")
109     #处理僵尸进程
110     signal.signal(signal.SIGCHLD,signal.SIG_IGN)
111 
112     while True:
113         try:
114             connfd,addr = sockfd.accept()
115         except KeyboardInterrupt:
116             sockfd.close()
117             sys,exit("服务器退出")
118         except Exception as e:
119             print("服务器异常:",e)
120             continue
121         print("连接客户顿:",addr)
122 
123         #创建子进程处理客户端请求
124         pid = os.fork()
125         if pid ==0:
126             sockfd.close()
127             do_request(connfd)#处理客户端请求
128             os._exit(0)
129         #无论是父进程或者创建进程失败都是逊汗接收新的连接
130         else:
131             connfd.close()
132 
133 if __name__=="__main__":
134     main()
server.py

  1 #客户端
  2 from socket import *
  3 import sys
  4 import time
  5 
  6 #具体功能
  7 class FtpClient(object):
  8     def __init__(self,sockfd):
  9         self.sockfd = sockfd
 10 
 11 
 12     def do_list(self):
 13         self.sockfd.send(b'L')#发送请求
 14         #等待回复
 15         data = self.sockfd.recv(128).decode()
 16         if data =='OK':
 17             #接收文件名称
 18             data = self.sockfd.recv(4096).decode()
 19             files = data.split(',')
 20             for file in files:
 21                 print(file)
 22         else:
 23             #无法完成操作
 24             print(data)
 25 
 26 
 27     def do_quit(self):
 28         self.sockfd.send(b'Q')
 29         self.sockfd.close()
 30         sys.exit("谢谢使用")
 31 
 32 
 33     def do_get(self,filename):
 34         self.sockfd.send(('G '+filename).encode())
 35         data = self.sockfd.recv(128).decode()
 36         if data == 'OK':
 37             fd = open(filename,'wb')
 38             while True:
 39                 data = self.sockfd.recv(1024)
 40                 if data == b'##':
 41                     break
 42                 fd.write(data)
 43             fd.close()
 44         else:
 45             print(data)
 46 
 47     def do_put(self,filename):
 48         try:
 49             f = open(filename,'rb')
 50         except Exception:
 51             print("没有找打文件")
 52             return
 53         filename = filename.split('/')[-1]
 54         self.sockfd.send(('P '+filename).encode())
 55         data = self.sockfd.recv(128).decode()
 56         if data == 'OK':
 57             while True:
 58                 data = f.read(1024)
 59                 if not data:
 60                     time.sleep(0.1)
 61                     self.sockfd.send(b'##')
 62                     break
 63                 self.sockfd.send(data)
 64             f.close()
 65             print("%s上传完毕"%filename)
 66         else:
 67             print(data)
 68 
 69 
 70 
 71 #网络连接
 72 def main():
 73     #服务器地址
 74     ADDR = ('127.0.0.1',8888)
 75 
 76     sockfd = socket()
 77     try:
 78         sockfd.connect(ADDR)
 79     except Exception as e:
 80         print("连接服务器失败:",e)
 81         return
 82 
 83     #创建文件处理类对象
 84     ftp = FtpClient(sockfd)#把sockfd -->属性
 85 
 86 
 87     while True:
 88         print("
-------------命令选项------------")
 89         print("***            list           ***")
 90         print("***           get  file       ***")
 91         print("***           put  file       ***")
 92         print("***              quit         ***")
 93         print("----------------------------------")
 94 
 95         cmd = input("输入命令>>")
 96         if cmd.strip() == 'list':
 97             ftp.do_list()
 98         elif cmd[:3] == 'get':
 99             filename = cmd.strip().split(' ')[-1]
100             ftp.do_get(filename)
101         elif cmd.strip() == 'quit':
102             ftp.do_quit()
103         elif cmd[:3] == 'put':
104             filename = cmd.split(' ')[-1]
105             ftp.do_put(filename)
106         else:
107             print("请输入正确命令")
108 
109 
110 
111 
112 
113 if __name__=="__main__":
114     main()
clent.py

list

get

put
       quit
作业:1.完成文件服务器上传功能
       2.复习http协议和httpserver1.0
       3.复习mysql的基本语句
       4.自己完成进程线程基础程序fork Process Thread

原文地址:https://www.cnblogs.com/shengjia/p/10420450.html