- 之前在使用socket进行数据收发的时候,进程(线程)会堵塞在accept,recv等方法,而使用非堵塞方式则会解决这类问题。下面是一个简单的非堵塞socket实例。
server端:
import socket
so = socket.socket()
so.bind(("127.0.0.1", 9999))
so.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
so.setblocking(False) # 设置为非堵塞IO
so.listen()
while True:
try:
conn, addr = so.accept()
print(addr)
mes = conn.recv(1024)
print(mes.decode("UTF-8"))
except BlockingIOError:
pass
conn.close()
so.close()
client端:
import socket
so = socket.socket()
so.connect(("127.0.0.1", 9999))
so.send(b"hello")
so.close()
- setblocking(False)是设置非堵塞IO的方法,不设置时,默认为True,当设置了这个参数为False,再调用会导致堵塞的函数则不会堵塞一直顺序执行代码,这样会导致下面的代码出现错误,这时就要使用try来捕获异常进行处理。
下面的例子展示了使用非阻塞IO进行socket聊天:
import socket
so = socket.socket()
so.bind(("127.0.0.1", 9999))
so.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
so.setblocking(False) # 设置为非堵塞IO
so.listen()
conn_list = []
del_conn_list = []
while True:
try: # 所有的堵塞操作都要有异常处理
conn, addr = so.accept()
print(addr, "已经连接了")
conn_list.append(conn)
except BlockingIOError:
for conn in conn_list:
try: # 所有的堵塞操作都要有异常处理
mes = conn.recv(1024)
if mes == b"": # 连接断开会发送空字符
# conn_list.remove(conn) # 不能从列表删除该连接,会导致列表索引混乱
del_conn_list.append(conn)
continue
print("收到%s的消息:%s" % (conn.getsockname(), mes.decode("UTF-8")))
print("连接列表长度", len(conn_list))
except Exception:
pass
for conn in del_conn_list: # 这里注意,是遍历要删除列表中的项
conn.close() # 在这里需要Close掉连接,因为对面已经断开了
conn_list.remove(conn)
del_conn_list.clear()
conn.close()
so.close()
- while True 会导致CPU利用率快速上升还,这是非阻塞IO的一大弊端。
网友评论