非阻塞socket与io多路复用(没整理好)

同步阻塞io

- io就是input,output,即输入和输出,读和写
	接收数据为input,发送数据为output
	读文件为input,写文件为output
- 同步阻塞:用户发起read请求,系统内核会去获取数据,在数据到达前,你的read线程会一直等在这个地方,不能做任何事情,直到数据到达,然后拷贝进用户缓冲区,read才完成,才继续往下执行
- 默认的套接字就是同步阻塞的	

同步非阻塞io

1. 用户发起read请求,如果内核的数据没有到达,立刻返回,然后不断循环的去发起read请求,直到有数据就读取数据		
	用户线程每次请求io都可以立刻返回,但是为了拿到数据,需要不断轮询,无谓的消耗了大量的CPU
	一般很少直接使用这种模型,但是在其他io模型中使用非阻塞io这一特性
2. 非阻塞套接字
	1. 设置非阻塞
		setblocking(False)
	2. accept,recv
		阻塞方法不阻塞,没有连接,没有数据会引发blockingioerror,所以需要用异常来捕获
3. 同步非阻塞socket实现并发
4. io多路复用	

非阻塞socket实现并发

1.思路:
	外循环用来不断的accept,接收连接,用一个列表来保存所有建立的对等socket,并设置为非阻塞
	内循环用来循环这个保存对等socket是否有数据传入
	# 非阻塞套接字实现并发
	import socket
	server = socket.socket()
	server.setblocking(False)   #设置非阻塞
	server.bind(("",6969))
	server.listen(10)
	client_list = []    #存放连接进来的客户端
	#设置一个大循环,不断地接收用户的请求
	while True:
	    #接收请求
	    try:
	        conn,addr = server.accept()     #没有连接他会引发blockingioerror异常
	        conn.setblocking(False) # 设置这个对等连接为非阻塞
	        client_list.append((conn,addr))
	        print("连接:{}".format(addr))
	    except BlockingIOError:
	        pass
	    #处理请求
	    for client,addr in client_list:
	        try:
	            recv_data = client.recv(1024)   #收数据
	            if recv_data:
	                print("接收来自:{}>>>{}".format(
	                    addr,recv_data.decode("utf-8")
	                ))
	                client.send(recv_data)  #发送数据
	            else:
	                client_list.remove((client,addr))   #从列表中删除
	                client.close()
	                print("断开连接:{}".format(addr))		                
	        except BlockingIOError:
	            pass

io多路复用

- epoll是inux系统下最快的技术,大部分服务器都采用epoll
- windows下没有epoll,Windows有select 
- 是事件驱动io
使用步骤:
	1. 创建epoll
	2. 创建回调函数
	3. 注册socket
	4. 循环监听
		# 通过epoll实现io多路复用实现并发的服务器
		import socket
		import selectors
		server = socket.socket()
		 #设置非阻塞和阻塞无所谓
		server.bind(("",6969))
		server.listen(1000)			
		def recv(soc):
		    data = soc.recv(1024)
		    if data:
		        soc.send(data)
		    else:
		        #删除注册
		        epoll_selector.unregister(soc)
		        soc.close()			
		def accept(soc):
		    #接收请求
		    conn,addr = soc.accept()
		    #把对等连接注册到epoll监视器
		    epoll_selector.register(
		        conn,
		        selectors.EVENT_READ,
		        recv
		    )
		#创建一个epoll监视器
		epoll_selector = selectors.DefaultSelector()  # 根据操作系统自行选择
		#注册服务端server
		epoll_selector.register(
		    server,     #主服务的socket
		    selectors.EVENT_READ,   #事件类型
		    accept  #回调函数
		)			
		#循环监听
		while True:
		    events = epoll_selector.select()     #epoll_select是阻塞的
		    # events就是所有的被触发了的事件
		    for key,mark in events:
		        sock = key.fileobj  #socket对象
		        callback = key.data
		        #执行回调函数
		        callback(sock)

多人聊天客户端
import socket
server = socket.socket()
server.setblocking(False) #设置非阻塞
server.bind("",6969)
server.listen(5)
clients = [ ] 存放连接进来的客户端
while True:
#循环接收客户端
try:
conn,addr = server.accept()
conn.setblocking(False) #设置这个对等连接为非阻塞
clients.append((conn,addr))
except Exception:
pass
#循环处理对等连接
for client,addr in clients:
#收数据
try:
recv_data = client.recv(1024)
if recv_data:
#给所有的人发一份
data = “receive {} from {}”.format(
recv_data.decode(“utf-8”),
addr
)
for c,a in clients:
c.send(recv_data)
else:
clients.remove((client,addr))
client.close()
except Exception:
pass

#发送端
import socket
client = socket.socket()
client.connect((“127.0.0.1”,6969))
while True:
data = input(">>>")
if data = “q”:
break
client.send(dta.encode)
client.close()

#接收端
import socket
client = socket.socket()
client.connect((“127.0.0.1”,6969))
while True:
res = client.recv(1024)
print(res.decode(“utf-8”))

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值