python-study-30

1、远程执行命令的c/s架构的软件 (模拟ssh远程执行命令)
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()
解决粘包问题终极版本/server
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()
解决粘包问题终极版本/client

2、粘包问题
操作系统在发包时,遵循tcp协议,
tcp协议使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包发送。
这样,接收端,就难于分辨出来了。
发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)


粘包问题主要还是因为接收方不知道消息之间的界限


ps:
发送和接收都是以操作系统基础
View Code
原文地址:https://www.cnblogs.com/xujinjin18/p/9285715.html