事件驱动
- 有一个事件(消息)队列;
- 鼠标按下时,往这个队列中增加一个点击事件(消息);
- 有个循环,不断从队列取出事件,根据不同的事件,调用不同的函数,如onClick()、onKeyDown()等;
- 事件(消息)一般都各自保存各自的处理函数指针,指向各自的处理函数;
IO多路
当进程进入堵塞状态时,是不占用CPU资源的
blocking IO,一般调用 socket 默认都是堵塞 IO,也就是当 socket 对象 recv 时,如果 recv 不到数据就会一直在堵塞,等待数据到来才进行下一步。
例子:打电话,直等到特定的人来接听才走下一步。
non-blocking IO,设定 sk.setblocking(False),可以设定为非堵塞IO模式,当 recv 不到数据时,立即返回一个错误,错误用 except 去捕捉,这段时间可以让 CPU 执行别的程序,一段时间后再回去 recv ,不断重复,非堵塞 IO 会发起比较多的系统调用,响应延迟增大了,不能立即返回去处理。
例子:打电话,找不到人就隔一段时间再打,一直打到特定的人来听电话。
IO multiplexing , IO 多路复用,用select ,epoll,好处是能同时处理多个连接,但不实用与单个连接。
例子:想不到例子了······
Asynchronous IO ,异步IO, 全程无堵塞的执行程序,等待系统内核通知程序已经完成,直接来取数据就行了。
例子:还是打电话,通知那边的人,叫他那个人到了就通知我,我再来打电话。
多路复用,还分为水平触发和边缘触发。
select 属于水平触发,
我在使用 selectors 模块是时一直报错
报错:[WinError 10035] 无法立即完成一个非阻止性套接字操作。
下面是我的代码
# server 端
import selectors
import socket
import json
import time
class Mytest:
def __init__(self):
self.keep = 1
self.creat_socket()
self.work()
def work(self):
print('wait for connect')
while True:
events = self.sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj, mask)
def creat_socket(self):
self.sel = selectors.DefaultSelector()
self.sock = socket.socket()
self.sock.bind(('localhost', 8889))
self.sock.listen(100)
# self.sock.setblocking(False)
self.sel.register(self.sock,selectors.EVENT_READ,self.accept)
def accept(self, sock, mask):
self.conn, self.addr = sock.accept() # Should be ready
print('accepted', self.conn, 'from', self.addr)
self.conn.setblocking(False)
self.sel.register(self.conn, selectors.EVENT_READ, self.read)
def read(self, conn, mask):
# try:
data = conn.recv(1024)
if self.keep == 2:
func = getattr(self, 'put')
func(conn,data)
else:
print('echoing', repr(data), 'to', conn)
data = data.decode('utf-8').split()
if len(data) == 2 :
if hasattr(self, data[0]):
func = getattr(self, data[0])
func(conn,data)
else:
conn.send('please input again'.encode('utf-8'))
# except Exception as e:
# print(e)
# print('closing', conn)
# self.sel.unregister(conn)
# conn.close()
def put(self, conn, data):
# 上传
if self.keep == 1:
print('put', data)
self.data_dic = {
'action' : 'put',
'file_name' : data[1]
}
data = json.dumps(self.data_dic)
conn.send(data.encode('utf-8'))
time.sleep(0.1)
self.file_size = int(conn.recv(1000).decode('utf-8'))
print('file_size = ', self.file_size)
print('file_name = ', self.data_dic['file_name'])
send_size = 0
f = open(self.data_dic['file_name'], 'wb')
time.sleep(3)
test = self.conn.recv(1024)
f.write(test)
self.send_size = send_size + len(test)
f.close()
self.keep = 2
print('put first end')
else:
f = open(self.data_dic['file_name'], 'ab')
f.write(data)
self.send_size = self.send_size + len(data)
f.close()
if self.send_size == self.file_size:
print('put successful')
self.keep = 1
def get(self, conn, data):
# 下载
print('get', data)
conn.send('get has none'.encode('utf-8'))
test = Mytest()
# client 端
import socket
import os
import json
import time
import sys
path = os.path.dirname(os.path.abspath(__file__))
class Myclient:
def __init__(self):
self.creat_connect()
self.work()
def creat_connect(self):
self.sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.sk.connect(('127.0.0.1',8889))
def work(self):
print('connecting to server')
while True:
inputs = input('>>>')
self.sk.send(inputs.encode('utf-8'))
data = self.sk.recv(1024).decode('utf-8')
if hasattr(self, inputs.split()[0]):
func = getattr(self, inputs.split()[0])
func(data)
else:
print(data)
def put(self, data):
# 上传
data = json.loads(data)
print('put', data)
paths = os.path.join(path, data['file_name'])
if os.path.exists(paths):
file_size = os.stat(paths).st_size
print('exist , file_size = ', file_size)
self.sk.send(str(file_size).encode('utf-8'))
time.sleep(2)
send_size = 0
f = open(data['file_name'], 'rb')
while send_size < file_size:
test = f.read(1024)
self.sk.send(test)
send_size = send_size + len(test)
f.close()
print('put end')
else:
print('file %s not exist' %data['file_name'])
def get(self, data):
# 下载
print('get', data)
client = Myclient()
因为之前设定的是非堵塞IO, 出现这个问题后我就把 self.sock.setblocking(False) 注释了,但是还是出现这个问题,之后我发现报错的代码是 当 conn 去 recv 时没有数据,就立即报错,但是我在这句之前加了延时,就不会报这个错误了。
还要注意避免两次 socket 的 send 数据粘包情况,这次写的不好,有些问题没有解决,例如不能多个人同时上传文件,应该是有些参数设定得不好。
最近这几天挺多事的,没有静下来学,拖慢进度了。。。真是抱歉
Python这个语言基本就学到这里了,剩下的得靠自己
可以看袁老师的:https://www.cnblogs.com/yuanchenqi/articles/5722574.html
网友评论