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

    
    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

马铃薯_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值