使用多路复用套接字I/O提升性能之——ForkingMixIn 《Python网络编程攻略》

本文介绍了一种基于Python的异步服务器设计方案,通过ForkingMixIn类实现了多客户端并发处理,确保服务器能高效响应不同客户端的请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前一例不同,本次考虑多个客户端连接服务器的情况,且可以异步通信。

服务器不需要在阻塞模式中处理客户发出的请求,而是单独处理每个请求。如果某个客户端接受或处理数据花了很长时间,服务器无需等待处理完成,即可使用另外的线程和其他客户端进行通信。

实现方法

  1. SocketServer模块:利用SocketServer模块提供的类可以直接实现TCP、UDP及其他协议服务器。
  2. ForkingMixIn类,用于异步处理客户端。
  3. 我们创建ForkingServer类,继承TCPServer和ForkingMixIn类。继承TCPServer可以省去手动创建服务器操作,如创建套接字、绑定地址和监听连接等;继承ForkingMinIn用于异步处理。
  4. ForkingServer类还要创建一个请求处理程序ForkingServerRequestHandler(继承自SocketServer库中的BaseRequestHandler类),说明如何处理客户端请求。
  5. 客户端ForkingClient使用面向对象的方式编写。

代码 2_1_forking_mixin_socket_server.py

'''
Created on 2017-2-28

@author: lenovo
'''
import os
import socket
import threading
import SocketServer

SERVER_HOST = 'localhost'
SERVER_PORT = 0 # Tells the kernel to pick up a port dynamically
BUF_SIZE = 1024
ECHO_MSG = 'Hello echo server!'

class ForkingClient():
    """ A client to test forking server"""
    def __init__(self,ip,port):
        # Create a socket
        self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        self.sock.connect((ip,port))

    def run(self):
        """Client playing with the server"""
        #send the data to server
        current_process_id = os.getpid()
        print 'PID %s Sending echo message to the server : "%s"' %(current_process_id,ECHO_MSG)
        sent_data_length = self.sock.send(ECHO_MSG)
        print "Sent: %d characters, so far..." %sent_data_length

        # Display server response
        response = self.sock.recv(BUF_SIZE)
        print "PID %s received: %s" %(current_process_id,response[5:])

    def shutdown(self):
        self.sock.close()

class ForkingServerRequestHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        # Send the echo back to the client
        data = self.request.recv(BUF_SIZE)
        current_process_id = os.getpid()
        response = '%s: %s' % (current_process_id,data)
        print "Server sending response [current_process_id: data] = [%s]" %response
        self.request.send(response)
        return
class ForkingServer(SocketServer.ForkingMixIn,SocketServer.TCPServer,):
    """Nothing to add here, inherited everything necessary form parents."""
    pass

def main():
    #Launch the server
    server = ForkingServer((SERVER_HOST,SERVER_PORT),ForkingServerRequestHandler)
    ip,port = server.server_address #Retrive the port number
    server_thread = threading.Thread(target=server.serve_forever)
    server_thread.setDaemon(True)
    server_thread.start()
    print 'Server loop running PID: %s' %os.getpid()

    #Launch the client
    client1 = ForkingClient(ip,port)
    client1.run()

    client2 = ForkingClient(ip,port)
    client2.run()

    #clean them up
    server.shutdown()
    client1.shutdown()
    client2.shutdown()
    server.socket.close()
if __name__ == '__main__':
    main()

运行结果

xx@ubuntu:~$ python 2_1_forking_mixin_socket_server.py 
Server loop running PID: 2545
PID 2545 Sending echo message to the server : "Hello echo server!"
Sent: 18 characters, so far...
Server sending response [current_process_id: data] = [2547: Hello echo server!]
PID 2545 received:  Hello echo server!
PID 2545 Sending echo message to the server : "Hello echo server!"
Sent: 18 characters, so far...
Server sending response [current_process_id: data] = [2548: Hello echo server!]
PID 2545 received:  Hello echo server!
xx@ubuntu:~$

原理分析

主线程中创建了一个ForkingServer实例,作为守护进程在后台运行,然后再创建两个客户端与服务器交互。

不难发现,服务器每次响应请求的进程是不同,一个是2547,一个是2548,可见服务器对每个客户端请求生成了不同的进程去去处理。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值