zoukankan      html  css  js  c++  java
  • python学习之路-10 网络编程之进阶

    本篇介绍内容

    • 作用域
    • python类的多继承
    • IO多路复用
    • socketserver之源码剖析
    • 多线程和多进程

    作用域

    if 1 == 1:
    	name = "xxx"
    
    print(name)
    
    

    上面代码在python和javascript中没有块级作用域,是可以执行的但是在c#和java中有块级作用域,会报错变量name不存在

    python的作用域链

    • 由内向外找
    • 找不到就报错

    当程序还没执行作用域在执行之前就已经定义好了,下面的例子证明了这点

    name = "aaa"
    
    def f2():
    	name = "bbb"
    	def f1():
    		print(name)
    	f1()
    f2() # 在f2执行之前f1和f2的作用域就已经被定义好了
    
    # 输出
    bbb
    
    
    name = "aaa"
    def f1():
    	print(name)
    
    def f2():
    	name = "bbb"
    	f1()
    f2() # 在f2执行之前f1和f2的作用域就已经被定义好了
    # 输出
    aaa
    
    name = "aaa"
    def f1():
    	print(name)
    
    def f2():
    	name = "bbb"
    	return f1
    
    # 在f2函数被执行之前f1和f2的作用域就已经被定义好了
    ret = f2()
    ret()
    
    # 输出
    aaa
    
    li = [lambda:x for x in range(10)] 
    
    上面的语句等同于下面的
    
    li = []
    for x in range(10):
    
        def f1():
            return x
    
        li.append(f1)
    print(li[0]())
    

    多继承

    • python3

    • python2.7

      • 经典类
      • 新式类 继承object

    IO多路复用

    select poll epoll

    IO多路复用底层就是监听socket对象内部是否有变化,是否在收发消息

    • select IO多路复用之监听客户端连接

      • 服务端
      import socket
      import select
      
      sk = socket.socket()
      sk.bind(("127.0.0.1", 9999,))
      sk.listen(5)
      
      while True:
          rlist, w, e = select.select([sk, ], [], [], 5)
          # 监听sk(服务器端)对象,如果sk对象发生变化,表示有客户端来连接了,此时rlist值为[sk]
          # 监听conn对象,如果conn发生变化,表示客户端有消息发送过来了,此时rlist的值为[客户端]
          print(rlist)
      
          for r in rlist:
              print(r)
              conn, address = r.accept()
              conn.sendall(bytes("hello", encoding="utf-8"))
      
      • 客户端
      import socket
      
      sk = socket.socket()
      sk.connect(("127.0.0.1", 9999,))
      
      data = sk.recv(1024)
      print(data)
      
      while True:
          input(">>")
      
      sk.close()
      
    • select IO多路复用之监听客户端连接以及接收客户端发送的数据

      • 服务端
      import socket
      import select
      
      sk = socket.socket()
      sk.bind(("127.0.0.1", 9999,))
      sk.listen(5)
      
      
      inputs = [sk,]
      while True:
          rlist, w, e = select.select(inputs, [], [], 1)
          # 监听sk(服务器端)对象,如果sk对象发生变化,表示有客户端来连接了,此时rlist值为[sk]
          # 监听conn对象,如果conn发生变化,表示客户端有消息发送过来了,此时rlist的值为[客户端]
      
          print(len(inputs), len(rlist))
      
          for r in rlist:
              print(r)
              if r == sk:
                  # 有新的客户端连接进来
                  conn, address = r.accept()
                  inputs.append(conn)
                  conn.sendall(bytes("hello", encoding="utf-8"))
              else:
                  # 有客户端给我发送数据
                  recv_data = r.recv(1024)
                  print(recv_data)
               
      
      • 客户端
      import socket
      
      sk = socket.socket()
      sk.connect(("127.0.0.1", 9999,))
      
      data = sk.recv(1024)
      print(data)
      
      while True:
          inp = input(">>")
          sk.sendall(bytes(inp, encoding='utf-8'))
      
      sk.close()
      
      
    • select IO多路复用之读写分离

      • 服务端
      import socket
      import select
      
      sk = socket.socket()
      sk.bind(("127.0.0.1", 9999,))
      sk.listen(5)
      
      
      inputs = [sk,]
      outputs = []
      
      while True:
          rlist, wlist, e = select.select(inputs, outputs, [], 1)
          # 监听sk(服务器端)对象,如果sk对象发生变化,表示有客户端来连接了,此时rlist值为[sk]
          # 监听conn对象,如果conn发生变化,表示客户端有消息发送过来了,此时rlist的值为[客户端]
      
          print(len(inputs), len(rlist))
      
          for r in rlist:
              print(r)
              if r == sk:
                  # 有新的客户端连接进来
                  conn, address = r.accept()
                  inputs.append(conn)
                  conn.sendall(bytes("hello", encoding="utf-8"))
              else:
                  # 有客户端给我发送数据
                  try:
                      recv_data = r.recv(1024)
      
                      if not recv_data: # 某些操作系统,在socket断开的时候,会发送一个空给server,所以要判断空的情况
                          raise Exception("断开连接")
                      else:
                          outputs.append(r)
                  except Exception as e:
                      inputs.remove(r)
      
          for w in wlist:
              w.sendall(bytes("response", encoding="utf-8"))
              outputs.remove(w)
      
      • 客户端
      import socket
      
      sk = socket.socket()
      sk.connect(("127.0.0.1", 9999,))
      
      data = sk.recv(1024)
      print(data)
      
      while True:
          inp = input(">>")
          sk.sendall(bytes(inp, encoding='utf-8'))
          print(sk.recv(1024))
      sk.close()
      
    • select IO多路复用之读写分离 - 服务端根据客户端的输入返回对应的信息

      • 服务端
      import socket
      import select
      
      sk = socket.socket()
      sk.bind(("127.0.0.1", 9999,))
      sk.listen(5)
      
      
      inputs = [sk, ]  #
      outputs = []
      messages = {}   # 用来存放客户端发送过来的消息,存放格式   连接客户端的对象: 消息
      
      while True:
          rlist, wlist, elist = select.select(inputs, outputs, [sk, ], 1)
          # rlist  监听sk(服务器端)对象,如果sk对象发生变化,表示有客户端来连接了,此时rlist值为[sk]
          # wlist  监听conn对象,如果conn发生变化,表示客户端有消息发送过来了,此时rlist的值为[客户端]
          # elist  监听sk(服务器端)对象是否发生错误
      
          print(len(inputs), len(rlist))
      
          for r in rlist:
              print(r)
              if r == sk:
                  # 有新的客户端连接进来
                  conn, address = r.accept()
                  inputs.append(conn)
                  messages[conn] = []  # 在存储消息的字典中创建一个以客户端连接对象为key 空列表为value的键值对
                  conn.sendall(bytes("hello", encoding="utf-8"))
              else:
                  # 有客户端给我发送数据
                  try:
                      recv_data = r.recv(1024)
      
                      if not recv_data: # 某些操作系统,在socket断开的时候,会发送一个空给server,所以要判断空的情况
                          raise Exception("断开连接")
                      else:
                          outputs.append(r)
                          messages[r].append(recv_data)
      
                  except Exception as e:
                      inputs.remove(r)
                      del messages[r]
      
          for w in wlist:
              print(messages[w])
              msg = messages[w].pop()
              resp = msg + bytes("response", encoding="utf-8")
              w.sendall(resp)
              outputs.remove(w)
      
      
      • 客户端
      import socket
      
      sk = socket.socket()
      sk.connect(("127.0.0.1", 9999,))
      
      data = sk.recv(1024)
      print(data)
      
      while True:
          inp = input(">>")
          sk.sendall(bytes(inp, encoding='utf-8'))
          print(sk.recv(1024))
      sk.close()
      

    socketserver之源码剖析

    多线程和多进程

    多线程和多进程的定义

    • 一个应用程序,可以有多进程和多线程
    • 默认:单进程,单线程
    • 单进程,多线程
      • IO类型的操作,不占用CPU,使用多线程进行IO操作,提高并发
      • 计算类型的操作,需要CPU计算,使用多进程进行计算型密集的操作提高并发,可以利用上CPU多核的特性
    • GIL全局解释器锁,在java和c#中是不存在GIL的,多线程也可以达到并发

    多线程

    • 初识多线程

      • 当没有多线程的时候只能够像下面代码中的这种方式进行工作
      import time
      
      def renwu(renwu_id):
          time.sleep(1)
          print(renwu_id)
      
      if __name__ == '__main__':
          for i in range(10):
              renwu(i)
      
      • 使用多线程进行操作
      import time
      import threading
      
      def renwu(renwu_id):
          time.sleep(1)
          print(renwu_id)
      
      if __name__ == '__main__':
          for i in range(10):
              t = threading.Thread(target=renwu, args=[i,])
              t.start()
      
    • 多线程模块下面Thread类的一些方法

    getName()	# 获得当前线程对象的名称
    ident		# 返回一个非0的整数  线程标识符  未运行的返回值为空
    is_alive()	# 返回一个布尔值,判断线程的存活状态
    isDaemon()	# 返回一个布尔值,判断线程是否为后台程序
    join()			# 设置子线程为阻塞模式
    setDaemon(daemonic)	# 设置对象是否为后台程序,该方法需要在start方法之前,运行需要一个参数,传True或者False
    setName(name)		# 设置线程的名称	
    start()	# 执行线程,不代表当前线程会被立即执行,什么时候执行由cpu调度决定
    
    • 模块threading下面的一些函数
    threading.active_count()	# 返回当前存活的线程数量,等于threading.enumerate()返回列表的长度
    threading.current_thread()		# 返回当前主线程对象
    threading.enumerate()	# 返回一个列表,该列表包括当前处于存活状态的线程对象
    threading.get_ident()	# 返回一个非0的整数  线程标识符
    
  • 相关阅读:
    Spring_配置 Bean(2)
    Spring_HelloWorld
    搭建 Spring 开发环境
    MongoDB快速入门(十三)- 聚合count、distinct和group
    缓存技术,封装好的缓存类
    HTTP协议详解
    C# 缓存技术
    Web Service 的工作原理
    webview长按保存图片
    android Webview 实现js调用java代码实现Activity跳转
  • 原文地址:https://www.cnblogs.com/CongZhang/p/5658369.html
Copyright © 2011-2022 走看看