[Python]SocketServer模块

        SocketServer是标准库中一个高级别的模块。用于简化网络客户与服务器的实现。模块中,已经实现了一些可供使用的类。

        我们将再次实现之前的那个基本TCP的例子。你会注意到新实现与之前有很多相似之处,但你也要注意到,现在很多繁杂的事情已经被封装好了,你不用再去关心那个样板代码了。例子给出的是一个最简单的同步服务器。

        为了要隐藏实现的细节。我们现在写程序时会使用类,这是与之前代码的另一个不同。用面向对象的方法可以帮助我们更好的组织数据与逻辑功能。你也会注意到,我们的程序现在是“事件驱动”了。这就意味着,只有在事件出现的时候,程序才有“反应”。

在之前的服务循环中,我们阻塞等待请求,有请求来的时候就处理请求,然后再回去继续等待。现在的服务循环中,就不用在服务器里写代码了,改成定义一个处理器,服务器在收到进来的请求的时候,可以调用你的处理函数。

SocketServer模块的类

Class

Description

BaseServer

Contains core server functionality and hooks for mix-in classes; used only for derivation so you will not create instances of this class; useTCPServer or UDPServer instead

TCPServer/UDPServer

Basic networked synchronous TCP/UDP server

UnixStreamServer/UnixDatagramServer

Basic file-based synchronous TCP/UDP server

ForkingMixIn/Threading MixIn

Core forking or threading functionality; used only as mix-in classes with one of the server classes to achieve some asynchronicity; you will not instantiate this class directly

ForkingTCPServer/ForkingUDPServer

Combination of ForkingMixIn and TCPServer/UDPServer

ThreadingTCPServer/ThreadingUDPServer

Combination of ThreadingMixIn and TCPServer/UDPServer

BaseRequestHandler

Contains core functionality for handling service requests; used only for derivation so you will not create instances of this class; useStreamRequestHandler or DatagramRequestHandler instead

StreamRequest Handler/DatagramRequest-Handler

Implement service handler for TCP/UDP servers


1. 创建一个SocketServerTCP服务器:

       在代码中,先导入我们的服务器类,然后像之前一样定义主机常量。主机常量后就是我们的请求处理器类,然后是启动代码。在下面的代码片断中可以看到更多细节。

#! /usr/bin/env python
#coding=utf-8

from SocketServer import (TCPServer as TCP,StreamRequestHandler as SRH)
from time import ctime

HOST = ''
POST = 12345
ADDR = (HOST,POST)

class MyRequestHandler(SRH):
    def handle(self):
        print('...connected from:',self.client_address)
        self.wfile.write('[%s] %s'%(ctime(),self.rfile.readline()))
        
tcpServ = TCP(ADDR,MyRequestHandler)
print('waiting for connection...')
tcpServ.serve_forever()

        我们从SocketServerStreamRequestHandler类中派生出一个子类,并重写handle()函数。在BaseRequest类中,这个函数什么也不做。在有客户消息进来的时候,handle()函数就会被调用。StreamRequestHandler 类支持像操作文件对象那样操作输入输出套接字。我们可以用readline()函数得到客户消息,用write()函数把字符串发给客户。

        为了保持一致性,我们要在客户与服务器两端的代码里都加上回车与换行。实际上,你在代码中看不到这个,因为,我们重用了客户传过来的回车与换行。

2. 创建SocketServerTCP客户端

#! /usr/bin/env python
#coding=utf-8
from socket import *

HOST = 'localhost'
PORT = 12345
BUFSIZE = 1024
ADDR = (HOST,PORT)

while 1:
    tcpCliSock = socket(AF_INET,SOCK_STREAM)
    tcpCliSock.connect(ADDR)
    data = raw_input("> ")
    if not data:
        break
    tcpCliSock.send("%s\r\n"%data)
    data = tcpCliSock.recv(BUFSIZE)
    if not data:
        break
    print data.strip()
    tcpCliSock.close()
    

         SocketServer的请求处理器的默认行为是接受连接,得到请求,然后就关闭连接。这使得我们不能在程序的运行时,一直保持连接状态,要每次发送数据到服务器的时候都要创建一个新的套接字。这种行为使得TCP 服务器的行为有些像UDP服务器。不过,这种行为也可以通过重写请求处理器中相应的函数来改变。

        现在,我们的客户端有点完全不一样了(我们得每次都创建一个连接)。其它的小区别在服务器代码的逐行解释中已经看到了:我们使用的处理器类像文件一样操作套接字,所以我们每次都要发送行结束字符(回车与换行)。服务器只是保留并重用我们发送的行结束字符。当我们从服务器得到数据的时候,我们使用strip()函数去掉它们,然后使用print语句提供的回车。

3.   使用SocketServer处理多连接

        上面的例子一次只能连接一个客户机并出力它的请求,如果要处理多连接问题,那么有三种主要的方法能实现这个目的:分叉(forking)、线程(threading)以及异步I/O(asynchronous I/O)。通过对SocketServer服务器使用混入类(mix-in class),派生进程和线程很容易处理。即使要自己实现它们,这些方法也很容易使用。它们确实有缺点:分叉占据资源,并且如果有太多的客户端时分叉不能很好分叉(尽管如此,对于合理数量的客户端,分叉在现代的UNIX或者Linux系统中是很高效的,如果有一个多CPU系统,那系统效率会更高);线程处理能导致同步问题。使用SocketServer框架创建分叉或者线程服务器非常简单: 

分叉SocketServer服务器:

#! /usr/bin/env python
#coding=utf-8

from SocketServer import (TCPServer as TCP,
                          StreamRequestHandler as SRH,
                          ForkingMixIn as FMI)
from time import ctime


class Server(FMI,TCP):
    pass

class MyHandler(SRH):
    def handle(self):
        print "...connected from:",self.client_address
        self.wfile.write("[%s] %s"%(ctime(),self.rfile.readline()))
        

HOST = ''
PORT = 12345
#BUFSIZE = 1024
ADDR = (HOST, PORT)

tcpServ = Server(ADDR,MyHandler)
tcpServ.serve_forever()
tcpServ.close()
                    
多线程SocketServer服务器:
#! /usr/bin/env python
#coding=utf-8

from SocketServer import (TCPServer as TCP,
                          StreamRequestHandler as SRH,
                          ThreadingMixIn as TMI)
                        
from time  import ctime

class Server(TMI,TCP):
    pass

class MyHandler(SRH):
    def handle(self):
        print("...connected from :",self.client_address)
        self.wfile.write("[%s] %s"%(ctime(),self.rfile.readline()))
        
host = 'localhost'
port = 12345
addr = (host,port)

tcpServ = Server(addr,MyHandler)
tcpServ.serve_forever()
tcpServ.close()


REF:

1,http://blog.sina.com.cn/s/blog_6826662b0100yf4h.html

2,Core Python Programming



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值