当前位置: 首页 > 工具软件 > SocketServer > 使用案例 >

python socketserver

闾丘诚
2023-12-01

一、 socketserver模块简介

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

socketserver,看其名字,就知道是一个socket的服务器模块的使用,在这个模块中,主要也就是实现服务器类的相关功能,在其中,也就是将socket模块和select模块进行了封装,从而创建了一些基类供人使用。

socketserver框架是一个基本的socket服务器端框架, 使用了threading来处理多个客户端的连接, 使用seletor模块来处理高并发访问, 是值得一看的python 标准库的源码之一

二、socketserver

socket不支持多并发,socketserver最主要的作用:就是实现一个并发处理,前面只是铺垫。
socketserver就是对socket的再封装。简化网络服务器版的开发。

1、socketserver一共有这么几种类型:

  • TCP 协议
class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)
  • UDP 协议
class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)
  • Unix 本机之间进程的TCP、UDP (不常用)
class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)
class socketserver.UnixDatagramServer(server_address, RequestHandlerClass,bind_and_activate=True)

类型之间的关系:

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

2、创建一个socketserver 至少分以下几步:

  • 首先,您必须创建一个请求处理类,继承BaseRequestHandlerclass类并且重写父类的handle()方法,该方法将处理传入的请求。
  • 其次,你必须实例化一个上面类型中的一个类(如TCPServer)传递服务器的地址和你上面创建的请求处理类 给这个TCPServer。
  • 然后,调用handle_request()或者serve_forever()方法来处理一个或多个请求。
ser.handle_request()  # 只处理一个请求,处理完就退出了
ser.serve_forever()   # 处理多个请求,永远执行。
  • 最后,调用server_close()关闭socket。

三、socketserver服务器端和客户端代码

服务器

import socketserver


ip_port=("127.0.0.1",8000)

class MyServer(socketserver.BaseRequestHandler):
    def Handle(self):
        print("conn is :",self.request) # conn
        print("addr is :",self.client_address) # addr

        while True:
            try:
                #收消息
                data = self.request.recv(1024)
                if not data:break
                print("收到客户端的消息是",data.decode("utf-8"))
                #发消息
                self.request.sendall(data.upper())
            except Exception as e:
                print(e)
                break


if __name__ == "__main__":
    s = socketserver.ThreadingTCPServer(ip_port,MyServer)
    s.serve_forever()

在上述的代码中,仅仅做了几件事,先定义了一个类,也就是处理请求的类,从基类baserequesthandler继承,主要就是重写其中handle方法,告知服务器如何来处理客户端的请求。

然后创建了一个线程的TCP服务器类,也就是通过多线程来进行应答客户端,然后使用一直运行的方法也就是serve_forever。

 

客服端

from socket import *


ip_port=("127.0.0.1",8000)
back_log =5
buffer_size = 1024

tcp_client = socket(AF_INET,SOCK_STREAM)
tcp_client.connect(ip_port)

while True:
    msg = input(">>>:").strip()
    if not msg:continue
    if msg =="quit":break
    tcp_client.sendall(msg.encode("utf-8"))
    data = tcp_client.recv(buffer_size)
    print("服务器命令执行的结果是:", data.decode("utf-8"))

tcp_client.close()

客户端的代码和socket编程的代码基本相同,因为在socketserver模块中,主要是创建socke的服务端,而不涉及到客户端,从而客户端不需要修改代码即可进行运行。

对比此段代码和socket编程的区别是:可以和多个client端同时进行通信.在单纯的socket编码中,同时只能一个进行通信,其他的连接会被阻塞。

四、 socketserver模块类介绍

socketserver.BaseServer(server_address, RequestHandlerClass) 主要有以下方法

fileno()  # 返回文件描述符
handle_request()  # 处理单个请求
server_forever(poll_interval=0.5)  # 每0.5秒检测一下是否发了让我shutdown的信号,做一些清理子进程或线程工作
server_close()  # 告诉server_forever(),让它停掉
server_close()  # 关闭
address_family  # 地址簇
RequestHandlerClass # 请求处理类
server_address  # IP地址
allow_reuse_address  # 允许重用地址,用于服务器断开,客户端未断开,端口需要等待几十秒才能用
# 使用如下:
server = socket.socket() #获得socket实例
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

finish_request()  # 和handle关系如下,看源码(BaseRequestHandler类构造函数):
def __init__(self, request, client_address, server):
    ......
    self.setup()
    try:
        self.handle()
    finally:
        self.finish()

在socketserver的默认请求处理器中,是接收连接,得到请求,然后就关闭连接,从而也就是客户端在循环的时候,必须每次都进行重新连接。

在上面的代码中,重写了事件处理的方法handle,在其中使用了循环,也就是一直保持和客户端的连接。

请求处理的基类是BaseRequestHandler,其中一般需要重写的方法就是handle方法,主要就是如何处理接下来的请求,在这个类里,主要有三个方法,一个是setup,handle和finish方法,在调用这个类的时候,先调用setup进行一些初始化的工作,然后调用handle方法进行处理请求,然后调用finish方法,做一些关闭连接什么的;在这个里面最主要的参数self.request,也就是请求的socket对象,其中可以发送消息sendall或者send,接收消息的recv

在请求处理的子类中有两个,一个是SreamRequestHandle和DatagramRequestHandle,在这个里面重写了基类的setup方法和finish方法,handle方法没有重写,因为这个是留给用户做处理请求的方法,在这里提供了几个参数,一个self.rfile用来读取数据的句柄,而self.wfile是用来发送消息的句柄。

在使用rfile和wfile时候需要注意,在客户端发送消息的时候需要自己加上回车,而在服务器端需要使用readline方法来进行读取,也就是读取一行,如下所示服务器端代码:

#!/usr/bin/env python  
  
import SocketServer  
import time  
  
  
HOST = '127.0.0.1'  
PORT = 8000
  
class MyHandler(SocketServer.StreamRequestHandler):  
    def handle(self):  
        while True:  
            data = self.rfile.readline().strip()  
            print(data) 
            print(self.client_address)
            self.wfile.write( ' %s %s ' % (data,time.ctime()))  
            if data == 'exit':  
                break  
  
s = SocketServer.ThreadingTCPServer((HOST,PORT),MyHandler)  
s.serve_forever() 

在使用rfile的时候,需要使用readline方法,否则会卡住请求的处理,而在客户端代码如下: 

#!/usr/bin/env python  
import socket  
  
  
HOST = '127.0.0.1'  
PORT = 8000
  
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
s.connect((HOST,PORT))  
while True:   
    kel = raw_input('>>>')  
    s.sendall(kel + '\n')  
    print s.recv(1024)  
    if kel == 'exit':  
        break  
s.close()  

在进行sendall数据的时候,需要加上''\n',表示此次发送的数据结束。

最基类的是服务器类BaseServer类,其中定义了相关的方法,不能直接使用这个类,只能用来继承,在子类中有俩,是作为同步服务器类使用,TCPServer和UDPServer,这两个类主要是和socket编程的时候是相同的,也就是会阻塞连接。TCPServer有一个子类为UNIXStreamServer,在UDPServer有一个子类为UnixDatagramServer,在最后的两个子类中,是基于文件同步的tcp和udp服务器。

两个混合类,一个是ForkingMixin,主要是用fork的,产生一个新的进程去处理;一个是ThreadingMixin,产生一个新的线程,主要是用来提供异步处理的能力,其余tcpserver和udpserver组合,又产生了新的四个类,从而提供异步处理的能力。

在使用混合类和服务器类的时候,注意混合类需要写在前面,因为混合类重写了服务器类的方法,从而需要放在第一个位置。

总结:

python中的socketserver模块,主要是用来提供服务器类,并且提供异步处理的能力。

 

 类似资料:

相关阅读

相关文章

相关问答