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的整数  线程标识符

posted on 2016-07-10 19:16  奋斗中的码农  阅读(490)  评论(0编辑  收藏  举报

导航