Socket网络编程-SocketServer
Socket网络编程-SocketServer
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.SocketServer概述
socket编程过于底层,编程虽然有套路,但是想要写出健壮的代码还是比较困难的,所以很多语言都对 socket底层API进行封装,Python的封装就是socketserver模块。它是网络服务编程框架,便于企业级 快速开发。 类的继承关系如下所示:
+------------+
| BaseServer |
+------------+
|
|
v
+-----------+ +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+ +--------------------+
v
+-----------+
+------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+ +------------------+ SocketServer简化了网络服务器的编写。 它有4个同步类:
TCPServer
UDPServer
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是创建多线程。 fork需要操作系统支持,Windows不支持。
二.编程接口
1>.创建服务器需要几个步骤
从BaseRequestHandler类派生出子类,并覆盖其handle()方法来创建请求处理程序类,此方法将 处理传入请求
实例化一个服务器类,传参服务器的地址和请求处理类
调用服务器实例的handle_request()或serve_forever()方法
调用server_close()关闭套接字
2>.案例展示
#!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import threading
import socketserver
import logging FORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s"
logging.basicConfig(format=FORMAT, level=logging.INFO) """
BaseRequestHandler:
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() 参数说明:
它是和用户连接的用户请求处理类的基类
服务端Server实例接收用户请求后,最后会实例化这个类。
它被初始化时,送入3个构造参数:request, client_address, server自身
以后就可以在BaseRequestHandler类的实例上使用以下属性:
self.request是和客户端的连接的socket对象
self.server是TCPServer实例本身
self.client_address是客户端地址
这个类在初始化的时候,它会依次调用3个方法。子类可以覆盖这些方法。
"""
class MyHandler(socketserver.BaseRequestHandler):
def handle(self):
# super().handle() #可以不调用,父类handle什么都没有做
print('-'*30)
print(self.server) #服务
print(self.request) #服务端负责客户端连接请求的socket对象
print(self.client_address) #客户端地址
print(self.__dict__)
print(self.server.__dict__) #能看到负责accept的socket
print(threading.enumerate())
print(threading.current_thread())
print('-'*30)
for i in range(3):
data = self.request.recv(1024)
logging.info(data)
logging.info('====end====') addr = ('172.30.1.2', 9999) """
将ThreadingTCPServer换成TCPServer,同时连接2个客户端观察效果。 ThreadingTCPServer是异步的,可以同时处理多个连接。
TCPServer是同步的,一个连接处理完了,即一个连接的handle方法执行完了,才能处理另一个连接, 且只有主线程。
"""
server = socketserver.ThreadingTCPServer(addr, MyHandler) #注意参数是MyHandler类
server.serve_forever() #永久循环执行
三.实现EchoServer(顾名思义,Echo,来什么消息回显什么消息 客户端发来什么信息,返回什么信息)
#!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import threading
import socketserver class Handler(socketserver.BaseRequestHandler):
def setup(self):
super().setup()
self.event = threading.Event() def finish(self):
super().finish()
self.event.set() def handle(self):
super().handle()
print('-' * 30)
while not self.event.is_set():
data = self.request.recv(1024).decode()
print(data)
msg = '{} {}'.format(self.client_address, data).encode()
self.request.send(msg) server = socketserver.ThreadingTCPServer(('172.30.1.2', 9999), Handler)
print(server)
threading.Thread(target=server.serve_forever, name='EchoServer', daemon=True).start() while True:
cmd = input('>>')
if cmd == 'quit':
server.server_close()
break
print(threading.enumerate())
四.实战—改写ChatServer
#!/usr/bin/env python
#_*_conding:utf-8_*_
#@author :yinzhengjie
#blog:http://www.cnblogs.com/yinzhengjie import datetime
import threading
from socketserver import ThreadingTCPServer, StreamRequestHandler
import logging FORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s"
logging.basicConfig(format=FORMAT, level=logging.INFO) """
注意:此程序线程不安全
"""
class ChatHandler(StreamRequestHandler):
clients = {} def setup(self):
super().setup()
self.event = threading.Event()
self.clients[self.client_address] = self.wfile def handle(self):
super().handle()
# for k,v in self.__dict__.items():
# print(k, type(v), v) while not self.event.is_set():
data = self.rfile.read1(1024) # 可以读取到数据
data = data.decode().rstrip()
print(data, '~~~~~~~~~~~~~') if data == 'quit' or data == '': # 主动退出和断开
break msg = '{} {}:{} {}'.format(datetime.datetime.now(), *self.client_address,data) for f in self.clients.values():
f.write(msg.encode())
f.flush() def finish(self):
self.clients.pop(self.client_address)
super().finish()
self.event.set() server = ThreadingTCPServer(('172.30.1.2', 9999), ChatHandler)
server.daemon_threads = True # 让所有启动线程都为daemon threading.Thread(target=server.serve_forever, name='chatserver', daemon=True).start() while True:
cmd = input('>>')
if cmd.strip() == 'quit':
server.server_close()
break
print(threading.enumerate())
五.总结
为每一个连接提供RequestHandlerClass类实例,依次调用setup、handle、finish方法,且使用了try...finally结构保证finish方法一定能被调用。这些方法依次执行完成,如果想维持这个连接和客户端 通信,就需要在handle函数中使用循环。
socketserver模块提供的不同的类,但是编程接口是一样的,即使是多进程、多线程的类也是一样,大 大减少了编程的难度。 将socket编程简化,只需要程序员关注数据处理本身,实现Handler类就行了。这种风格在Python十分常见。
Socket网络编程-SocketServer的更多相关文章
- python基础(15)-socket网络编程&socketserver
socket 参数及方法说明 初始化参数 sk = socket.socket(参数1,参数2,参数3) 参数1:地址簇 socket.AF_INET IPv4(默认) socket.AF_INET6 ...
- Day09: socket网络编程-OSI七层协议,tcp/udp套接字,tcp粘包问题,socketserver
今日内容:socket网络编程 1.OSI七层协议 2.基于tcp协议的套接字通信 3.模拟ssh远程执行命令 4.tcp的粘包问题及解决方案 5.基于udp协议的套接字 ...
- Python全栈【Socket网络编程】
Python全栈[socket网络编程] 本章内容: Socket 基于TCP的套接字 基于UDP的套接字 TCP粘包 SocketServer 模块(ThreadingTCPServer源码剖析) ...
- python之Socket网络编程
什么是网络? 网络是由节点和连线构成,表示诸多对象及其相互联系.在数学上,网络是一种图,一般认为专指加权图.网络除了数学定义外,还有具体的物理含义,即网络是从某种相同类型的实际问题中抽象出来的模型.在 ...
- Python之路【第七篇】python基础 之socket网络编程
本篇文章大部分借鉴 http://www.cnblogs.com/nulige/p/6235531.html python socket 网络编程 一.服务端和客户端 BS架构 (腾讯通软件:ser ...
- 循序渐进Socket网络编程(多客户端、信息共享、文件传输)
循序渐进Socket网络编程(多客户端.信息共享.文件传输) 前言:在最近一个即将结束的项目中使用到了Socket编程,用于调用另一系统进行处理并返回数据.故把Socket的基础知识总结梳理一遍. 1 ...
- Py西游攻关之Socket网络编程
新闻 管理 Py西游攻关之Socket网络编程 知识预览 计算机网络 回到顶部 网络通信要素: A:IP地址 (1) 用来标识网络上一台独立的主机 (2) IP地址 = 网络地址 + 主机 ...
- Python面向对象进阶和socket网络编程-day08
写在前面 上课第八天,打卡: 为什么坚持?想一想当初: 一.面向对象进阶 - 1.反射补充 - 通过字符串去操作一个对象的属性,称之为反射: - 示例1: class Chinese: def __i ...
- Python之旅Day8 socket网络编程
socket网络编程 Socket是网络编程的一个抽象概念.通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可.soc ...
随机推荐
- K8s集群认证之RBAC
kubernetes认证,授权概括总结: RBAC简明总结摘要:API Server认证授权过程: subject(主体)----->认证----->授权[action(可做什么)]--- ...
- Golang(五)Context 的使用和源码分析
0. 前言 golang 的 Context 包,是专门用来简化对于处理单次请求但是涉及到多个 goroutine 之间与请求域的数据.取消信号.截止时间等相关操作,这些操作可能涉及多个 API 调用 ...
- JS 中判断数据类型是否为 null、undefined 或 NaN
判断 undefined var aaa = undefined; console.log(typeof(aaa) === "undefined"); // true 判断 nul ...
- 深度学习 NI-DL 框架
NI-DL 应用框架:图像分类,目标检测,分割提取. 底层:TensorFlow,Keras,Cuda,C/C++ 上层:C#.NET Winform [图像分类] 识别一张图片是否为某个类型的物体/ ...
- linux alias写快捷键笔记
linux alias写快捷键笔记<pre>#vi ~/.bashrc ps:~找个代表当前登录用户的用户目录 pwd就知道了alias phpfpmrestart='/usr/local ...
- prometheus使用postgresql-adapter连接postgresql
概述 Prometheus使用postgresql需要使用postgresql-adapter进行数据转换.在安装postgresql-adapter之前需要安装2个扩展:pg_prometheus和 ...
- 【转】JavaScript 高性能数组去重
原文地址:https://www.cnblogs.com/wisewrong/p/9642264.html 一.测试模版 数组去重是一个老生常谈的问题,网上流传着有各种各样的解法 为了测试这些解法的性 ...
- 发现一个企业微信第三方应用开发的疑似BUG
1.企业微信两个账号A(超级管理员),账号B(分级管理员),账号B具有创建应用与小程序权限.2.账号B添加一个第三方应用后(创建后能看到第三方应用),使用下图接口登录时回调的agent一直为空,3.超 ...
- 责任链(ChainOfResponsibility)模式
在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出请求的客户端并不知道链上的哪一个对象,这使得系统可以在不影响客户端的 ...
- SET QUOTED_IDENTIFIER选项对索引的影响
早上来到公司,发现用于整理索引碎片的Job跑失败了,查看job history,发现以下错误消息: ALTER INDEX failed because the following SET optio ...