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个客户端链接(长连接)

 

 

 

转载于:https://www.cnblogs.com/lixiaoliuer/p/6739528.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值