单线程、单进程非堵塞实现并发实现并发
什么时候会堵塞?
1.recv接受数据
2.accept等待客户到来时
如何实现非堵塞?
1.使用setblocking函数,将其值设置为False。
2.套接字使用此函数即可设置为非堵塞
实现非堵塞之后系统可能会报错?
大家想一下:
咱们现在已经把套接字设置为非堵塞,若客户端没有链接或者链接之后
还没发送消息,那么系统便会报错。
系统报错的原因:
正常情况下,不使用setblocking函数,系统解堵塞的时候是有客户端
链接,或者客户端发送过来数据。计算机根据有客户端链接,或者客
户端发送过来数据来解堵塞。因此咱们调用setblocking函数时可以理
解为不正常的解堵塞(强加的),此时若系统没有客户端链接便会报
错。
如何解决系统会报错的原因呢?
可以使用try来捕捉异常。咱们想要捕捉的异常是解堵塞之后没有客户
端到来。
大家看一下下面这段代码:
import socket
# 创建套接字
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定
tcp_socket.bind(("", 7890))
# 监听
tcp_socket.listen(1024)
while True:
try:
# 将套接字设置为非堵塞
tcp_socket.setblocking(False)
# 等待客户端的链接
new_socket,new_addr = tcp_socket.accept()
except Exception as ret:
print("客户端没有到来.")
else:
print("客户端已经链接")
recv_data = tcp_socket.recv(1024)
print(recv_data.decode("utf-8"))
那么问题又来了,假若A客户端链接完成之后,数据还没有发送完,这个
循环就退出了,那么就达不到服务端的目的。
接下来就涉及到一种非常重要的思想:
咱们可以在循环的外面定义一个列表,然后将链接上的客户端放到列表中,在对列表进行遍历,当客户端close或者不发送信息时咱们就可以将添加进来的这个套接字从列表中移除。下面是实现:
import socket
# 创建套接字
import time
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定
tcp_socket.bind(("", 7890))
# 监听
tcp_socket.listen(1024)
# 将套接字设置为非堵塞
tcp_socket.setblocking(False)
client_socket_list = list()
while True:
try:
# 等待客户端的链接
new_socket,new_addr = tcp_socket.accept()
except Exception as ret:
time.sleep(1)
print("客户端没有到来.")
else:
# 将套接字设置为非堵塞
tcp_socket.setblocking(False)
print("客户端已经链接")
client_socket_list.append(new_socket)
# recv_data = tcp_socket.recv(1024)
# print(recv_data.decode("utf-8"))
for i in client_socket_list:
try:
recv_data = i.recv(1024)
except Exception as ret:
print("这个客户端没有发送消息。")
else:
if recv_data:
print(recv_data.decode("utf-8"))
else:
new_socket.close()
client_socket_list.remove(new_socket)