SocketServer.py这个文件700来行,除去注释大概300来行左右,据网友称该模块实乃学习类继承之典范。
要理解这个模块真的非常的简单,也让人体会到同步编程的简单性。另外我现在比较关注web编程,所以会比较关注tcp部分忽略掉udp(源码版本Python2.7.11)

类继承关系

不说别的,单单看到这张图就能唬住好多人,感觉很高大上有没有

1
2
3
4
5
6
7
8
9
10
11
12
13
+------------+
| BaseServer |
+------------+
|
v
+-----------+ +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+ +------------------+
|
v
+-----------+ +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+ +--------------------+

同步处理类比

服务端嘛,请允许我污一下,就像古装剧里面的怡红院,都有个门口接客的老鸨,有客户来就引进去然后交给失足少女。老鸨就是服务端的监听socket,失足少女就是具体处理的业务逻辑。可以写成如下伪代码

1
2
3
4
5
6
7
import socket
s = socket.socket()
s.bind(('localhost',9999))
s.listen(2048)
while True:
client,addr = s.accept()
handle(client,addr,s)

可以说socketserver就是由上面最基本的步骤,为了扩展性而写的代码。上面的伪代码handle(client,addr,s)是一部分,上面的分为另外一部分。

socketserver因为是同步的,所以理解起来比asyncore要简单许多。而且注释写的非常详尽,我就不详述BaseServer/BaseRequestHandler的类方法了,说一下几个有点意思的地方。

  1. BaseServer部分基本就代表了监听套接字,然而还是提供了2个对连接套接字的方法,就是处理完成之后关闭啦~~shutdown_request/close_request
  2. handle_request方法和server_forever是非常相似的,区别就是handler_request只相应一个请求。大概是用来调试吧。该函数还调起了一个特别垃圾的handle_timeout函数。看名字是不是以为是对连接套接字的超时处理函数-_-,实际上是等多久还没来一个新连接会触发,可是这个需求基本没有。所以我非常认为这个handle_request仅仅用来调试一次而已
  3. 上面的伪代码并没有用到select,为什么socketserver就用到了,其实如果只是为了处理tcp那么此处是没有必要用select的,因为tcp需要accept而udp是直接recvfrom就好了。用select只是为了通知有数据来了。都是为了适应多种情况才用的select。另外需要注意的是它不是用的文件描述符,是直接用的self,这里只要self实现了file_no方法就可以了(参照官方文档)。还有select另外套了一个_eintr_retry函数。这里是因为某些情况下select会被操作系统中断而引发异常(比如使用single)
  4. 可以很明显的看到实现的ThreadingTCPServer是通过继承的方式实现的,实质就是处理连接套接字的时候使用多线程或者多进程,可以想到要实现相同的效果用装饰器同样是可以的
  5. StreamRequestHandler中使用了socket.makefile将连接套接字分成了读和写2个类文件对象(只能是阻塞socket)。可以感受到的优势就是read(num)返回的长度是准确的,recv就没有这个优势
  6. 用到了threading.Event,这个地方我是没多搞明白。调用shutdown方法会中断循环从而关闭服务。一般会在处理线程调用这个。如果不是在处理线程调用那么会发生死锁。。。我能想到的只有这里

    socks5 DEMO(引用自http://xiaoxia.org/2011/03/29/written-by-python-socks5-server/)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    import socket, select, SocketServer, struct

    class Socks5Handle(SocketServer.StreamRequestHandler):
    def tcprelay(self, sock, remote):
    fdset = [sock, remote]
    while True:
    r, w, e = select.select(fdset, [], [])
    if sock in r:
    if remote.send(sock.recv(4096)) <= 0: break
    if remote in r:
    if sock.send(remote.recv(4096)) <= 0: break

    def handle(self):
    try:
    print('socks connection from ', self.client_address)
    sock = self.connection
    # 1. Version
    sock.recv(262)
    sock.send(b"\x05\x00")
    # 2. Request
    data = self.rfile.read(4)
    mode = ord(data[1])
    addrtype = ord(data[3])
    if addrtype == 1: # IPv4
    addr = socket.inet_ntoa(self.rfile.read(4))
    elif addrtype == 3: # Domain name
    addr = self.rfile.read(ord(sock.recv(1)[0]))
    port = struct.unpack('>H', self.rfile.read(2))
    reply = b"\x05\x00\x00\x01"
    try:
    if mode == 1: # 1. Tcp connect
    remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    remote.connect((addr, port[0]))
    print('Tcp connect to', addr, port[0])
    else:
    reply = b"\x05\x07\x00\x01" # Command not supported
    local = remote.getsockname()
    reply += socket.inet_aton(local[0]) + struct.pack(">H", local[1])
    except socket.error:
    # Connection refused
    reply = '\x05\x05\x00\x01\x00\x00\x00\x00\x00\x00'
    sock.send(reply)
    # 3. Transfering
    if reply[1] == '\x00': # Success
    self.tcprelay(sock, remote)
    except socket.error:
    print('socket error')


    def main():
    server = SocketServer.ThreadingTCPServer(('', 1081), Socks5Handle)
    server.serve_forever()


    if __name__ == '__main__':
    main()

和asyncore对比

asyncore和socketserver同样实现了并发。对比一下
1.从名字都可以看出来server。socketserver只能用来实现server,而asyncore还可以实现客户端
2.socketserver实现了多线程和多进程,asyncore框架是单线程事件循环

相关资料

SocketServer – Creating network servers.