一、socketserver模块简介

socketserver模块简化了网络编程,模块下有五个服务类:BaseServer、TCPServer、UDPServer、UnixStreamServer、UnixDatagramServer 。这五个类的关系如下:

+------------+
| BaseServer |
+------------+
|
v
+-----------+ +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+ +------------------+
|
v
+-----------+ +--------------------+
| UDPServer |------->| UnixDatagramServer |

1、四个基本的同步服务器类简介:

class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True):TCP数据流服务器
class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True):UDP数据报服务器

class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True):仅限于Unix系统的,Unix套接字流
class socketserver.UnixDatagramServer(server_address, RequestHandlerClass, bind_and_activate=True):仅限于Unix系统的,Unix数据报

他们的参数意义相同,如下:

server_address:服务器的地址,他应该是一个元组包含地址和端口如:('192.168.1.1',9000),

RequestHandlerClass:我们自定义的类,类中必须重写handle()方法。用于处理所有socket请求。

bind_and_activate:如果为True,将自动调用server_bind()和server_activate()。

这四个类运行时只能处理一个请求,也就是一个服务端只能对应一个客户端,这对于我们将来要编写的FTP服务器可能不适用,因为我们希望一个服务能处理多个客户端,下面我们来看socketserver为我们提供的两个处理异步的类。

2、异步服务器类简介

class socketserver.ForkingMixIn:启用多进程
class socketserver.ThreadingMixIn:启用多线程

创建异步服务的方法非常简单,下面创建一个简单的TCP框架为例:

import socketserver

class MyTCPServer(socketserver.BaseRequestHandler):  # 自定义TCP服务类,必须继承socketserver.BaseRequestHandler
def handle(self): # 重写此类,
'''
我们要处理的任务
:return:
'''
self.fun() # 执行我们的任务
def fun(self):
print('Hello World') class ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): # 类名随便起,必须要继承这两个类
pass
if __name__ == "__main__":
ip_port = ("127.0.0.1", 9000) # TCP服务器的地址和端口 with socketserver.ThreadingTCPServer(ip_port, MyTCPServer) as server:
server.serve_forever() # 开启TCP服务

这样我们就简单的创建了一个异步TCP服务器框架,其实ThreadingTCPServer这个类我们不用自己创建,因为socketserver已经为我们创建好了,如下:

class ForkingUDPServer(ForkingMixIn, UDPServer): pass  # 多进程UDP服务器
class ForkingTCPServer(ForkingMixIn, TCPServer): pass # 多进程TCP服务器
class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass # 多线程UDP服务器
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass # 多线程TCP服务器

如果觉得socketserver提供的这四个类不是你想要的,那么你就可以像上面那样自己定义,上面都是服务类,通过服务类实例化对象,但是目前还不知道对象拥有哪些方法,因为这些服务类都是继承的BaseServer类,所以方法都在BaseServer类中,有些方法只是定义了接口,在子类中实现的。

3、服务对象常用方法

class socketserver.BaseServer(server_address, RequestHandlerClass):

fileno():返回服务器正在监听的套接字的文件描述符(int类型的数字)。此函数最常传递给选择器,以允许监视同一进程中的多个服务器。

handle_request():处理单个请求。此函数按顺序调用以下方法:get_request()、verify_request()和process_request()。如果handler类的用户提供的handle()方法引发异常,则将调用服务器的handle_error()方法。如果在超时秒内未收到请求,将调用handle_timeout(),并返回handle_request()。

serve_forever(poll_interval=0.5):定时任务,通常是在一个线程中,每poll_interval秒轮询一次,直到调用shutdown停止。

service_actions():该函数被serve_forever定时函数重复调用,这个方法我们可以继承BaseServer,然后重写此方法。

shutdown():此方法用于停止serve_forever()定时任务。

socket:socket对象。

socket_type:socket套接字类型,TCP,UDP等。

allow_reuse_address:服务器是否允许地址的重用。默认为false ,并且可在子类中更改。

address_family:设置socket套接字家族。

server_address:值是一个元组,socket服务器地址和监听的端口。

server_activate():服务器将处于监听状态,该函数可被重写,其实他的内部就是self.socket.listen(self.request_queue_size)。

server_bind():将socket绑定到地址上,可以被重写。

get_request():此方法的前提是必须接收到来自套接字的请求,返回一个元组(与客户端通信的新套接字对象,客户端地址)。其实该方法就是将self.socket.accept()的结果返回。

server_close():关闭服务(关闭socket),此方法可被重写。

RequestHandlerClass:值是类名,这个类是我们定义的用于创建实例处理我们的请求,如上面TCP异步框架中的MyTCPServer,这个类就是RequestHandlerClass的值。

request_queue_size:请求队列的大小。如果处理单个请求需要很长时间,在服务器繁忙时会将请求放到队列中,当请求数达到request_queue_size的值时。来自客户端的进一步请求将得到一个“拒绝连接”错误。默认值通常是5,但是这个值可以被子类覆盖。

finish_request(request, client_address):此方法会实例化RequestHandlerClass并调用它的handle()方法来实际处理请求。

process_request(request,client_address):调用finish_request()来创建RequestHandlerClass的一个实例。我们可以自己创建线程池或进程池来调用这个函数,实现服务器处理多个请求的问题,ForkingMixIn和ThreadingMixIn类就是这样做的。

handle_error(request,client_address):如果RequestHandlerClass实例的handle()方法引发异常,则调用此函数。默认操作是将回溯打印到标准错误,并继续处理其他请求。在版本3.6中更改:现在仅调用从Exception类派生的异常。

timeout:超时时间(以秒为单位),如果是None,会一直阻塞。如果设置了timeout,handle_request()在超时期间没有收到传入请求,则调用handle_timeout()方法。

handle_timeout():当timeout属性被设置为None以外的值,并且超时周期已经过去而没有收到任何请求时,将调用此函数。多进程 服务器的默认操作是收集已退出的任何子进程的状态,而在线程服务器中,此方法不执行任何操作。

verify_request(request,client_address):返回一个布尔值;如果值为真,请求将被处理,如果值为假,请求将被拒绝。可以重写此函数以实现服务器的访问控制。默认实现只是一句return True。

上面这些都是服务对象的方法,下面来介绍处理socket请求类BaseRequestHandler。

4、客户端请求处理类BaseRequestHandler

class socketserver.BaseRequestHandler:

这是所有socket请求处理程序的基类。它只定义了接口,而没有实现,如果想要使用接口,我们首先继承BaseRequestHandler,然后在子类中重写这些方法。每个socket请求处理程序子类必须重写handle()方法,因为该方法是用于处理所有socket请求。该类的方法如下:

setup():在handle()方法之前调用,执行初始化操作。 默认不执行任何操作,我们可以重写此方法来实现程序的初始化。

handle():所有socket请求任务都是在这个函数内部完成的,我们在子类中必须重写此方法,并处理socket请求,因为默认基类中的handle()的实现不执行任何操作。

finish():在handle()方法之后调用以执行清理操作。默认实现不执行任何操作。如果setup()引发异常,则不会调用此函数。

虽然上面的接口都只是定义而没有实现,但是它的实例属性还是很有用的;

self.request;客户端和服务端的连接对象,用于发送数据,接收数据。

self.client_address:socket客户端地址 。

self.server:socket服务端信息。

class socketserver.StreamRequestHandler
class socketserver.DatagramRequestHandler
这两个类是socketserver继承BaseRequestHandler后重写了setup(),finish(),实现了对读,写缓冲区的设置,有兴趣的可以看看源码。

5、官方示例:

TCP同步服务示例:

# 服务端
import socketserver class MyTCPHandler(socketserver.BaseRequestHandler): # 自定义类,继承BaseRequestHandler,处理socket请求 def handle(self): # socket客户端请求
self.data = self.request.recv(1024).strip() # 接收socket客户端发来的数据
print("{} wrote:".format(self.client_address[0]))
print(self.data)
self.request.sendall(self.data.upper()) # 将数据大写后发给客户端
'''
class MyTCPHandler(socketserver.StreamRequestHandler):
# 自定义类,功能与上面的一样,只不过是继承StreamRequestHandler
def handle(self):
# self.rfile is a file-like object created by the handler;
# we can now use e.g. readline() instead of raw recv() calls
self.data = self.rfile.readline().strip()
print("{} wrote:".format(self.client_address[0]))
print(self.data)
# Likewise, self.wfile is a file-like object used to write back
# to the client
self.wfile.write(self.data.upper())
''' if __name__ == "__main__":
HOST, PORT = "localhost", 9999 with socketserver.TCPServer((HOST, PORT), MyTCPHandler) as server:
server.serve_forever() # 启用TCP服务器
# 打印内容如下
127.0.0.1 wrote:
b'Hello World' # 客户端
import socket
import sys HOST, PORT = "localhost", 9999
data = "Hello World" # Create a socket (SOCK_STREAM means a TCP socket)
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
# Connect to server and send data
sock.connect((HOST, PORT))
sock.sendall(bytes(data + "\n", "utf-8")) # Receive data from the server and shut down
received = str(sock.recv(1024), "utf-8") print("Sent: {}".format(data))
print("Received: {}".format(received)) # 打印内容如下
Sent: Hello World
Received: HELLO WORLD

UDP服务示例:

# 服务端
import socketserver class MyUDPHandler(socketserver.BaseRequestHandler):
"""
This class works similar to the TCP handler class, except that
self.request consists of a pair of data and client socket, and since
there is no connection the client address must be given explicitly
when sending data back via sendto().
""" def handle(self):
data = self.request[0].strip()
socket = self.request[1]
print("{} wrote:".format(self.client_address[0]))
print(data)
socket.sendto(data.upper(), self.client_address) if __name__ == "__main__":
HOST, PORT = "localhost", 9999
with socketserver.UDPServer((HOST, PORT), MyUDPHandler) as server:
server.serve_forever()
# 打印内容如下
127.0.0.1 wrote:
b'Hello World' # 客户端
import socket
import sys HOST, PORT = "localhost", 9999
data = "Hello World" # SOCK_DGRAM is the socket type to use for UDP sockets
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # As you can see, there is no connect() call; UDP has no connections.
# Instead, data is directly sent to the recipient via sendto().
sock.sendto(bytes(data + "\n", "utf-8"), (HOST, PORT))
received = str(sock.recv(1024), "utf-8") print("Sent: {}".format(data))
print("Received: {}".format(received))
# 打印内容如下
Sent: Hello World
Received: HELLO WORLD

TCP服务异步示例:

import socket
import threading
import socketserver class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler): # 自定义socket请求处理类
def handle(self):
data = str(self.request.recv(1024), 'ascii')
cur_thread = threading.current_thread()
response = bytes("{}: {}".format(cur_thread.name, data), 'ascii')
self.request.sendall(response) class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): # 自定义线程类处理多个请求
pass def client(ip, port, message):
'''
socket客户端
:param ip: 服务段的IP地址
:param port: 服务端的端口
:param message: 给服务端发送的消息
:return:
'''
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect((ip, port))
sock.sendall(bytes(message, 'ascii'))
response = str(sock.recv(1024), 'ascii')
print("Received: {}".format(response)) if __name__ == "__main__": HOST, PORT = "localhost", 0 # 端口是0随机获取一个未被使用的端口
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
with server:
ip, port = server.server_address # 获取服务端的IP地址和端口号
server_thread = threading.Thread(target=server.serve_forever) # 创建线程对象
server_thread.daemon = True # 守护线程
server_thread.start() # 开启线程,在线程中开启TCP服务器
print("Server loop running in thread:", server_thread.name)
# 模拟三个socket客户端连接TCP服务器
client(ip, port, "Hello World 1")
client(ip, port, "Hello World 2")
client(ip, port, "Hello World 3") server.shutdown()
# 打印内容如下:
Server loop running in thread: Thread-1
Received: Thread-2: Hello World 1
Received: Thread-3: Hello World 2
Received: Thread-4: Hello World 3

参考文档:https://docs.python.org/3/library/socketserver.html?highlight=socketserver#module-socketserver


socketserver 模块简介的更多相关文章

  1. socketserver模块简介

    1. socketserver模块简介 在python的socket编程中,实用socket模块的时候,是不能实现多个连接的,当然如果加入其 它的模块是可以的,例如select模块,在这里见到的介绍下 ...

  2. 网络编程(基于udp协议的套接字/socketserver模块/进程简介)

    一.基于UDP协议的套接字 TCP是建立可靠连接,并且通信双方都可以以流的形式发送数据.相对TCP,UDP则是面向无连接的协议. 使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就 ...

  3. Python socketserver模块解析

    参考:https://blog.csdn.net/qq_33733970/article/details/79153938 1.功能简介 socketserver模块是对socket模块的再封装,用于 ...

  4. socketserver模块、MySQL(数据库、数据表的操作)

    一.socketserver实现并发 基于tcp的套接字,关键就是两个循环,一个链接循环,一个通信循环. socketserver模块中分两大类:server类(解决链接问题)和request类(解决 ...

  5. Python::OS 模块 -- 简介

    OS 模块简介 OS模块是Python标准库中的一个用于访问操作系统功能的模块,OS模块提供了一种可移植的方法使用操作系统的功能.使用OS模块中提供的接口,可以实现跨平台访问.但是在OS模块中的接口并 ...

  6. socket 和 SocketServer 模块

    一 .Socket 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket socket(TCP,IP)通常也称作"套接字",用于描述IP地址和端 ...

  7. SocketServer模块

    在利用select实现伪并发的socket博文中我们说了: 如果要实现一个server端可以和多个客户端进行通信可以使用 1.多线程 2.多进程 3.select I/O多路复用 在那篇博文中我们介绍 ...

  8. 浅析python中socketserver模块使用

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

  9. Python网络编程(2)-粘包现象及socketserver模块实现TCP并发

    1. 基于Tcp的远程调用命令实现 很多人应该都使用过Xshell工具,这是一个远程连接工具,通过上面的知识,就可以模拟出Xshell远程连接服务器并调用命令的功能. Tcp服务端代码如下: impo ...

随机推荐

  1. [MongoDB] 使用PHP在MongoDB中搜索的实现

    条件操作符用于比较两个表达式并从mongoDB集合中获取数据.MongoDB中条件操作符有:(>) 大于 - $gt(<) 小于 - $lt(>=) 大于等于 - $gte(< ...

  2. 前端Css学习

    CSS 称为层叠样式表 css样式引入方式 第一种 head标签中引入 <style> /* 选择器{css属性名称:属性值;css属性名称:属性值;} */ div{ /* css注释 ...

  3. [bzoj1905] [ZJOI2007] Hide 捉迷藏

    题意简述 给定一棵 \(n\) 个点的树,起初每个点都为黑色. 2种操作,要么改变某个点的颜色(由黑至白或由白至黑),要么询问距离最远的两个黑点间的距离. 共 \(m\) 次操作. \(n\leq 1 ...

  4. Pytest学习6-跳过或xfail失败的用例

    Skip跳过用例 跳过(Skip)指,你希望如果某些条件得到满足你的测试用例才执行,否则Pytest应该完全跳过运行该用例 1. 跳过测试用例的最简单方法是使用skip装饰器标记它,可以传递一个可选的 ...

  5. 01-Java基本语法【前言、入门程序、常量、变量】

    重点知识记录: 1.java语言是美国Sun公司在1995年推出的高级编程语言. 2.java语言主要应用在互联网程序的开发领域. 3.二进制转换 1)十进制数据转换成二进制数据:使用除以2获取余数的 ...

  6. IntelliJ IDEA 2017.3尚硅谷-----配置 Maven

  7. (GHRD)HPS

    DE1作为ARM+FPGA的组合,ARM和FPGA之间通信,两个区块间有三个通道可以让两部分实现传输数据,统称为 HPS-FPGA AXI Bridges. 分别为:FPGA-to-HPS Bridg ...

  8. OpenCV之Core组件进阶

    颜色空间缩减 利用C++类型转换时向下取整操作,实现定义域内颜色缩减.表达式如下 Inew = (Iold/10)*10 简单的颜色空间缩减算法可由以下两步组成: (1)遍历图像矩阵的每个元素 (2) ...

  9. TCP/IP协议-为什么说TCP是可靠连接

    我们平常经常说UDP是不可靠连接,TCP是可靠连接,然而TCP为什么是可靠的呢 1. TCP和UDP的优缺点TCP 缺点: [1] 三次握手四次挥手,传输更多包,浪费一些带宽[2] 为了进行可靠通信, ...

  10. 1.6 APP需要怎么测试

    来源:  https://tieba.baidu.com/p/5011439767           http://www.cnblogs.com/testwriter/p/6702624.html ...