day8-socketserver使用

概述

我们之前所学的socket都是一个人上传和下载文件,它不支持多用户,多并发同时处理,所以就出现了SocketServer,它产生的原因就是能够实现并发处理。

SocketServer模块简化了编写SocketServer的任务

SocketServer的四种类

TCPServer

说明:使用Internet TCP协议,它在客户端和服务器之间提供连续的数据流。如果bind_and_activate为true,则构造函数自动尝试调用server_bind()和server_activate().其他参数传递给BaseServer基类。

class socketserver.TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)

UDPServer

说明:使用UDP协议,这些数据包是离散的数据包,所以可能不按顺序到达或在传输途中丢失。参数与TCPServer相同

class socketserver.UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)

UnixStreamServer和UnixDatagramServer

说明:这些较少使用的类与TCP和UDP类相似,但使用Unix域socket;他们在非Unix平台上不可用。参数与TCPServer相同

class socketserver.UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)
class socketserver.UnixDatagramServer(server_address, RequestHandlerClass,bind_and_activate=True)

小结

这四个类同步处理请求;每个请求必须在下一个请求可以开始之前完成。如果每个请求需要很长时间才能完成,这是不合适的,因为它需要大量的计算,或者因为它返回了很多客户端处理缓慢的数据。解决方案是创建一个单独的进程或线程来处理每个请求; ForkingMixIn和ThreadingMixIn混合类可以用来支持异步行为。

继承图中有五个类,其中四个代表四种类型的同步服务器

+------------+
| BaseServer |
+------------+
      |
      v
+-----------+        +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+        +------------------+
      |
      v
+-----------+        +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+        +--------------------+

注意:UnixDatagramServer派生自UDPServer,而不是来自UnixStreamServer - IP和Unix流服务器之间的唯一区别是地址族,这在两个Unix服务器类中都是重复的。

创建SocketServer的步骤

  • 首先,您必须通过继承BaseRequestHandler类并重写handle()方法来创建请求处理类;这个方法将处理传入的请求。
  • 其次,您必须实例化一个Server类(4种其中1种),并将参数Server的IP地址和上面创建的请求处理类传递给Server类。
  • 然后调用服务器对象的handle_request()或server_forever()方法来处理一个或多个请求。
  • 最后,调用server_close()关闭socket。

简单SocketServer代码实现

服务器端

思路:创建Handle处理类 => 重写handle()方法(处理传入请求) => 实例化Server类 => 调用server_forever()方法处理多个客户端请求

import socketserver


class MyTCPHandler(socketserver.BaseRequestHandler):
    """
    服务器的请求处理类

    每次连接到服务器都会被实例化一次,并且必须重写handle()方法来实现与之通信的客户端
    """

    def handle(self):

        while True:
          try:
             # self.request 是TCP socket连接到客户端
             self.data = self.request.recv(1024).strip()
             print("{} wrote:".format(self.client_address[0]))
             print(self.data)
             if not self.data: #如果没有收到数据,说明客户端已断开
                 print("客户端{}已经断开!".format(self.client_address[0]))
                 break
             # 发回同样的数据,只是变成了大写
             self.request.send(self.data.upper())
           except ConnectionResetError as e:
               print("error",e)
               break


if __name__ == "__main__":
    HOST, PORT = "localhost", 9995

    # 创建一个Server对象(实例化)并绑定IP地址和端口
    server = socketserver.TCPServer((HOST,PORT), MyTCPHandler)

    # 激活Server后,它将一直运行直到使用Ctrl-C去中断它
    server.serve_forever()

#运行输出
127.0.0.1 wrote:
b'ls'
127.0.0.1 wrote:
b'ls'
127.0.0.1 wrote:
b''
客户端127.0.0.1已经断开!

解析:MyTCPHandler()类是自己写的一个请求处理类,这个请求处理类继承socketserver,而且要重写handle()方法,这个handle()方法默认为空,客户端到服务器的每次请求都会被实例化,接收数据不再是之前的conn.recv(),而必须是self.request.recv(),同样发送数据给客户端也是self.request。

注意:服务器端跟客户端所有的交互都是在handle()里完成的,每一个从客户端发来的请求,它的请求都会被分配到def handle()进行处理,并且处理过程就是handle()规定的。

客户端

import socket

client = socket.socket()
client.connect(("localhost",9995))

while True:
    cmd_input = input(">>:")
    if len(cmd_input) == 0:
        continue
    client.send(cmd_input.encode())
    data = client.recv(1024)
    print(data.decode())

#运行输出
>>:ls
LS
>>:dir
DIR
posted @ 2017-10-25 09:42  Mr.hu  阅读(104)  评论(0编辑  收藏  举报