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. CSS3实现PS中的蚁行线动画以及画布的马赛克背景图

    话不多说,先看例子,外链 效果截图如下: 蚁行线 马赛克背景 代码: 蚁行线代码如下: /* <!-- HTML代码 --> <div class="ant"&g ...

  2. makefile通用版本(三)

    DIR_INC = ./include DIR_SRC = ./src DIR_OBJ = ./obj DIR_BIN = ./bin DIR_LIB = -Wl,-rpath=/home/exbot ...

  3. QT QWidget 关闭的流程

    当QWidget被点击右上角“X”关闭时: 1.调用虚函数closeEvent 2.调用QWidget的析构函数

  4. Scala 在挖财的应用实践

    编者按:本文是根据ArchSummit 大会上挖财资深架构师王宏江的演讲<Scala 在挖财的应用实践>整理而成. 这次分享有三个方面,一是介绍一下挖财当前的开发情况和后端的架构, 二是挖 ...

  5. GPG实践

    遇见的问题 安装之后没有显示如教程中的 直接提示真实姓名于电子邮件的地址 公钥与密钥 设置吊销证书

  6. 记一次Pr字幕模糊问题及解决方法

    目录 问题: 解决: 问题: 1.导出视频后,发现字幕很模糊 2.发现我们导出时的设置如下图,画面大小为432x244 3.即使暴力修改宽度为1080,导出画面的清晰度也不会有什么变化. 解决: 1. ...

  7. kali 更改图标村大小

    1.“设置” --> "通用辅助功能" --> "大号字体" 2.在终端中输入 “gnome-tweaks” 打开 优化 --> 扩展  -- ...

  8. Maven 教程(9)— Maven坐标详解

    原文地址:https://blog.csdn.net/liupeifeng3514/article/details/79544532 Maven的一个核心的作用就是管理项目的依赖,引入我们所需的各种j ...

  9. struts2.xml 中result type属性说明

    chain           用来处理Action链,被跳转的action中仍能获取上个页面的值,如request信息.           com.opensymphony.xwork2.Acti ...

  10. Java学习:方法重载的使用规则

    方法的重载 对于功能类似的方法来说,因为参数列表不一样,却需要记住那多不同的方法名称,太麻烦. 方法的重载(Overload):多个方法的名称一样,但是参数列表不一样.好处:只需要记住唯一一个方法名称 ...