Python学习——socketserver实现多并发

并发与并行的区别:(来自百度百科)

并发:并发当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。.这种方式我们称之为并发(Concurrent)。

并行:当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。

区别:并发和并行是即相似又有区别的两个概念,并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔内发生。在多道程序环境下,并发性是指在一段时间内宏观上有多个程序在同时运行,但在单处理机系统中,每一时刻却仅能有一道程序执行,故微观上这些程序只能是分时地交替执行。倘若在计算机系统中有多个处理机,则这些可以并发执行的程序便可被分配到多个处理机上,实现并行执行,即利用每个处理机来处理一个可并发执行的程序,这样,多个程序便可以同时执行。

以上来自于百度百科,简单来说,并发和并行在宏观上都体现为多个线程同时运行。若这些线程运行在单核处理器上,则这些线程只能交替运行,此时为并发;若这些线程运行在多核处理器上,此时每个线程可以占用一个处理器,这些线程同时运行,叫做并行。

利用socketserver实现server多并发

(关于socketserver的详细讲解,见官方文档:21.21. socketserver — A framework for network servers

socketserver是python中一个简化编写server的模块。包含四个具体的类:

  1. class socketserver.TCPServer(server_addressRequestHandlerClassbind_and_activate=True):                                                                                                                                                                                                                        This uses the Internet TCP protocol, which provides for continuous streams of data between the client and server. If bind_and_activate is true, the constructor automatically attempts to invoke server_bind() andserver_activate(). The other parameters are passed to the BaseServer base class.                                                                                                                                                                                                                                                                                                       这个类使用TCP协议,能够在客户和服务器之间提供连续的数据流。如果bind_and_activatetrue,则构造函数会自动尝试调用server_bind()和server_activate()。 其他参数将传递给BaseServer基类。                                                                  
  2. class socketserver.UDPServer(server_addressRequestHandlerClassbind_and_activate=True)

    This uses datagrams, which are discrete packets of information that may arrive out of order or be lost while in transit. The parameters are the same as for TCPServer.                                                                                                                               这个类使用UDP协议。                                                                                                                                                             

  3. class socketserver.UnixStreamServer(server_addressRequestHandlerClassbind_and_activate=True)                              

  4. class socketserver.UnixDatagramServer(server_addressRequestHandlerClassbind_and_activate=True)                                                                                                                                                                                                                           These more infrequently used classes are similar to the TCP and UDP classes, but use Unix domain sockets; they’re not available on non-Unix platforms. The parameters are the same as for TCPServer.                                                                   第三个类和第四个类与前面1、2所述的TCP、UDP类类似,但之使用在Unix平台上。                                                             

如何使用socketserver

创建一个socketserver至少需要以下几步:

  1. 我们必须要创建一个请求处理类,并且这个类要继承BaseRequestHandler,并且还要重写父类中的Handler()方法;
  2. 我们实例化一个实例(上面四个中的其中一个),并且传递server ip和上面创建的请求处理类给这个实例;
  3. 调用调用handle_request() 或者serve_forever()模块。其中:                                                                          server.handle_request() # 只处理一个请求                                                                                                        server.handle_forever() # 处理多个请求
  4. 关闭server(server.close())

服务器端代码示例:

import socketserver
from bs4 import BeautifulSoup

class MyTCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        while True:
            try:
                self.data = self.request.recv(1024).strip()
                print("{} wrote:".format(self.client_address[0]))
                print(self.data)
                self.request.send(self.data.upper())
            except ConnectionResetError as e:
                print("err",e)
                break
if __name__ == "__main__":
    HOST, PORT = "localhost", 9999
    # Create the server, binding to localhost on port 9999
    server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler)
    server.serve_forever()

客户端:

__author__ = "Scott Knight"

import socket
client = socket.socket()
 
#client.connect(('192.168.16.200',9999))
client.connect(('localhost',9999))

while True:
    cmd = input(">>:").strip()
    if len(cmd) == 0: continue
    client.send(cmd.encode("utf-8"))
    cmd_res_size = client.recv(1024) ##接受命令结果的长度
    print("命令结果大小:",cmd_res_size)
    received_size = 0
    received_data = b''
    while received_size < int(cmd_res_size.decode()) :
        data = client.recv(1024)
        received_size += len(data) #每次收到的有可能小于1024,所以必须用len判断
        #print(data.decode())
        received_data += data
    else:
        print("cmd res receive done...",received_size)
        print(received_data.decode())


client.close()

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

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

猜你喜欢

转载自blog.csdn.net/weixin_41931548/article/details/87823549
今日推荐