• socketserver(多连接)


      正如前面的socket模块部分看到的一样,写一个简单套接字服务器不是很难,如果想实现超出继承的应用,最好寻求一些帮助,socketserver模块是标准库中很多服务器框架的基础,这些服务器架构包括BaseHTTPServer、SimpleHTTPServer、CGIHTTPServer、SimpleXMLRPCServer、DocXMLRPCServer,所有的这些服务器框架都为基础服务器增加了特定功能;

      socketserver内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进程” 专门负责处理当前客户端的所有请求

    ThreadingTCPServer(多线程,真并发

    ThreadingTCPServer实现的Soket服务器内部会为每个client创建一个 “线程”,该线程用来和客户端进行交互。

    使用ThreadingTCPServer:

    • 创建一个继承自 SocketServer.BaseRequestHandler 的类
    • 类中必须定义一个名称为 handle 的方法
    • 启动ThreadingTCPServer

    用socketserver对ssh程序做修改,实现多用户同时操作互不影响

     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 #-Author-Lian
     4 
     5 #scoketserver
     6 
     7 import socketserver,os
     8 
     9 class Myserver(socketserver.BaseRequestHandler):
    10     def handle(self):
    11         while True:
    12             conn = self.request
    13            # conn,add = server.accept()
    14             while True:
    15                 print("开始收")
    16                 client_data = conn.recv(1024)
    17                 client_data = client_data.decode("utf-8")
    18                 if client_data == "exit":           #收到exit 退出
    19                     break
    20                 send_data = os.popen(client_data).read()    #执行命令结果,要发送的数据
    21                 send_data = send_data.encode("utf-8")       #转换为bytes类型
    22 
    23                 length = str(len(send_data))              #统计发送数据的长度
    24                 conn.sendall(length.encode("utf-8"))      #长度以bytes类型发送过去
    25 
    26                 return_value = conn.recv(1024)
    27                 return_value = return_value.decode("utf-8")
    28 
    29                 if return_value == "start":
    30                     if not send_data:            # 如果执行结果为空,表示命令不存在
    31                         conn.sendall((client_data +"命令不存在").encode("utf-8"))
    32                     else:
    33                       conn.sendall(send_data)
    34             conn.close()
    35 
    36 if __name__ == '__main__':
    37     server = socketserver.ThreadingTCPServer(("127.0.0.1",8888),Myserver)
    38     server.serve_forever()
    39 
    40 ssh 服务端多用户同时连接
    ssh 服务端多用户同时连接
     1 #!/usr/bin/env python
     2 # -*- coding:utf-8 -*-
     3 #-Author-Lian
     4 
     5 #ssh client
     6 
     7 import socket
     8 
     9 ip_port = ("127.0.0.1",8888)
    10 client = socket.socket()
    11 client.connect(ip_port)
    12 
    13 while True:
    14     cmd = input("->>").strip()
    15     if not cmd:                 #空字符 重新输入
    16         continue
    17     client.sendall(cmd.encode("utf-8"))     #要执行的命令发送过去
    18     if cmd == "exit":           #如果为exit 退出连接
    19         break
    20 
    21     length = client.recv(1024)     #数据长度
    22     length = length.decode("utf-8")
    23     length = int(length)            #长度转换为int
    24 
    25     client.sendall("start".encode("utf-8"))     #发送字节start
    26 
    27     sum_data = ""                   #初始汇总的数据
    28     while length >= 0:              #循环收数据
    29         server_data = client.recv(1024)
    30         length -=1024
    31         sum_data +=server_data.decode("utf-8")
    32     print(sum_data)                 #打印最终的执行数据
    33 
    34 client.close()
    35 
    36 ssh 客户端多用户同时连接
    ssh 客户端多用户同时连接

    ThreadingTCPServer源码剖析

    内部调用流程为:

    • 启动服务端程序
    • 执行 TCPServer.__init__ 方法,创建服务端Socket对象并绑定 IP 和 端口
    • 执行 BaseServer.__init__ 方法,将自定义的继承自SocketServer.BaseRequestHandler 的类 MyRequestHandle赋值给 self.RequestHandlerClass
    • 执行 BaseServer.server_forever 方法,While 循环一直监听是否有客户端请求到达 ...
    • 当客户端连接到达服务器
    • 执行 ThreadingMixIn.process_request 方法,创建一个 “线程” 用来处理请求
    • 执行 ThreadingMixIn.process_request_thread 方法
    • 执行 BaseServer.finish_request 方法,执行 self.RequestHandlerClass()  即:执行 自定义 MyRequestHandler 的构造方法(自动调用基类BaseRequestHandler的构造方法,在该构造方法中又会调用 MyRequestHandler的handle方法)

    对源码进行精简做一个程序:

    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
    import socket
    import threading
    import select
     
     
    def process(request, client_address):
        print request,client_address
        conn = request
        conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.')
        flag = True
        while flag:
            data = conn.recv(1024)
            if data == 'exit':
                flag = False
            elif data == '0':
                conn.sendall('通过可能会被录音.balabala一大推')
            else:
                conn.sendall('请重新输入.')
     
    sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sk.bind(('127.0.0.1',8002))
    sk.listen(5)
     
    while True:
        r, w, e = select.select([sk,],[],[],1)
        print 'looping'
        if sk in r:
            print 'get request'
            request, client_address = sk.accept()
            = threading.Thread(target=process, args=(request, client_address))
            t.daemon = False
            t.start()
     
    sk.close()

    如精简代码可以看出,SocketServer的ThreadingTCPServer之所以可以同时处理请求得益于 select 和 Threading 两个东西,其实本质上就是在服务器端为每一个客户端创建一个线程,当前线程用来处理对应客户端的请求,所以,可以支持同时n个客户端链接(长连接)

     

  • 相关阅读:
    Git 和 GitHub 入门
    TestStand 登录界面如何自定义
    LabVIEW可以通过哪些方式和MES交互
    基于TestStand和C#开发平台TTStand 初识系列之六 【TestRun】
    基于TestStand和C#开发平台TTStand 初识系列之五 【SystemSet】
    基于TestStand和C#开发平台TTStand 初识系列之四 【Process】
    基于TestStand和C#开发平台TTStand 初识系列之三 【Development】
    基于TestStand和C#开发平台TTStand 初识系列之二 【安装】
    基于TestStand和C#开发平台TTStand 初识系列之一 【介绍】
    TestStand 如何正确使用Trace功能
  • 原文地址:https://www.cnblogs.com/lixiaoliuer/p/6739528.html
Copyright © 2020-2023  润新知