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的更多相关文章

  1. python基础(15)-socket网络编程&socketserver

    socket 参数及方法说明 初始化参数 sk = socket.socket(参数1,参数2,参数3) 参数1:地址簇 socket.AF_INET IPv4(默认) socket.AF_INET6 ...

  2. Day09: socket网络编程-OSI七层协议,tcp/udp套接字,tcp粘包问题,socketserver

    今日内容:socket网络编程    1.OSI七层协议    2.基于tcp协议的套接字通信    3.模拟ssh远程执行命令    4.tcp的粘包问题及解决方案    5.基于udp协议的套接字 ...

  3. Python全栈【Socket网络编程】

    Python全栈[socket网络编程] 本章内容: Socket 基于TCP的套接字 基于UDP的套接字 TCP粘包 SocketServer 模块(ThreadingTCPServer源码剖析) ...

  4. python之Socket网络编程

    什么是网络? 网络是由节点和连线构成,表示诸多对象及其相互联系.在数学上,网络是一种图,一般认为专指加权图.网络除了数学定义外,还有具体的物理含义,即网络是从某种相同类型的实际问题中抽象出来的模型.在 ...

  5. Python之路【第七篇】python基础 之socket网络编程

    本篇文章大部分借鉴 http://www.cnblogs.com/nulige/p/6235531.html python socket  网络编程 一.服务端和客户端 BS架构 (腾讯通软件:ser ...

  6. 循序渐进Socket网络编程(多客户端、信息共享、文件传输)

    循序渐进Socket网络编程(多客户端.信息共享.文件传输) 前言:在最近一个即将结束的项目中使用到了Socket编程,用于调用另一系统进行处理并返回数据.故把Socket的基础知识总结梳理一遍. 1 ...

  7. Py西游攻关之Socket网络编程

    新闻 管理   Py西游攻关之Socket网络编程   知识预览 计算机网络 回到顶部 网络通信要素: A:IP地址   (1) 用来标识网络上一台独立的主机 (2) IP地址 = 网络地址 + 主机 ...

  8. Python面向对象进阶和socket网络编程-day08

    写在前面 上课第八天,打卡: 为什么坚持?想一想当初: 一.面向对象进阶 - 1.反射补充 - 通过字符串去操作一个对象的属性,称之为反射: - 示例1: class Chinese: def __i ...

  9. Python之旅Day8 socket网络编程

    socket网络编程 Socket是网络编程的一个抽象概念.通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可.soc ...

随机推荐

  1. K8s集群认证之RBAC

    kubernetes认证,授权概括总结: RBAC简明总结摘要:API Server认证授权过程: subject(主体)----->认证----->授权[action(可做什么)]--- ...

  2. Golang(五)Context 的使用和源码分析

    0. 前言 golang 的 Context 包,是专门用来简化对于处理单次请求但是涉及到多个 goroutine 之间与请求域的数据.取消信号.截止时间等相关操作,这些操作可能涉及多个 API 调用 ...

  3. JS 中判断数据类型是否为 null、undefined 或 NaN

    判断 undefined var aaa = undefined; console.log(typeof(aaa) === "undefined"); // true 判断 nul ...

  4. 深度学习 NI-DL 框架

    NI-DL 应用框架:图像分类,目标检测,分割提取. 底层:TensorFlow,Keras,Cuda,C/C++ 上层:C#.NET Winform [图像分类] 识别一张图片是否为某个类型的物体/ ...

  5. linux alias写快捷键笔记

    linux alias写快捷键笔记<pre>#vi ~/.bashrc ps:~找个代表当前登录用户的用户目录 pwd就知道了alias phpfpmrestart='/usr/local ...

  6. prometheus使用postgresql-adapter连接postgresql

    概述 Prometheus使用postgresql需要使用postgresql-adapter进行数据转换.在安装postgresql-adapter之前需要安装2个扩展:pg_prometheus和 ...

  7. 【转】JavaScript 高性能数组去重

    原文地址:https://www.cnblogs.com/wisewrong/p/9642264.html 一.测试模版 数组去重是一个老生常谈的问题,网上流传着有各种各样的解法 为了测试这些解法的性 ...

  8. 发现一个企业微信第三方应用开发的疑似BUG

    1.企业微信两个账号A(超级管理员),账号B(分级管理员),账号B具有创建应用与小程序权限.2.账号B添加一个第三方应用后(创建后能看到第三方应用),使用下图接口登录时回调的agent一直为空,3.超 ...

  9. 责任链(ChainOfResponsibility)模式

    在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出请求的客户端并不知道链上的哪一个对象,这使得系统可以在不影响客户端的 ...

  10. SET QUOTED_IDENTIFIER选项对索引的影响

    早上来到公司,发现用于整理索引碎片的Job跑失败了,查看job history,发现以下错误消息: ALTER INDEX failed because the following SET optio ...