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. [THUPC2019]过河卒二(组合数学,容斥原理)

    以后都懒得写题目大意和数据范围了. hz学长的题其实也不那么毒瘤吗.比CDW的好多了 先考虑没有障碍怎么做. 首先发现,答案相当于一个左下角是 $(1,1)$,右上角是 $(n+1,m+1)$ 的棋盘 ...

  2. Python、Spyder的环境搭建

    有什么不对欢迎大家指出,一起交流啊,只针对Windows!!!!(苹果买不起...)Python安装的话2.7版本和3.6版本都可以,虽然2.7比较全面,但还是建议安装3.6,这里以3.6为例进行介绍 ...

  3. C语言实现linux之who功能

    /* who_test.c */ #include<stdio.h> #include<string.h> #include<getopt.h> #include& ...

  4. B1003

    import re n = input() for i in range(int(n)): str = input() if re.match(r'A*PA+TA*',str): a = re.spl ...

  5. 解决github clone慢的问题

    github clone非常慢,解决方法,首先要有vpn 参考 https://www.zhihu.com/question/27159393 第一种方法 这种是没有vpn的方法,测试从10k到 几十 ...

  6. 删除list集合中某些数据

    去除list集合中不符合条件的数据 List<DictVo> applyStateList = SingletonHoldResource.getInstance().getList(Fr ...

  7. C# POST方式提交数据,接收方式,使用Request.Form[""]或Request[""]来获取

    /// <summary> /// 调用接口 /// </summary> /// <param name="url"></param&g ...

  8. 依赖注入之unity(winform方式)

    依赖注入之unity(winform方式) 要讲unity就必须先了解DI和IOC及DIP,如下链接提供DI和IOC的基础:https://www.cnblogs.com/zlp520/p/12015 ...

  9. 【Python开发】Pycharm下的Anaconda配置

    我的系统是Win 64位的,用的Python 3.5.1 ,最近在学机器学习,用到了Numpy这个科学计算库,网上查了之后,看到很多装Numpy出问题的情况,所以决定装Anaconda,简单一些,并且 ...

  10. 内存泄漏(Memory Leak)

    内存泄露检测工具Valgrind   内存泄露简介 回到顶部 什么是内存泄漏 内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因,程序未释放或无法释放,造成系统内存的浪费,导致 ...