'''
Created on 2019-10-16
SOCKETSERVER
ThreadedTCPServer:多线程接收客户端信息
@author: heidu004
'''
#!/usr/bin/python3
# -*-coding:utf-8 -*-
#BaseRequestHandlerclass
#StreamRequestHandler
from socketserver import TCPServer, StreamRequestHandler,ThreadingMixIn
import time
import threading
import ctypes
import inspect
ADDR = ('127.0.0.1', 1234)
BUFSIZ = 1024
__exitFlag__ = False
g_conn_pool = [] # 连接池
threadList = ["Thread-1", "Thread-2", "Thread-3"]
# 创建 StreamRequestHandler 类的子类
class MyRequestHandler(StreamRequestHandler):
def setup(self):
#self.request.sendall("连接服务器成功!".encode(encoding='utf8'))
# client_address 属性的值为客户端的主机端口元组
print('{}'.format(self.client_address)+'接入')#客户端地址
# 加入连接池
g_conn_pool.append(self.request)
# 重写 handle 方法,该方法在父类中什么都不做
# 当客户端主动连接服务器成功后,自动运行此方法
def handle(self):
while True:
try:
# request.recv 方法接收客户端发来的消息
data = self.request.recv(BUFSIZ)
if not data:
break
msg = time.strftime("%Y-%m-%d %X") #获取结构化事件戳
print("[%s][%s]>>%s" %(msg, self.client_address,data.decode('utf-8')))
#self.request.sendall("已接收到相关指令".encode(encoding='utf8'))
except Exception:
print("客户端已断开{}".format(self.client_address))
# 意外掉线
self.remove()
break
for con_pool in g_conn_pool:#向所有客户端转发
if con_pool != self.request:
con_pool.sendall('[{}][{}] {}'.format(time.strftime("%Y-%m-%d %X"),self.client_address, data.decode()).encode())
else:
con_pool.sendall('[{}] [以发送]'.format(time.strftime("%Y-%m-%d %X")).encode())
# request.sendall 方法发送消息给客户端
#self.request.sendall('[{}] {}'.format(time.ctime(), data.decode()).encode())
def finish(self):
print("清除了这个客户端。")
def remove(self):
print("有一个客户端掉线了。")
g_conn_pool.remove(self.request)
class ThreadedTCPServer(ThreadingMixIn, TCPServer):
pass
def _async_raise(tid, exctype):
"""引发异常,根据需要执行清理"""
tid = ctypes.c_long(tid)
if not inspect.isclass(exctype):
exctype = type(exctype)
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
if res == 0:
raise ValueError("无效的线程ID")
elif res != 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
raise SystemError("PyThreadState_SetAsyncExc 无效")
def stop_thread(thread):
_async_raise(thread.ident, SystemExit)
def main():
# 主线程逻辑
cmd=''
while True:
cmd = input('>>')
print(cmd)
if cmd == 'HELP':
print('输入COUNT:查看当前在线人数')
print('输入INPUT:给指定客户端发送消息')
print('输入CLOSE:关闭服务端')
elif cmd == 'COUNT':
print("--------------------------")
print("当前在线人数:", len(g_conn_pool))
elif cmd == 'INPUT':
if len(g_conn_pool) >0:
print("--------------------------")
index, msg = input("请输入“索引,消息”的形式:>>").split(",")
g_conn_pool[int(index)].sendall(msg.encode(encoding='utf8'))
else:
print('没有客户端连接')
elif cmd == 'INPUTS':
if len(g_conn_pool) >0:
print("--------------------------")
__exitFlag__=True
else:
print('没有客户端连接')
elif cmd == 'CLOSE':
server.shutdown()#关闭socket的功能
print("关闭socket的功能")
stop_thread(server_thread)#关闭关闭server_thread的功能
print("关闭关闭server_thread的功能")
print('程序已经关闭')
exit()
else:
print('输入正确指令查看HELP')
if __name__ == '__main__':
msg = time.strftime("%Y-%m-%d %X") #获取结构化事件戳
print('---------------------------------------------------------------------------')
print('| _____ &&&&_> > ')
print('| \/,---< &&&&&&\ \' 输入HELP:查看帮助 ')
print('| ( )c~c ~~@~@ )-- &&\ \' 输入COUNT:查看当前在线人数 ')
print('| C >/ \< |&/ 输入INPUT:给指定客户端发送消息 ')
print('| \_O/ - 哇塞 <<_ * - *_>> 输入CLOSE:关闭服务端 ')
print('| ,- >o<-. / ____ _/' )
print('| / \/ \ / /\ _) _)')
print('| / /| | |\ \ / / ) |')
print('| \ \| | |/ / \ \ / | [%s]'%(msg))
print('| \_\ | |_/ \ \_ | [%s]-缓存[%s]'%(ADDR,BUFSIZ))
print('| /_/`___|_\ /_/\____| ')
print('| | | | \ \| SOCKETSERVER_ThreadedTCPServer')
print('| | | | `. ) 2019-10-20')
print('| | | | / / heidu004')
print('| |__|_|_ /_/| 服务器永远等待客户端的连接')
print('| (____)_) |\_\_ ')
print('-----------------------------------------------------------------------------')
server = ThreadedTCPServer(ADDR, MyRequestHandler)
# 新开一个线程运行服务端
server_thread = threading.Thread(target=server.serve_forever)# 服务器永远等待客户端的连接
server_thread.daemon = True
server_thread.start()
main()