import threading
from socketserver import ThreadingTCPServer,BaseRequestHandler
import sys
import logging FORMAT = '%(asctime)s %(threadName)d %(thread)d %(message)s'
logging.basicConfig(level=logging.INFO,format=FORMAT) class ChatHandler(BaseRequestHandler): #一对一,相当于receive函数
clients = {} def setup(self):
self.event = threading.Event()
self.clients[self.client_address] = self.request
def finish(self):
self.clients.pop(self.client_address)
self.event.set() def handle(self):
print(self.request) #new_socket 用来recv
while not self.event.is_set():
data = self.request.recv(1024)
print(data,self.client_address)
msg = '{}.ack'.format(data).encode()
#如何实现一对多,多在哪里,如何获得
for c in self.clients.values():
c.send(msg)
addr = ('0.0.0.0',9999)
server = ThreadingTCPServer(addr,ChatHandler) #相当于tcp总的socket
print(server)
t = threading.Thread(target=server.serve_forever,name='chatserver')
t.start()
try:
while True:
cmd = input(">>>")
if cmd.strip() == 'quit':
break
except Exception as e:
print(e)
except KeyboardInterrupt:
pass
finally:
print('exit')
sys.exit(0)

类的继承关系

BaseServer------>TCPServer---------->UDPServer
| |
UnixStreamServer UnixDatagramServer
socketserver有四个同步类
TCPServer,UDPAServer,UnixStreamServer,UnixDatagramServer
2个mixin类,ForkingMixin,ThreadingMixin类用来支持异步 class ForkingUDPServer(ForkingMixin,UDPServer):pass
class ForkingTCPServer(ForkingMixin,TCPServer):pass
class ThreadingUDPServer(ThreadingMixin,UDPServer):pass
class ThreadingTCPServer(ThreadingMixin,TCPServer):pass
fork创建多进程,thread是创建多线程
BaseRequestHandler类
它是用户连接的用户请求处理类的基类,定义为BaseRequestHandler(request,client_address,server)
服务端server实例接收用户请求后,最后会实例化这个类
它被实例化时,送入3个构建参数,request,client,address,server自身
以后就可以在BaseRequestHandler类的实例上使用一下属性
self.request是和客户端连接的socket对象
self.server是tcpserver本身
self.client_address是客户端的地址 def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
self.server = server
self.setup()
try:
self.handle()
finally:
self.finish() def setup(self): 没一个连接初始化
pass def handle(self): 每一次请求处理
pass def finish(self): 每一个连接清理
pass  

官方文档例子

import socketserver

class MyHandler(socketserver.BaseRequestHandler):#相当于socket的recv方法
def handle(self):
print(self.request) #new_socket
print(self.client_address) #('127.0.0.1', 62685)
print(self.server) #<socketserver.ThreadingTCPServer object at 0x033CFA50> server = socketserver.ThreadingTCPServer(('0.0.0.0',9999),MyHandler)
print(server) #<socketserver.ThreadingTCPServer object at 0x033CFA50>
server.serve_forever()

实现群聊

import threading
from socketserver import ThreadingTCPServer,BaseRequestHandler
import sys
import logging FORMAT = '%(asctime)s %(threadName)d %(thread)d %(message)s'
logging.basicConfig(level=logging.INFO,format=FORMAT) class ChatHandler(BaseRequestHandler): #一对一,相当于receive函数
clients = {} def setup(self):
self.event = threading.Event()
self.clients[self.client_address] = self.request
def finish(self):
self.clients.pop(self.client_address)
self.event.set() def handle(self):
print(self.request) #new_socket 用来recv
while not self.event.is_set():
data = self.request.recv(1024)
print(data,self.client_address)
msg = '{}.ack'.format(data).encode()
#如何实现一对多,多在哪里,如何获得
for c in self.clients.values():
c.send(msg)
addr = ('0.0.0.0',9999)
server = ThreadingTCPServer(addr,ChatHandler) #相当于tcp总的socket
print(server)
t = threading.Thread(target=server.serve_forever,name='chatserver')
t.start()
try:
while True:
cmd = input(">>>")
if cmd.strip() == 'quit':
break
except Exception as e:
print(e)
except KeyboardInterrupt:
pass
finally:
print('exit')
sys.exit(0)
类的继承关系 BaseServer------>TCPServer---------->UDPServer
| |
UnixStreamServer UnixDatagramServer
socketserver有四个同步类
TCPServer,UDPAServer,UnixStreamServer,UnixDatagramServer
2个mixin类,ForkingMixin,ThreadingMixin类用来支持异步 class ForkingUDPServer(ForkingMixin,UDPServer):pass
class ForkingTCPServer(ForkingMixin,TCPServer):pass
class ThreadingUDPServer(ThreadingMixin,UDPServer):pass
class ThreadingTCPServer(ThreadingMixin,TCPServer):pass
fork创建多进程,thread是创建多线程
BaseRequestHandler类
它是用户连接的用户请求处理类的基类,定义为BaseRequestHandler(request,client_address,server)
服务端server实例接收用户请求后,最后会实例化这个类
它被实例化时,送入3个构建参数,request,client,address,server自身
以后就可以在BaseRequestHandler类的实例上使用一下属性
self.request是和客户端连接的socket对象
self.server是tcpserver本身
self.client_address是客户端的地址 def __init__(self, request, client_address, server):
self.request = request
self.client_address = client_address
self.server = server
self.setup()
try:
self.handle()
finally:
self.finish() def setup(self): 没一个连接初始化
pass def handle(self): 每一次请求处理
pass def finish(self): 每一个连接清理
pass  
官方文档例子 import socketserver class MyHandler(socketserver.BaseRequestHandler):#相当于socket的recv方法
def handle(self):
print(self.request) #new_socket
print(self.client_address) #('127.0.0.1', 62685)
print(self.server) #<socketserver.ThreadingTCPServer object at 0x033CFA50> server = socketserver.ThreadingTCPServer(('0.0.0.0',9999),MyHandler)
print(server) #<socketserver.ThreadingTCPServer object at 0x033CFA50>
server.serve_forever()
利用socketserver实现群聊 import threading
import socketserver
from socketserver import ThreadingTCPServer,BaseRequestHandler
import sys
import logging FORMAT = '%(asctime)s %(threadName)s %(thread)d %(message)s'
logging.basicConfig(level=logging.INFO,format=FORMAT) class ChatHandler(BaseRequestHandler): #当服务端接收到新的请求后,baserequestHandler新类就会实例化 并一次执行setup ,try handle,finally finish
clients = {}
def setup(self):
self.event = threading.Event()
self.clients[self.client_address] = self.request def finish(self):
self.clients.pop(self.client_address)
self.event.set() def handle(self):#相当于socket的recv方法,每个不同的连接上请求过来后,生成连接的socket对象
#就是self.request,客户端地址self.client.address
while not self.event.is_set():
data = self.request.recv(1024).decode()
if data =='quit':
break
msg = "{} {}".format(self.client_address,data).encode()
logging.info(msg)
for c in self.clients.values():
self.request.send(msg)
print('END')
addr = ('0.0.0.0',9999)
server = socketserver.ThreadingTCPServer(addr,ChatHandler) #baseserver源码serve_forever函数有try...finally关闭连接
server_thread = threading.Thread(target=server.serve_forever,name='ChatServer',daemon=True).start() try:
while True:
cmd = input("please set a exit code >>>")
if cmd.strip() == 'quit':
break
except Exception as e:
print(e)
except KeyboardInterrupt:
sys.exit(0
"""
通过打印可以看出,客户端主动断开连接,会导致revc方法立即返回一个空bytes,并没有同时抛出异常
当循环回到recv这一句话会抛出异常,所以通过判断data数据是否为空来判断客户端是否断开 """
def handle(self):
while not self.event.is_set():
data = self.request.recv(1024)
if not data or data =='quit':
break """
总结:
为每一个连接提供RequestHandlerClass类实例,依次调用setup,handle,finish方法,并且使用
try。。。finally结构保证finish方法一定被调用,这些方法一次执行完成,如果想维持这个连接和客户端通信
就需要在handler中循环使用 """

Python之socketserver的更多相关文章

  1. python利用socketserver实现并发套接字功能

    本文实现利用python的socketserver这个强大的模块实现套接字的并发 目录结构如下: 测试文件请放在server_file文件夹里面 server.py #!/usr/bin/env py ...

  2. python之socketserver实现并发

    python之socketserver实现并发 服务端 import socketserver #socketserver模块是用来实现并发 # 我们自己的类里一定要继承socketserver.Ba ...

  3. python 从SocketServer到 WSGIServer 源码分析、

    python 下有个wsgi的封装库.wsgiref. WSGI 指的是 Web服务器网关接口(Python Web Server Gateway Interface) django的runserve ...

  4. 浅析python中socketserver模块使用

    虽然说用python编写简单的网络程序狠方便,但是复杂一点的网络程序还是用现成的框架比较好,这样就可以专心事物逻辑,而不是套接字的各种细节.Socketserver模块简化了编写网络服务程序,同时so ...

  5. Python基础-socketserver

    ocketserver通讯模块实现并发操作,基于select.epoll.socket.多线程,实现的正真多线程多并发 socketserver通讯模块底层调用的socket模块,只是它作了处理基于l ...

  6. python 并发socketserver模块

    1.源码class 1.server类:处理链接 +------------+ | BaseServer | +------------+ | v +-----------+ +----------- ...

  7. python之SocketServer编程

    编写一个SocketServer需要实现以下步骤 编写一个handler类,继承BaseRequestHandler,重写handle()方法 针对是TCP还是UDP,生成一个server对象 调用s ...

  8. Python使用socketServer包搭建简易服务器过程详解

    官方提供了socketserver包去方便我们快速的搭建一个服务器框架. 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做案例的 ...

  9. Python之socketserver源码分析

    一.socketserver简介 socketserver是一个创建服务器的框架,封装了许多功能用来处理来自客户端的请求,简化了自己写服务端代码.比如说对于基本的套接字服务器(socket-based ...

  10. 解读python中SocketServer源码

    在看SocketServer源码之前,先看一个例子: class Base(object): def __init__(self, name): self.name = name self.Testf ...

随机推荐

  1. LOJ.6160.[美团CodeM初赛 RoundA]二分图染色(容斥 组合)

    题目链接 \(Description\) 求在\(2n\)个点的完全二分图(两边各有\(n\)个点)上确定两组匹配,使得两个匹配没有交集的方案数. \(n\leq10^7\). \(Solution\ ...

  2. HTML入门5

    格式化文本,高阶处理,接下来了解,标记引文,描述列表,计算机代码和其他文本,上下标,联系信息等数据. 学习不太知名的HTML元素来标记高级语义特征. 描述列表,也叫自定义列表,第三种类型的列表,除了u ...

  3. centos7下NFS使用与配置

    NFS是Network File System的缩写,即网络文件系统.客户端通过挂载的方式将NFS服务器端共享的数据目录挂载到本地目录下. nfs为什么需要RPC?因为NFS支持的功能很多,不同功能会 ...

  4. vim编辑器显示行号

    Vim编辑器显示行号的设置 1. 显示行号 :set nu 2. 不显示行号 :set nonu :set nu :set nonu

  5. Python学习小纪

    1.打包发布*.py文件---"文件路径下打开命令行 d:\python\python.exe setup.py sdist" eg:打包发布f:\C\python\print_l ...

  6. C++标准库algorithm

    (1) 基本数学相关: max(t1, t2)和min(t1, t2), 返回t1和t2中的较大.较小者. max_element(b, e)和min_element(b, e), 返回两个迭代器所指 ...

  7. kettle 通用的数据库迁移流程

    需求: 1.你是否遇到了需要将mysql数据库中的所有表与数据迁移到Oracle. 2.你是否还在使用kettle重复的画着:表输入-表输出.创建表,而烦恼. 下面为你实现了一套通用的数据库迁移流程. ...

  8. 树莓派与Linux系统之间文件传输

    最近因为要学习Python,于是把放在家里接了一年灰的树莓派又给搜出来了,刚买那会也捣鼓了好一阵子, 基本操作都学会了,但现在又忘光了,只能又从头开始搞了,首先第一个要解决的是怎么把文件从电脑传输到树 ...

  9. 如何把原生小程序项目合并的mpvue项目中

    当时的情景是这样的: 使用mpvue写微信小程序,写着写着项目写到一半了,突然间不想这样继续写了,想切换回原生小程序语法去写剩余部分. 如下图,红色框里的功能是已经用mpvue完成的功能,绿色框部分的 ...

  10. B-Tree与B+Tree简明扼要的区别

    原文:https://blog.csdn.net/zhuanzhe117/article/details/78039692 看了很多讲B树和B+树的文章,大多都是围绕各自的特性讲的,第一,树中每个结点 ...