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 相当于此前的connself.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 subprocessimport 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), 获取 ACKself.request.sendall(bytes('begin:{}'.format(len(send_data)), encoding='utf-8')) # 发送给客户端的ack = self.request.recv(1024).decode()# 发送 dataif 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:continueif 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'))
# 循环接收 datarecv_size = 0recv_data = b''while recv_size < data_size: # 若data长度为0(cd等无返回结果的命令),则直接跳出该循环,既判断了数据是否接收完整,又避免了执行无返回数据命令后client的recv阻塞data = sk.recv(1024)recv_data += datarecv_size += len(data)else:print('recived: {}'.format(recv_size)) # 打印已经接收的数据长度
print(recv_data.decode('gbk'))
sk.close()
- 注意:
- top命令,该命令时一个一直执行的命令,当命令结束,返回结果才能固定
- 所以,一致会处于等待获取命令执行结果的状态