Python SockerServer Thread

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

    
    

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章