1、背景
socket 服务端一直不停的接收客户端连接,当服务端停止时做一些处理操作,比如从数据表中删除某些数据。
如下代码:
import socket
class SocketServer:
def __init__(self, host, port):
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_address = (host, port)
self.server_socket.bind(self.server_address)
self.server_socket.listen(5)
def handle_client(self, client_socket):
pass
def delete_handler(self):
print("Deleting data")
def start_server(self):
try:
while True:
client_socket, client_address = self.server_socket.accept()
self.handle_client(client_socket)
except KeyboardInterrupt:
print('Server shutting down.')
finally:
self.server_socket.close()
self.delete_handler() # 服务端关闭后的处理操作
if __name__ == '__main__':
server = SocketServer('0.0.0.0', 9999)
server.start_server()
情况:
- cmd窗口运行时,按ctrl + c捕捉不到KeyboardInterrupt错误。
- pycharm运行关闭时也捕捉不到KeyboardInterrupt错误。
2、解决办法1:signal信号机制+threading.Event()(不行)
- 设置个全局的事件机制
- 设置信号捕捉ctrl+c
- 捕捉到后evnet.set()
- 事件默认false,set()后为True
- while True 改成while not self.stop_event.is_set()
代码示例:
import socket
import threading
import signal
class SocketServer:
def __init__(self, host, port):
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_address = (host, port)
self.server_socket.bind(self.server_address)
self.server_socket.listen(5)
self.stop_event = threading.Event()
# 设置信号处理程序,捕获 Ctrl+C
signal.signal(signal.SIGINT, self.handle_interrupt)
def handle_client(self, client_socket):
pass
def delete_handler(self):
print("Deleting data")
def handle_interrupt(self):
# 捕获 Ctrl+C 信号,设置停止事件
self.stop_event.set()
def start_server(self):
try:
while not self.stop_event.is_set():
client_socket, client_address = self.server_socket.accept()
self.handle_client(client_socket)
except KeyboardInterrupt:
print('Server shutting down.')
finally:
self.server_socket.close()
self.delete_handler() # 服务端关闭后的处理操作
if __name__ == '__main__':
server = SocketServer('0.0.0.0', 9999)
server.start_server()
结果:不行,因为accept已经阻塞住了,一直卡在当前循环,无法进行下一次循环判断。除非接受一条客户段连接,到下次循环之间,恰好按了ctrl+c,这样可以判断到。当然这种实际也是行不通的。
3、解决办法2:单独的线程等待连接(成功)
使用一个单独的线程来等待连接,并在主线程中捕获信号以触发关闭操作。
import socket
import threading
import time
class SocketServer:
def __init__(self, host, port):
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server_address = (host, port)
self.server_socket.bind(self.server_address)
self.server_socket.listen(5)
self.stop_event = threading.Event()
def handle_client(self, client_socket):
pass
def delete_handler(self):
print("Deleting data")
def accept_connections(self):
try:
while True:
client_socket, client_address = self.server_socket.accept()
client_thread = threading.Thread(target=self.handle_client,
args=(client_socket,))
client_thread.start()
except Exception as e:
print(f'Server error: {e}')
def start_server(self):
accept_thread = threading.Thread(target=self.accept_connections, args=())
accept_thread.start()
try:
# 主程序逻辑
while True:
time.sleep(1) # 主线程的其他操作
except KeyboardInterrupt:
# 捕获 Ctrl+C
print('Server shutting down.')
finally:
self.server_socket.close()
self.delete_handler() # 服务端关闭后的处理操作
if __name__ == '__main__':
server = SocketServer('0.0.0.0', 9999)
server.start_server()
实际情况:
- cmd运行,按ctrl+c后会捕捉到KeyboardInterrupt异常,因此finally里的服务端关闭后的处理操作也会执行。但是命令行还会有输出,应是多线程的问题,还需要点击X号关闭程序。
- pycharm中运行,关闭时会捕捉到KeyboardInterrupt异常,因此finally里的服务端关闭后的处理操作也会执行。
评论列表,共 0 条评论
暂无评论