socketserver

 



一、SocketServer实现并发服务器:       
  • 格式:
# 定义一个多并发的类,从socketserver模块中BaseRequestHandler类继承 
class MysocketServer(socketserver.BaseRequestHandler):
def handle(self):
# 重写handler方法,名称必须为handler,因为父类中也有handler,只不过该handler为空,client一旦建立连接,则会调用该方法
# print self.request,self.client_address,self.server
# self.request 相当于此前的conn
self.request.sendall(bytes('welcome.',encoding='utf-8'))

while True:
# 正常收发交互代码块
# 用 self.request 代替 conn

if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(('127.0.0.1',8009),MyServer)
server.serve_forever()
  • 模拟并发 SSH (ftp代码较多,放于网盘中)
    • =================================server=========================================================
import subprocess
import socketserver

class MysocketServer(socketserver.BaseRequestHandler):

def handle(self):
self.request.sendall(bytes('welcome to my server', encoding='utf-8'))

while True:
try:
cmd = self.request.recv(1024).decode()
if len(cmd) == 0:
raise Exception('客户端状态发生改变, go to close()')

# 执行cmd ,获取cmd执行结果
obj = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

stdout_data, stderror_data = obj.communicate()
send_data = stdout_data if len(stderror_data) == 0 else stderror_data

# 发送 len(data), 获取 ACK
self.request.sendall(bytes('begin:{}'.format(len(send_data)), encoding='utf-8'))  # 发送给客户端的
ack = self.request.recv(1024).decode()
# 发送 data
if ack.startswith('start'):
self.request.sendall(send_data)

except Exception as ex:
print(ex)
break

if __name__ == '__main__':
server = socketserver.ThreadingTCPServer(('127.0.0.1', 9998), MysocketServer)
server.serve_forever()
    • =================================client.py=========================================================
import socket

sk = socket.socket()
sk.connect(('127.0.0.1', 9998,))

welcome_msg = sk.recv(1024).decode()
print(welcome_msg)

while True:
cmd = input('>> ').strip()
if len(cmd) == 0:
continue
if cmd == 'exit':
break

# 发送 cmd 命令
sk.sendall(bytes(cmd, encoding='utf-8'))
# 获取 data长度
recv_data = sk.recv(1024).decode()
if recv_data.startswith('begin'):
data_size = int(recv_data.split(':')[-1])
print('send: {}'.format(data_size))  # 打印需要接收的数据长度

# 发送ACK确认
sk.sendall(bytes('start', encoding='utf-8'))

# 循环接收 data
recv_size = 0
recv_data = b''
while recv_size < data_size:     # 若data长度为0(cd等无返回结果的命令),则直接跳出该循环,既判断了数据是否接收完整,又避免了执行无返回数据命令后client的recv阻塞
data = sk.recv(1024)
recv_data += data
recv_size += len(data)
else:
print('recived: {}'.format(recv_size))  # 打印已经接收的数据长度

print(recv_data.decode('gbk'))

sk.close()

 




  • 注意:
    • top命令,该命令时一个一直执行的命令,当命令结束,返回结果才能固定
    • 所以,一致会处于等待获取命令执行结果的状态









































 

posted on 2016-09-05 14:47  台灯不太亮  阅读(158)  评论(0编辑  收藏  举报

导航