'''
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()