Python学习-day8

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python学习-day8相关的知识,希望对你有一定的参考价值。

一、Socket进阶

        运用socket实现简版ssh,即在客户端输入指令,服务器收到指令后执行并返回结果

技术分享
 1 import socket
 2 import os
 3 server = socket.socket()
 4 server.bind((localhost,9999))
 5 server.listen()
 6 
 7 while True:
 8     conn,addr = server.accept()
 9     print(new conn : ,addr)
10     while True:
11         print(waiting to be execute )
12         data = conn.recv(1024)
13         if not data:
14             print(conncetion is cut)
15             break
16         print(execute instruction!,data)
17 
18         cmd_res = os.popen(data.decode()).read()#popen返回的是内存地址,加read可以读出内容
19         
20         print(before send)
21         if len(cmd_res) == 0:#指令如果没有返回结果如cd,返回客户端‘cmd has no output !‘
22             cmd_res = cmd has no output !
23        
24         conn.send(cmd_res.encode(utf-8))
25         print(send done!)
26 server.close()
server
技术分享
 1 import socket
 2 
 3 client = socket.socket()
 4 client.connect((localhost,9999))
 5 while True:
 6     cmd = input(>>>:).strip()
 7     if len(cmd)==0:continue
 8     client.send(cmd.encode(utf-8))
 9 
10     cmd_res_size = client.recv(1024)#接收命令长度
11     print(data lenth: ,cmd_res_size.decode())
12 
13 client.close()
client

但是这样实现,会发现当指令的执行结果内容太长时,无法一次性接收完,然后执行下一条指令时,又会接收到上次没接收完整的内容。因为客户端限制了每次接收的数据最多1024字节,而且socket每次发送接收数据的量是有限的,所以客户端接收的数据最大不能超过8192字节。那么当传输数据超过了客户端能一次接收的最大限制时,就要让客户端分批接收了,可以在发送数据前告知客户端数据的总大小,然后客户端可以计算出分批接收的次数。

技术分享
 1 import socket
 2 import os
 3 server = socket.socket()
 4 server.bind((localhost,9999))
 5 server.listen()
 6 
 7 while True:
 8     conn,addr = server.accept()
 9     print(new conn : ,addr)
10     while True:
11         print(waiting to be execute )
12         data = conn.recv(1024)
13         if not data:
14             print(conncetion is cut)
15             break
16         print(execute instruction!,data)
17 
18         cmd_res = os.popen(data.decode()).read()#popen返回的是内存地址,加read可以读出内容
19         print(before send,len(cmd_res))
20         print(before send)
21         if len(cmd_res) == 0:#指令如果没有返回结果如cd,返回客户端‘cmd has no output !‘
22             cmd_res = cmd has no output !
23 
24         conn.send(str(len(cmd_res.encode())).encode(utf-8))
25         conn.send(cmd_res.encode(utf-8))
26         print(send done!)
27 server.close()
server
技术分享
 1 import socket
 2 client = socket.socket()
 3 client.connect((localhost,9999))
 4 while True:
 5     cmd = input(>>>:).strip()
 6     if len(cmd)==0:continue
 7     client.send(cmd.encode(utf-8))
 8 
 9     cmd_res_size = client.recv(1024)#接收命令长度
10     print(data lenth: ,cmd_res_size.decode())
11 
12     received_size = 0
13     received_data = b‘‘
14     while received_size < int(cmd_res_size.decode()):
15         data = client.recv(1024)
16         received_size += len(data)
17         received_data += data
18     else:
19         print(cmd res receive done...,received_size)
20         print(received_data.decode())
21         print(received done!)
22 client.close()
client

      修改后的程序,运行还是会出现‘粘包’的现象,即服务器端连续调用send方法时,多次发送的数据被拼到一起传送给客户端。因为我们调用send方法时,数据并没有立刻发送到客户端,而是先把数据放到了socket的缓冲池中,等缓冲池满了或者超时了才会发送给客户端。这样就导致了客户端一次接收的数据实际可能包含多次的请求结果。我们没办法直接操作缓冲区,所以要解决这个问题,只能让缓冲区超时。可以在服务器端每次发出数据后,等待客户端返回一个收到数据的确认信息,收到确认信息后再发送下一次的数据。

技术分享
 1 import socket
 2 import os
 3 server = socket.socket()
 4 server.bind((localhost,9999))
 5 server.listen()
 6 
 7 while True:
 8     conn,addr = server.accept()
 9     print(new conn : ,addr)
10     while True:
11         print(waiting to be execute )
12         data = conn.recv(1024)
13         if not data:
14             print(conncetion is cut)
15             break
16         print(execute instruction!,data)
17 
18         cmd_res = os.popen(data.decode()).read()#popen返回的是内存地址,加read可以读出内容
19         print(before send,len(cmd_res))
20 
21         if len(cmd_res) == 0:#指令如果没有返回结果如cd,返回客户端‘cmd has no output !‘
22             cmd_res = cmd has no output !
23         conn.send(str(len(cmd_res.encode())).encode(utf-8))#发送数据前,先发送数据长度给客户端
24         client_ack = conn.recv(1024)#接收客户端的确认信息
25         print(client_ack.decode())
26         conn.send(cmd_res.encode(utf-8))
27         print(send done!)
28 server.close()
server
技术分享
 1 import socket                                                        
 2 client = socket.socket()                                             
 3 client.connect((192.168.170.133,9999))                             
 4 while True:                                                          
 5     cmd = input(>>>:).strip()                                      
 6     if len(cmd)==0:continue                                          
 7     client.send(cmd.encode(utf-8))                                 
 8                                                                      
 9     cmd_res_size = client.recv(1024)#接收命令长度                          
10     print(data lenth: ,cmd_res_size.decode())                      
11     client.send(b"ready to recv file") #发送确认消息                       
12                                                                      
13     received_size = 0                                                
14     received_data = b‘‘                                              
15     while received_size < int(cmd_res_size.decode()):                
16         data = client.recv(1024)                                     
17         received_size += len(data)                                   
18         received_data += data                                        
19     else:                                                            
20         print(cmd res receive done...,received_size)               
21         print(received_data.decode())                                
22         print(received done!)                                      
23 client.close()                                                       
24                                                                      
client

 这样修改后的程序就不会再出现粘包的问题了。

二、SocketServer

      Python提供了两个基本的socket模块。一个是socket,它提供了标准的BSD Socket API;另一个是socketServer,它提供了服务器中心类,可以简化网络服务器的开发。

SocketServer提供了4个基本的服务类:

TCPServer针对TCP套接字流

UDPServer针对UDP数据报套接字

UnixStreamServer和UnixDatagramServer针对UNIX域套接字,不常用。这个四个服务类都是同步处理请求的。一个请求没处理完不能处理下一个请求。要想支持异步模型,可以利用多继承让server类继承ForkingMixIn 或 ThreadingMixIn mix-in classes。

       要实现一项服务,还必须派生一个handler class请求处理类,并重写父类的handle()方法。handle方法就是用来专门是处理请求的。该模块是通过服务类和请求处理类组合来处理请求的。

      SocketServer模块提供的请求处理类有BaseRequestHandler,以及它的派生类StreamRequestHandler和DatagramRequestHandler。从名字看出可以一个处理流式套接字,一个处理数据报套接字。

       

         总结用SocketServer创建一个服务的步骤:

         1.创建一个request handler class(请求处理类),继承自BaseRequestHandler class并重写它的handle()方法,该方法将处理到的请求。

         2.实例化一个server class对象,并将服务的地址和之前创建的request handler class传递给它。

         3.调用server class对象的handle_request() 或 serve_forever()方法来开始处理请求。

技术分享
 1 import  socketserver
 2 class MyTCPHandler(socketserver.BaseRequestHandler):#定义请求处理类
 3     def handle(self):
 4         while True:
 5             try:
 6                 self.data = self.request.recv(1024).strip()
 7                 print({} wrote:.format(self.client_address[0]))
 8                 print(self.data)
 9                 self.request.send(self.data.upper())
10             except ConnectionResetError as e:
11                 print(err,e)
12                 break
13 
14 if __name__ == __main__:
15     host,port = localhost,9999
16     server = socketserver.ThreadingTCPServer((host,port),MyTCPHandler)#实例化服务类
17     server.serve_forever()#开启服务
socketserver

 

以上是关于Python学习-day8的主要内容,如果未能解决你的问题,请参考以下文章

python学习 day8 题型做法总结

Python学习-day8

day8 python学习

python学习之路-day8

Python学习day8--linux基础

python day8 学习整理