zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    开源项目之Android Afinal框架
    DateTimePicker——开源的Android日历类库
    Android 教你打造炫酷的ViewPagerIndicator
    Android UI-仿微信底部导航栏布局
    Android 下拉刷新框架实现
    Android-设置PullToRefresh下拉刷新样式
    Android-PullToRefresh下拉刷新库基本用法
    android 在使用ViewAnimationUtils.createCircularReveal()无法兼容低版本的情况下,另行实现圆形...
    Android5.0新特性——兼容性(support)
    求訪问啊啊啊啊
  • 原文地址:https://www.cnblogs.com/xujinjin18/p/9285715.html
Copyright © 2011-2022 走看看