第十一章:网络通信-socketserver:创建网络服务器-回送示例

11.5.5 回送示例
下面这个例子实现了一对简单的服务器/请求处理器,将接受TCP连接,并回送客户发送的所有数据。首先来看看请求处理器。

import logging
import sys
import socketserver

logging.basicConfig(level=logging.DEBUG,
                    format='%(name)s:%(message)s',
                    )

class EchoRequestHandler(socketserver.BaseRequestHandler):

    def __init__(self,request,client_address,server):
        self.logger = logging.getLogger('EchoRequestHandler')
        self.logger.debug('__init__')
        socketserver.BaseRequestHandler.__init__(self,request,
                                                 client_address,
                                                 server)
        return

    def setup(self):
        self.logger.debug('handle')

        # Echo the data bvack to the client.
        data = self.request.recv(1024)
        self.logger.debug('recv()->"%s"',data)
        self.request.send(data)
        return

    def finish(self):
        self.logger.debug('finish')
        return socketserver.BaseRequestHandler.finish(self)

# 真正需要实现的只有一个方法,即EchoRequestHandler.handle(),不过这里包含了前面
# 提到的所有方法以便展示调用顺序。EchoServer类的工作与TCPServer相同,只不过在
# 调用各个方法时会记录日志。
class EchoServer(socketserver.TCPServer):

    def __init__(self,server_address,handler_class=EchoRequestHandler,
                 ):
        self.logger = logging.getLogger('EchoServer')
        self.logger.debug('__init__')
        socketserver.TCPServer.__init__(self,server_address,
                                        handler_class)
        return

    def server_activate(self):
        self.logger.debug('server_activate')
        socketserver.TCPServer.server_activate(self)
        return

    def server_forever(self,poll_interval=0.5):
        self.logger.debug('waiting for request')
        self.logger.info(
            'Handling requests,press <Ctrl-C> to quit'
            )
        socketserver.TCPServer.serve_forever(self,poll_interval)
        return

    def handle_request(self):
        self.logger.debug('handle_request')
        return socketserver.TCPServer.handle_request(self)

    def verify_request(self,request,client_address):
        self.logger.debug('verify_request(%s,%s)',
                          request,client_address)
        return socketserver.TCPServer.verify_request(
            self,request,client_address,
            )

    def process_request(self,request,client_address):
        self.logger.debug('process_request(%s,%s)',
                          request,client_address)
        return socketserver.TCPServer.process_request(
            self,request,client_address,
            )

    def server_close(self):
        self.logger.debug('server_close')
        return socketserver.TCPServer.server_close(self)

    def finish_request(self,request,client_address):
        self.logger.debug('finish_request(%s,%s)',
                          request,client_address)
        return socketserver.TCPServer.finish_request(
            self,request,client_address,
            )

    def close_request(self,request_address):
        self.logger.debug('close_request(%s)',request_address)
        return socketserver.TCPServer.close_request(
            self,request_address,
            )

    def shutdown(self):
        self.logger.debug('shutdown()')
        return socketserver.TCPServer.shutdown(self)

# 最后一步是增加一个主程序,这会建立服务器,使它在一个线程中运行,并且向这个
# 服务器发送数据以展示回送数据时会调用哪些方法。

if __name__ == '__main__':
    import socket
    import threading

    address = ('localhost',0) # Let the kernel assign a port.
    server = EchoServer(address,EchoRequestHandler)
    ip,port = server.server_address  # What port was assigned?

    # Start the server in a thread.
    t = threading.Thread(target=server.serve_forever)
    t.setDaemon(True)  # Don't hang on exit.
    t.start()

    logger = logging.getLogger('client')
    logger.info('Server on %s:%s',ip,port)

    # Connect to the server.
    logger.debug('creating socket')
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    logger.debug('conneting to server')
    s.connect((ip,port))

    # Send the data.
    message = 'Hello,world'.encode()
    logger.debug('sending data: %r',message)
    len_sent = s.send(message)

    # Receive a response.
    logger.debug('waiting for response')
    response = s.recv(len_sent)
    logger.debug('response from server:%r',response)

    # Clean up.
    server.shutdown()
    logger.debug('closing socket')
    s.close()
    logger.debug('done')
    server.socket.close()

运行这个程序会生成以下输出:
在这里插入图片描述

每次程序运行时使用的端口号都会改变,因为内核会自动分配可用的端口。要让服务器每次监听一个特定的端口,需要在地址元组中提供该端口号而不是0。

以下是这个服务器的“压缩”版本,这里没有日志记录调用。请求处理器类中只需要提供handle()方法。

import socketserver

class EchoRequestHandler(socketserver.BaseRequestHandler):

    def handle(self):
        # Echo the data back to the client.
        data = self.request.recv(1024)
        self.request.send(data)
        return


if __name__ == '__main__':
    import socket
    import threading

    address = ('localhost',0)  # Let the kernel assign a port.
    server = socketserver.TCPServer(address,EchoRequestHandler)
    ip,port = server.server_address # What port was assigned?

    t = threading.Thread(target=server.serve_forever)
    t.setDaemon(True) # Don't hang on exit.
    t.start()

    # Connect to the server.
    s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    s.connect((ip,port))

    # Send the data.
    message = 'Hello,world'.encode()
    print('Sending : {!r}'.format(message))
    len_sent = s.send(message)

    # Receive a response.
    response = s.recv(len_sent)
    print('Received: {!r}'.format(response))

    # Clean up.
    server.shutdown()
    s.close()
    server.socket.close()

这里并不需要特殊的服务器类,因为TCPServer会处理所有服务器需求。
运行结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值