Python socket模块学习
socket模块学习
非阻塞模式
socket的默认情况下是阻塞模式:socket.accept()方法在没有接受到连接之前不能处理已经建立连接的其他操作,以及在recv()方法或者其他接受数据的方法时候都是阻塞的,如果没有接受到数据就会一直处于阻塞状态,来等待接受数据,这种情况只有通过开启新的进程或者线程来解决来自不同客户端的连接请求或者接受数据;socket可以支持非阻塞的模式;可以使用以下两种方法来设置socket的非阻塞模式:
# 设置套接字为阻塞或非阻塞模式:如果 flag 为 false,则将套接字设置为非阻塞,否则设置为阻塞。
# socket.setblocking(flag)
# 如果value赋为 0,则套接字将处于非阻塞模式。如果指定为 None,则套接字将处于阻塞模式。
# socket.settimeout(value)
# 阻塞
sock.setblocking(True)
sock.settimeout(None)
# 非阻塞
sock.setblocking(False)
sock.settimeout(0.0)
在非阻塞模式下可以实现在单线程模式下实现与多个客户端连接的交互:
非阻塞模式的服务端:
# demo_socket_server_2.py文件
import logging
import socket
logging.basicConfig(level=logging.DEBUG,
format="%(asctime)s>%(message)s", datefmt="%Y-%m-%d %H:%M:%S")
logger = logging.getLogger(__name__)
class ServerClass(object):
"""docstring for ServerClass"""
def __init__(self):
self.__HOST = "127.0.0.1"
self.__PORT = 9999
self.ADDR = (self.__HOST, self.__PORT)
self.__TCP_SOCKET = socket.socket(
family=socket.AF_INET, type=socket.SOCK_STREAM)
# 设置非阻塞
# self.__TCP_SOCKET.setblocking(False)
self.__TCP_SOCKET.settimeout(0.0)
# 用来存放套接字对象的列表
self.connlist = list()
def start_server(self):
with self.__TCP_SOCKET as sock:
sock.bind(self.ADDR)
sock.listen()
logger.info("Server is Running")
while True:
try:
conn, addr = sock.accept()
# logger.info(conn)
# 将连接的套接字对象设置为非阻塞
conn.setblocking(False)
msg = f"Hi,{
addr}"
self.send_data(conn, msg)
# 添加到列表
self.connlist.append(conn)
# 如果没有连接进来需要捕获BlockingIOError异常
except BlockingIOError as e:
pass
# logger.debug("没有新的客户端连接")
# 循环套接字对象列表 进行收发数据
for conn in self.connlist:
msg = self.recv_data(conn)
self.send_data(conn, msg)
def recv_data(self, conn):
"""接收数据"""
try:
msg = conn.recv(1024).decode("utf-8")
if not msg or msg in ["quit"]:
logger.debug("断开连接")
# 将套接字对象从列表移除
self.connlist.remove(conn)
else:
logger.info(msg)
return msg
except IOError as e:
pass
# logger.debug("没有接收到数据")
def send_data(self, conn, msg):
"""发送数据"""
if msg:
msg =