python-study-30
1、远程执行命令的c/s架构的软件 (模拟ssh远程执行命令)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from socket import * import subprocess import struct import json server=socket(AF_INET,SOCK_STREAM) #创建一个服务器的套接字 server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #解决方案 # 重启服务端时可能会遇到地址占用 # 这个是由于你的服务端仍然存在四次挥手的time_wait状态在占用地址 server.bind(('127.0.0.1',8080)) #把地址绑定到套接字 server.listen(5) #监听链接 while True: #链接循环,这个链接结束,继续处理下一个客户端链接,不会因为一个客户端链接结束,导致服务器结束 conn,client_addr=server.accept() print('新的客户端',client_addr) while True: #收发循环,实现循环通讯 try: #windows突然断开,服务端会因为没有链接 而崩溃 cmd=conn.recv(1024) #cmd=b'dir' 接收的是bytes类型 使用时要解码 if len(cmd) == 0:break #linux如果突然断开,自己给自己收空,就死循环 # 运行系统命令 obj=subprocess.Popen(cmd.decode('utf-8'), #接收的是bytes类型 使用时要解码 shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE ) stdout=obj.stdout.read() #从管道接收正确输出,bytes类型 stderr=obj.stderr.read() #从管道接收错误输出,bytes类型 #先制作报头是字典但因为通讯是bytes类型所以要转换 dic--str--bytes header_dic={ 'filename':'a.txt', 'total_size':len(stdout) + len(stderr), 'hash':'xasf123213123' } header_json=json.dumps(header_dic) #先用json序列化,变成str类型 header_bytes=header_json.encode('utf-8') #str编码成bytes类型 #1、先把报头的长度len(header_bytes)打包成4个bytes,然后发送 conn.send(struct.pack('i',len(header_bytes))) #int -->bytes #2、发送报头 conn.send(header_bytes) #报头传过去 #3、再发送真实的数据 conn.send(stdout) conn.send(stderr) except ConnectionResetError: break conn.close() server.close()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from socket import * import struct import json client=socket(AF_INET,SOCK_STREAM) client.connect(('127.0.0.1',8080)) while True: #收发循环,解决循环通讯的问题 cmd=input('>>: ').strip() if len(cmd) == 0:continue #如果发空的话,系统接收为0不会发给服务端,服务端不会响应,客户端还在等着接收,所以就会卡在这里 client.send(cmd.encode('utf-8')) #str==》bytes 发给服务端 #1、先收4个字节,该4个字节中包含报头的长度 header_len=struct.unpack('i',client.recv(4))[0] #4个字节反解成int类型数字,代表报头的长度 #2、再接收报头 header_bytes=client.recv(header_len) #在接收报头长度的字节 #从报头中解析出想要的内容 header_json=header_bytes.decode('utf-8') #字节解码成json字符串 header_dic=json.loads(header_json) #json字符串在反序列化得到字典 print(header_dic) total_size=header_dic['total_size'] #从报头得到真实数据的字节长度 #3、再收真实的数据 循环接收字节 recv_size=0 res=b'' while recv_size < total_size : data=client.recv(1024) res+=data recv_size+=len(data) print(res.decode('gbk')) #因为命令是系统执行的返回给python的 所以要遵循系统的编码标准 也就是gbk client.close()
2、粘包问题
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
操作系统在发包时,遵循tcp协议,
tcp协议使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包发送。
这样,接收端,就难于分辨出来了。
发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)
粘包问题主要还是因为接收方不知道消息之间的界限
ps:
发送和接收都是以操作系统基础