前言

    在学完socket之后,可以实现简单的服务端与客户端的交互,但是基础的socket只能实现一个客户端与一个服务端的交互,并不能实现多个客户端同时与一个服务端进行交互,所以便出现了socketserver模块.

1.socketserver简介

    socket模块不能实现并发处理,socketserver是对socket的一个封装,其最主要的作用就是实现并发处理.
    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)

注:我们最常用的就是TCP和UDP协议.

类型之间的关系:
+------------+
| BaseServer |
+------------+
      |
      v
+-----------+        +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+        +------------------+
      |
      v
+-----------+        +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+        +--------------------+

其中,BaseServer是基类.

2.创建socketserver

    我们来看创建一个socketserver需要哪些步骤.
    socketserver创建步骤:

  • 第一步:必须自己创建一个请求处理类,让这个类继承BaseRequestHandler(),并且重写父类的handle()方法.
  • 第二步:必须实例化一个TCPServer(这里以TCPServer为例),并且传递server_ip和上面创建的请求处理类给这个TCPServer对象.
  • 第三步:调用handle_request()或者serve_forever()方法来处理一个或多个请求。
handle_request()方法是处理一个请求,我们一般不用这个
server_forever()方法是用来处理多个请求,我们一般用的就是这个
  • 第四步:调用server_close()来关闭socket.

3.实现一个简单的SocketServer

    在上一个标题中我们知道了创建一个SocketServer的步骤,接下来我们就来实现一个SocketServer.
服务端代码----socketserver_server.py

"""
    创建一个socketserver需要以下几个步骤:
        1.必须自己创建一个请求处理类,这个类要继承BaseRequestHandler,并且重写父类的handle方法
        2.必须实例化一个TCPserver(这是socketserver的一种类型,还有UDPserver),并且传递server_ip和上面创建的请求处理类
        3.调用handle_request()或者server_forever()方法来处理一个或多个请求
            注:handle_request()是处理一个请求,server_forever()是处理多个请求
        4.调用server_close()关闭socket
"""
import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):  # 创建自己的一个请求处理类,继承BaseRequestHandler
    def handle(self):                                 # 重写handle()函数
        # 跟客户端所有的交互都是在handle里完成的
        # 每一个请求过来都会实例化MyTCPHandler
        print("conn is: ",self.request)               # self.request就是socket中的conn
        print('addr is: ',self.client_address)        # self.client_address就是Socket中的addr

        # 接下来就是接收客户端的请求,并且与客户端进行数据交互
        while True:
            try:
                data = self.request.recv(1024)
                if not data:
                    break
                print('收到的客户端的消息是:',data.decode())
                self.request.sendall(data.upper())

            except ConnectionResetError as e:
                print('error--',e)
                break


if __name__ == '__main__':
    server = socketserver.TCPServer(('localhost',9966),MyTCPHandler)
    server.serve_forever()
代码解释:

按照socketserver创建流程我们来解释一下代码.
(1) 创建一个自己的请求处理类,这个类要继承BaseRequestHandler:

class MyTCPHandler(socketserver.BaseRequestHandler):  # 创建自己的一个请求处理类,继承BaseRequestHandler

(2) 重写BaseRequestHandler类中的handle方法:

def handle(self):                                 # 重写handle()函数
        # 跟客户端所有的交互都是在handle里完成的
        # 每一个请求过来都会实例化MyTCPHandler
        print("conn is: ",self.request)               # self.request就是socket中的conn
        print('addr is: ',self.client_address)        # self.client_address就是Socket中的addr

        # 接下来就是接收客户端的请求,并且与客户端进行数据交互
        while True:
            try:
                data = self.request.recv(1024)
                if not data:
                    break
                print('收到的客户端的消息是:',data.decode())
                self.request.sendall(data.upper())

            except ConnectionResetError as e:
                print('error--',e)
                break

这里需要说明的是:

  • 服务端跟客户端的交互都是在这个handle()方法中完成的
  • 每一个客户端的请求连接后都会实例化MyTCPHandler
  • self.request 就是socket中的conn
  • self.client_address 就是socket中的addr

(3) 实例化一个TCPserver,并且传递server_ip和上面创建的请求处理类

server = socketserver.TCPServer(('localhost',9966),MyTCPHandler)

注:这里会传入两个参数,第一个参数是ip和端口,第二个参数是我们创建的请求处理类.
其实还有一个参数bind_and_activate=True,但这个我们现在用不到,我也没有去做研究,也不知道这个参数具体代表什么.有知道的小伙伴可以在评论中分享一下,感谢大家.

(4)调用serve_forever()来处理多个请求

server.serve_forever()

客户端代码----socketserver_client.py

socketserver主要是针对服务端来做的,所以对于客户端代码,并没有太多的改变,就用之前写过的一个代码就可以.

'''
    客户端
'''
import socket

client = socket.socket()        # 创建Socket对象,声明socket类型

client.connect(('localhost',9966))
while True:
    msg = input("请输入: ")

    if len(msg) == 0:
        continue

    client.send(msg.encode('utf-8'))

    data = client.recv(1024)
    print('客户端接收的数据为: ',data.decode())


client.close()

客户端代码就不做过多解释了.

运行结果:

    我们开启一个终端来运行服务端代码,另外开启两个终端,每个终端都运行客户端代码,以此来实现并发的效果.结果如下:

服务端:

python连接rocketmq认证账号密码 python serversocket_请求处理

客户端1:

python连接rocketmq认证账号密码 python serversocket_请求处理_02


客户端2:

python连接rocketmq认证账号密码 python serversocket_客户端_03

警告!

        到这里我们发现客户端1正常运行,而客户端2处于等待状态,当客户端1关闭时,客户端2才运行,这个效果和socket也没有区别啊,也没有体现出多并发的效果.
        原来啊,要想真正实现并发的效果,只需要改动一个地方就可以.将socketserver.TCPServer改成socketserver.ThreadingTCPServer就可以了.
        socketserver.ThreadingTCPServer才是真正实现多并发的socketserver.下面来看效果.

4.实现一个真正多并发的socketserver

服务端代码----socketserver_server.py

"""
    创建一个socketserver需要以下几个步骤:
        1.必须自己创建一个请求处理类,这个类要继承BaseRequestHandler,并且重写父类的handle方法
        2.必须实例化一个TCPserver(这是socketserver的一种类型,还有UDPserver),并且传递server_ip和上面创建的请求处理类
        3.调用handle_request()或者server_forever()方法来处理一个或多个请求
            注:handle_request()是处理一个请求,server_forever()是处理多个请求
        4.调用server_close()关闭socket
"""
import socketserver

class MyTCPHandler(socketserver.BaseRequestHandler):  # 创建自己的一个请求处理类,继承BaseRequestHandler
    def handle(self):                                 # 重写handle()函数
        # 跟客户端所有的交互都是在handle里完成的
        # 每一个请求过来都会实例化MyTCPHandler
        print("conn is: ",self.request)               # self.request就是socket中的conn
        print('addr is: ',self.client_address)        # self.client_address就是Socket中的addr

        # 接下来就是接收客户端的请求,并且与客户端进行数据交互
        while True:
            try:
                data = self.request.recv(1024)
                if not data:
                    break
                print('收到的客户端的消息是:',data.decode())
                self.request.sendall(data.upper())

            except ConnectionResetError as e:
                print('error--',e)
                break


if __name__ == '__main__':
    server = socketserver.ThreadingTCPServer(('localhost',9966),MyTCPHandler)   # ThreadingTCPServer才是可以真正的实现多并发
    server.serve_forever()

客户端代码----socketserver_client.py

客户端代码不变

'''
    客户端
'''
import socket

client = socket.socket()        # 创建Socket对象,声明socket类型

client.connect(('localhost',9966))
while True:
    msg = input("请输入: ")

    if len(msg) == 0:
        continue

    client.send(msg.encode('utf-8'))

    data = client.recv(1024)
    print('客户端接收的数据为: ',data.decode())


client.close()
运行结果

服务端:

python连接rocketmq认证账号密码 python serversocket_请求处理_04

客户端1:

python连接rocketmq认证账号密码 python serversocket_服务端_05


客户端2:

python连接rocketmq认证账号密码 python serversocket_客户端_06


    到这里,我们真正实现了一个多并发的socketserver.