首页 > 编程语言 >Python 高级编程之网络编程 SocketServer(七)

Python 高级编程之网络编程 SocketServer(七)

时间:2023-02-13 23:34:11浏览次数:68  
标签:SocketServer socketserver Python 创建 self 编程 server 服务器 客户端

目录

一、概述

socket不能多并发,只能支持一个用户socketserver 模块是 Python 中用于创建网络服务器的模块,提供了一种简单而一致的接口。它是构建网络服务器的框架,处理了创建、维护和关闭连接的许多底层细节,socketserversocket的再封装

  • socketserverpython2中为SocketServer
  • python3种取消了首字母大写,改名为socketserver
  • socketserver中包含了两种类,
    • 一种为服务类(server class):前者提供了许多方法:像绑定,监听,运行…… (也就是建立连接的过程) 。
    • 一种为请求处理类(request handle class):专注于如何处理用户所发送的数据(也就是事务逻辑)。
  • 一般情况下,所有的服务,都是先建立连接,也就是建立一个服务类的实例,然后开始处理用户请求,也就是建立一个请求处理类的实例。

socketserver 模块提供了几个类,包括:

  • BaseServer:实现服务器的基本类。

  • TCPServer:处理 TCP 连接的服务器。

  • UDPServer:处理 UDP 连接的服务器。

  • UnixStreamServer:类似于TCPServer提供面向数据流的套接字连接,但是旨在UNIX平台上可用。

  • UnixDatagramServer:类似于UDPServer提供面向数据报的套接字连接,但是旨在UNIX平台上可用。

  • ForkingMixIn:实现了核心的进程化功能,用于与服务器类进行混合,提供异步特性。

  • ThreadingMixIn:实现了核心的线程化功能,用于与服务器类进行混合,异步特性。

  • ForkingTCPServer:每个请求创建一个新进程的 TCP 服务器。ForkingMixInTCPServer`组合。

  • ForkingUDPServer:每个请求创建一个新进程的 UDP 服务器。ForkingMixInUDPServer组合。

  • ThreadingTCPServer:在单独的线程中处理每个请求的 TCP 服务器。ThreadingMixInTCPServer组合。

  • ThreadingUDPServer:在单独的线程中处理每个请求的 UDP 服务器。ThreadingMixInUDPServer组合。

  • BaseRequestHandler:用于定制Handler类型,自定义的Handler类型只要继承自BaseRequestHandler,并覆盖写入它的handle() 方法即可。

  • StreamRequestHandler:TCP请求处理类的一个实现。

  • DataStreamRequestHandler:UDP请求处理类的一个实现。

server类继承关系:
在这里插入图片描述
请求处理类继承关系:
在这里插入图片描述

Socket 编程可以参考我这篇文章:Python 高级编程之网络编程 Socket(六)

在这里插入图片描述

二、socket 模块与 socketserver 关系

socketsocketserver 是两个不同的 Python 模块,都用于网络编程。

  • socket 模块提供了通用的套接字编程接口,可用于创建客户端和服务器端程序。它涵盖了与网络通信相关的底层细节,如创建套接字、绑定地址、监听请求、接受连接、发送数据和接收数据。
  • socketserver 模块是 socket 模块的一个封装,它抽象了服务器端网络编程的复杂度,使您能够快速编写服务器端程序。它提供了多种服务器类型,如多线程服务器多进程服务器单进程服务器,以满足不同的网络编程需求。此外,它还提供了简单的面向对象编程模型,允许您扩展基础类并定制服务器行为。

总而言之,如果您需要快速编写简单的服务器端程序,那么 socketserver 模块可能是您的最佳选择;如果您需要更多的灵活性和细节控制,则可以使用 socket 模块。

在解析socketserver是如工作之前,我们先看看socektserver类的继承关系图:

三、socketserver 模块使用

继承关系图中有五个类,其中四个类表示四种类型的同步服务器:

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

1)创建 TCPServer

TCPServer 类是 Python3 中基于 TCP 协议的多线程服务器类

语法规则:

# 这将使用InternetTCP协议,该协议提供客户机和服务器之间的连续数据流。如果 bind_and_activate 为true,构造函数自动尝试调用 server_bind() 和 server_activate() . 其他参数将传递给 BaseServer 基类。
s = socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)

# socketserver.UnixStreamServer:仅限于Unix系统的,Unix套接字流
s = socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)

使用 UDPServer 类时,您可以指定下列三个参数:

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

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

  • bind_and_activate:如果为True,将自动调用server_bind()和server_activate()。一般默认即可。

下面是一个使用 TCPServer 类的简单示例:

import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        # 接收客户端请求的数据
        self.data = self.request.recv(1024).strip()
        print("{} 发送了:{}".format(self.client_address[0], self.data))
        # 向客户端发送响应数据
        self.request.sendall(self.data.upper())

if __name__ == "__main__":
    # 创建服务器,绑定 IP 地址和端口号
    HOST, PORT = "localhost", 9999
    server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)
    # 启动服务器
    server.serve_forever()

该代码定义了一个简单的多线程服务器,它绑定在本地主机(localhost)的端口号 9999 上。当有客户端连接时,服务器会接收客户端发送的数据,然后将数据转换为大写并发送回客户端。

  • 请注意,您需要创建一个名为 MyTCPHandler 的处理程序类,该类必须从 socketserver.BaseRequestHandler 类继承,并实现 handle 方法。在 handle 方法中,您可以处理客户端请求,并向客户端发送响应数据。

  • 最后,您可以通过调用 server.serve_forever() 方法启动服务器,并使其处于持续监听状态。

2)创建 UDPServer

UDPServer 是 socketserver 模块中用于创建 UDP 服务器的类。

语法规则:

# 它使用数据报,这些数据报是离散的信息包,在传输过程中可能出现无序到达或丢失。
s = socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)

# socketserver.UnixDatagramServer:仅限于Unix系统的,Unix套接字流
s = socketserver.UnixDatagramServer(server_address, RequestHandlerClass, bind_and_activate=True)

使用 UDPServer 类时,您可以指定下列三个参数:

  • server_address:服务器的 IP 地址和端口号。例如:("localhost", 9999)。

  • RequestHandlerClass:处理客户端请求的处理程序类。例如:MyUDPHandler。

  • bind_and_activate:如果为True,将自动调用server_bind()和server_activate()。一般默认即可。

四、异步服务器类(对线程、多进程)

socketserver 模块中也提供了一些异步服务器类,它们可以在单独的线程中处理多个客户端请求,从而提高服务器的并发性能。下面一一介绍。

1)ThreadingMixIn(多线程)

ThreadingMixIn 类是 socketserver 模块中的一个异步服务器类,用于创建基于多线程的异步服务器

您可以通过继承该类来创建自己的异步服务器类,然后通过该类创建服务器。例如,创建一个基于多线程的异步 TCP 服务器的代码如下:

import socketserver

class ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass

# 创建服务器,绑定 IP 地址和端口号
HOST, PORT = "localhost", 9999
server = ThreadingTCPServer((HOST, PORT), MyTCPHandler)

在这里,您需要创建一个名为 MyTCPHandler 的处理程序类,该类必须从 socketserver.BaseRequestHandler 类继承,并实现 handle 方法。该方法是处理客户端请求的核心方法,在该方法中您可以处理客户端请求,并向客户端发送响应数据。

在创建基于多线程的异步服务器时,每个客户端请求都会在一个单独的线程中处理,从而提高服务器的并发性能。

完整实例如下:

import socket
import threading
import socketserver

class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):

    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):
    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__":
    # Port 0 means to select an arbitrary unused port
    HOST, PORT = "localhost", 0

    server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
    with server:
        ip, port = server.server_address

        # Start a thread with the server -- that thread will then start one
        # more thread for each request
        server_thread = threading.Thread(target=server.serve_forever)
        # Exit the server thread when the main thread terminates
        server_thread.daemon = True
        server_thread.start()
        print("Server loop running in thread:", server_thread.name)

        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

2)ForkingMixIn(多进程)

ForkingMixIn 类是 socketserver 模块中的一个异步服务器类,用于创建基于多进程的异步服务器。

您可以通过继承该类来创建自己的异步服务器类,然后通过该类创建服务器。例如,创建一个基于多进程的异步 TCP 服务器的代码如下:

import socketserver

class ForkingTCPServer(socketserver.ForkingMixIn, socketserver.TCPServer):
    pass

# 创建服务器,绑定 IP 地址和端口号
HOST, PORT = "localhost", 9999
server = ForkingTCPServer((HOST, PORT), MyTCPHandler)

在这里,您需要创建一个名为 MyTCPHandler 的处理程序类,该类必须从 socketserver.BaseRequestHandler 类继承,并实现 handle 方法。该方法是处理客户端请求的核心方法,在该方法中您可以处理客户端请求,并向客户端发送响应数据。

在创建基于多进程的异步服务器时,每个客户端请求都会在一个单独的进程中处理,从而提高服务器的并发性能。

【注意】在 Unix 系统上,使用多进程的异步服务器可能会导致内存占用增加。因此,在 Unix 系统上,建议使用多线程的异步服务器。

3)ForkingTCPServer (TCP 多进程)

ForkingTCPServer 是 socketserver 模块中的一个异步服务器类,用于创建基于多进程的 TCP 服务器。

要使用 ForkingTCPServer 类,您需要提供服务器的 IP 地址和端口号,以及处理客户端请求的处理程序类。

以下是一个使用 ForkingTCPServer 类的示例:

import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        # 获取客户端请求的数据
        data = self.request.recv(1024).strip()
        # 向客户端发送响应数据
        self.request.sendall(bytes("Hello, {0}".format(data), "utf-8"))

# 创建服务器,绑定 IP 地址和端口号
HOST, PORT = "localhost", 9999
server = socketserver.ForkingTCPServer((HOST, PORT), MyTCPHandler)

# 启动服务器
server.serve_forever()

在这个示例中,我们创建了一个名为 MyTCPHandler 的处理程序类,该类从 socketserver.BaseRequestHandler 类继承,并实现了 handle 方法。该方法是处理客户端请求的核心方法,在该方法中您可以处理客户端请求,并向客户端发送响应数据。

接下来,我们使用 socketserver.ForkingTCPServer 类创建了一个 TCP 服务器,并绑定了服务器的 IP 地址和端口号。最后,我们使用 serve_forever 方法启动服务器,以便处理。

4)ForkingUDPServer (UDP 多进程)

ForkingUDPServer 是 socketserver 模块中的一个异步服务器类,用于创建基于多进程的 UDP 服务器。

要使用 ForkingUDPServer 类,您需要提供服务器的 IP 地址和端口号,以及处理客户端请求的处理程序类。

以下是一个使用 ForkingUDPServer 类的示例:

import socketserver

class MyUDPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        data = self.request[0].strip()
        socket = self.request[1]
        # 向客户端发送响应数据
        socket.sendto(bytes("Hello, {0}".format(data), "utf-8"), self.client_address)

# 创建服务器,绑定 IP 地址和端口号
HOST, PORT = "localhost", 9999
server = socketserver.ForkingUDPServer((HOST, PORT), MyUDPHandler)

# 启动服务器
server.serve_forever()

在这个示例中,我们创建了一个名为 MyUDPHandler 的处理程序类,该类从 socketserver.BaseRequestHandler 类继承,并实现了 handle 方法。该方法是处理客户端请求的核心方法,在该方法中您可以处理客户端请求,并向客户端发送响应数据。

接下来,我们使用 socketserver.ForkingUDPServer 类创建了一个 UDP 服务器,并绑定了服务器的 IP 地址和端口号。最后,我们使用 serve_forever 方法启动服务器,以便处理客户端请求。

5)ThreadingTCPServer(TCP 多线程)

ThreadingTCPServer 是 socketserver 模块中的一个异步服务器类,用于创建基于多线程的 TCP 服务器

要使用 ThreadingTCPServer 类,您需要提供服务器的 IP 地址和端口号,以及处理客户端请求的处理程序类。

以下是一个使用 ThreadingTCPServer 类的示例:

import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        data = self.request.recv(1024).strip()
        # 向客户端发送响应数据
        self.request.sendall(bytes("Hello, {0}".format(data), "utf-8"))

# 创建服务器,绑定 IP 地址和端口号
HOST, PORT = "localhost", 9999
server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)

# 启动服务器
server.serve_forever()

在这个示例中,我们创建了一个名为 MyTCPHandler 的处理程序类,该类从 socketserver.BaseRequestHandler 类继承,并实现了 handle 方法。该方法是处理客户端请求的核心方法,在该方法中您可以处理客户端请求,并向客户端发送响应数据。

接下来,我们使用 socketserver.ThreadingTCPServer 类创建了一个 TCP 服务器,并绑定了服务器的 IP 地址和端口号。最后,我们使用 serve_forever 方法启动服务器,以便处理客户端请求。

5)ThreadingUDPServer(UDP 多线程)

ThreadingUDPServer 是 socketserver 模块中的一个异步服务器类,用于创建基于多线程的 UDP 服务器。

要使用 ThreadingUDPServer 类,您需要提供服务器的 IP 地址和端口号,以及处理客户端请求的处理程序类。

以下是一个使用 ThreadingUDPServer 类的示例:

import socketserver

class MyUDPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        data = self.request[0].strip()
        socket = self.request[1]
        # 向客户端发送响应数据
        socket.sendto(bytes("Hello, {0}".format(data), "utf-8"), self.client_address)

# 创建服务器,绑定 IP 地址和端口号
HOST, PORT = "localhost", 9999
server = socketserver.ThreadingUDPServer((HOST, PORT), MyUDPHandler)

# 启动服务器
server.serve_forever()

在这个示例中,我们创建了一个名为 MyUDPHandler 的处理程序类,该类从 socketserver.BaseRequestHandler 类继承,并实现了 handle 方法。该方法是处理客户端请求的核心方法,在该方法中您可以处理客户端请求,并向客户端发送响应数据。

接下来,我们使用 socketserver.ThreadingUDPServer 类创建了一个 UDP 服务器,并绑定了服务器的 IP 地址和端口号。最后,我们使用 serve_forever 方法启动服务器,以便处理客户端请求。


Python 高级编程之网络编程 SocketServer 讲解就先到这里,这里知识讲概念和示例,后面会有相关项目应用,有任何疑问欢迎给我留言哦,后续会持续更新相关技术文章,请小伙伴耐心等待哦,也可以关注我的公众号【大数据与云原生技术分享】进行深入技术交流~

标签:SocketServer,socketserver,Python,创建,self,编程,server,服务器,客户端
From: https://www.cnblogs.com/liugp/p/17118283.html

相关文章

  • python中list中的元素去重
     直观方法最简单的思路就是: 代码如下:ids=[1,2,3,3,4,2,3,4,5,6,1]news_ids=[]foridinids:   ifidnotinnews_ids:       news_ids.a......
  • SparkSQL指南-快速开始(Python版)——(一)
    快速开始创建环境Spark程序主要分为三个阶段:创建环境数据操作关闭环境(在Streaming程序中为执行环境)下面是批处理的SparkSQLAPI的创建环境的类:SparkSession,其目的......
  • python中defaultdict 的用法
    defaultdict:当我使用普通的字典时,用法一般是dict={},添加元素的只需要dict[element]=value即,调用的时候也是如此,dict[element]=xxx,但前提是element字典里,如果不在字......
  • 电商网站Web自动化测试实战( 编写京东搜索脚本python+selenium框架)
    电商网站Web自动化测试实战(编写京东搜索脚本)1,打开京东页京东首页地址:https://www.jd.com/,故进入京东首页如下:2,打开浏览器开发者模式定位元素前需先打开浏览器开发者......
  • python pandas库总结-数据分析和操作工具
    参考:https://pandas.pydata.org/Input/output相关函数pandas.read_excel—将Excel文件读入pandas数据框支持读取xls,xlsx,xlsm,xlsb,odf,ods和odt文件扩展名,支持单......
  • python爬虫学习——列表
    namelist=[]#定义一个空的列表namelist1=["小张","小红","小李"]print(namelist1[0])print(namelist1[1])print(namelist1[2])testlist=[1,"测试"]#列表中......
  • python入门学习笔记004--趣学Python算法--第4例百钱百鸡
    中国古代数学家张丘建在他的《算经》中提出了一个著名的“百钱百鸡问题”:一只公鸡值五钱,一只母鸡值三钱,三只小鸡值一钱,现在要用百钱买百鸡,请问公鸡、母鸡、小鸡各多少只? ......
  • python 多线程 join
    当一个进程启动之后,会默认产生一个线程。这个线程就是主线程。如果是多线程时,主线程会创建多个线程。主线程执行完成后就会退出。多线程执行完成后也会退出。注意:只有守护......
  • 9.4 操作系统和高级编程语言使硬件抽象化
    通过使用操作系统提供的系统调用,程序员就没必要编写直接控制硬件的程序了。通过使用高级编程语言,有时甚至也无需考虑系统调用的存在。这是因为操作系统和高级编程语言能够......
  • python文件I/O
    1、打印到控制台:printif__name__=='__main__':print('hello')2、读取键盘输入:inputif__name__=='__main__':str1=input('请输入:')print(str1)3、打开......