zoukankan      html  css  js  c++  java
  • Python学习笔记八

    类的高级用法

    多态:  

         在其他语言,使用的是类的继承。

        在python中,不需要指定数据类型。

    基于TCP协议的socket通信实现:

      类似于打电话的情景。

      服务端: 

      1.买手机

      2.插卡

      3.开机

      4.等待电话链接

      5.收消息

      6.发消息

      7.挂电话

      8.关手机

      具体代码实现如下:

    import socket #导入一个socket模块
    server1=socket.socket(socket.AF_INET,socket.SOCK_STREAM)    #买手机,基于socket的网络通信,使用的是TCP协议
    server1.bind(('127.0.0.1',8080))   #插卡,指定服务器的IP地址和端口号
    server1.listen(5)      #开机,设置监听等待数
    conn,client_addr=server1.accept()      #等待电话链接
    while True:
        recv_data=conn.recv(1024)             #收消息,限制单个消息的最大数为1024字节
        print(recv_data)
        conn.send(recv_data.upper())          #发消息
    
    conn.close()       #挂手机
    server1.close()         #关机

      客户端:

      1.买手机

      2.打电话

      3.发消息

      4.收消息

      具体代码实现:

    import socket   
    client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    client.connect(('127.0.0.1',8080))      #打电话
    
    while True:
        message=input('数据>>').strip()    
        client.send(message.encode('utf-8'))    #发消息
        recv=client.recv(1024)          #收消息
        print(recv)

      上面的服务端和客户端都添加了while True,实现了通信循环。

      但是现在有个问题:就是如果客户端输入为空,客户端会卡住。

      分析这个问题:

      要么就是客户端没有发送出去,要么就是客户端没有收到。

      结果:因为客户端发送为空的消息,但是服务器并没有收到该消息,所以客户端也不会收到空消息,所以会被卡住。

         所以需要在客户端上设置,用户不可以发送为空的消息。

      修改后的代码:

      

    import socket
    client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    client.connect(('127.0.0.1',8080))      #打电话
    
    while True:
        message=input('数据>>').strip()
        if not message:continue
        client.send(message.encode('utf-8'))    #发消息
        recv=client.recv(1024)          #收消息
        print(recv)

    加上链接循环:

    import socket #导入一个socket模块
    server1=socket.socket(socket.AF_INET,socket.SOCK_STREAM)    #买手机,基于socket的网络通信,使用的是TCP协议
    server1.bind(('127.0.0.1',8080))   #插卡,指定服务器的IP地址和端口号
    server1.listen(5)      #开机,设置监听等待数
    while True:
        conn,client_addr=server1.accept()      #等待电话链接
        while True:
            try:
                recv_data=conn.recv(1024)        #收消息,限制单个消息的最大数为1024字节
           if not recv_date:break
    print(recv_data) conn.send(recv_data.upper()) #发消息 except ConnectionResetError: break conn.close() #挂手机 server1.close() #关机
    前提是:客户端单方面断开链接
    如果服务端是windows系统,就添加一个try错误处理,如果服务端是linux,就不会有异常,服务端一直在接受空,所以需要加一个判断,如果为空就退出通信循环

     命令的结果:如何获取

      os.system('命令'): 这种方法只是执行了一下命令,并返回一个值。可以通过这个值,判断命令是否执行成功。

      subprocess.Popen('命令',shell=True):这个方法是执行的结果是内存地址。它可以指定执行的结果放到某个位置。

      subprocess.Popen('命令',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)

    import subprocess
    res=subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    res_stdout=res.stdout.read()
    res_stderr=res.stderr.read()
    print(res_stdout.decode('gbk'))
    res_stdout1=res.stdout.read()
    print('jieguo',res_stdout1.decode('gbk'))
    #管道读取一次以后,管道就为空了。因为取走了。
    结果如下:

    C:\Users\yangjianbo\AppData\Local\Programs\Python\Python36\python.exe C:/Users/yangjianbo/PycharmProjects/untitled/第八课面向对象高级/subprocess模块.py
    驱动器 C 中的卷是 Windows
    卷的序列号是 58DC-A9CB

    
    

    C:\Users\yangjianbo\PycharmProjects\untitled\第八课面向对象高级 的目录

    
    

    2017/11/08 22:10 <DIR> .
    2017/11/08 22:10 <DIR> ..
    2017/11/05 12:25 19 b.py
    2017/11/08 21:35 355 socket客户端.py
    2017/11/08 21:35 764 socket服务器.py
    2017/11/08 22:10 417 subprocess模块.py
    2017/11/05 12:10 0 __init__.py
    2017/11/08 21:50 <DIR> __pycache__
    2017/11/07 23:32 352 客户端2.py
    2017/11/07 23:32 352 客户端3.py
    2017/11/07 23:32 352 客户端4.py
    2017/11/07 23:32 352 客户端5.py
    2017/11/07 23:32 352 客户端6.py
    2017/11/07 23:34 352 客户端7.py
    11 个文件 3,667 字节
    3 个目录 458,471,485,440 可用字节

    第二次读取管道的命令结果==========》

    可以看到结果:第一次的结果是正确执行命令后的结果,第二次的命令执行结果就为空了。

       

    
    
    命令执行错误的结果,会放到stderr的管道中。
    import subprocess
    res=subprocess.Popen('啊啊啊',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
    res_stdout=res.stdout.read()
    res_stderr=res.stderr.read()
    print(res_stdout.decode('gbk'))
    res_stdout1=res.stdout.read()
    print('第二次读取管道的命令结果==========》',res_stdout1.decode('gbk'))
    print(res_stderr.decode('gbk'))
    结果:

    C:\Users\yangjianbo\AppData\Local\Programs\Python\Python36\python.exe C:/Users/yangjianbo/PycharmProjects/untitled/第八课面向对象高级/subprocess模块.py

    
    

    第二次读取管道的命令结果==========》
    '啊啊啊' 不是内部或外部命令,也不是可运行的程序
    或批处理文件。

    stdin参数:用来把第一个命令执行的结果输入到第二个命令中。  

    简单SSH程序:

    服务端代码:

    import socket #导入一个socket模块
    import subprocess
    server1=socket.socket(socket.AF_INET,socket.SOCK_STREAM)    #买手机,基于socket的网络通信,使用的是TCP协议
    server1.bind(('127.0.0.1',8080))   #插卡,指定服务器的IP地址和端口号
    server1.listen(5)      #开机,设置监听等待数
    while True:
        conn,client_addr=server1.accept()      #等待电话链接
        while True:
            try:
                cmd=conn.recv(1024)        #收消息,限制单个消息的最大数为1024字节
                if not cmd :break
                cmd=cmd.decode('utf-8')
                cmd_res=subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
                stdout_res=cmd_res.stdout.read()
                stderr_res=cmd_res.stderr.read()   # 返回的结果就是bytes类型,所以不需要再decode了。
                conn.send(stdout_res+stderr_res)          #发消息
            except ConnectionResetError:
                break
        conn.close()       #挂手机
    server1.close()         #关机

    客户端代码:

    import socket
    client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    client.connect(('127.0.0.1',8080))      #打电话
    
    while True:
        cmd=input('数据>>').strip()
        if not cmd:continue
        client.send(cmd.encode('utf-8'))    #发消息
        recv=client.recv(1024).decode('gbk')       #收消息    因为输出在windows系统下,所以客户端的编码应该为gbk.
       print(recv) client.close()

    关于SSH远程程序执行cd命令的问题:

      以一个变量为标准,当执行cd命令的时候,把这个变量的值加上你要切换的目录,这才是整个完整的路径。

    关于SSH远程程序执行top命令的问题:

      时时刷新top命令,其实是服务端在定期刷新一下,返回结果给客户端。不可能实现实时刷新的效果,肯定是在定期刷新的。

    1024: 收包的大小限制,最大为1024字节。只是限制收消息的大小。这个值最大设置为8096,再大就没有必要了。

    解决方法:

      把客户端接收的包大小调大,但是这种方法不合适,因为无法预测服务端返回的结果大小。

      而且收到的数据都存放在内存中,太消耗资源了。

    TCP粘包现象:

      TCP为了避免网络中的大量小包,会使用一个nagle算法,将包粘在一起发送。数据量小,时间间隔小,TCP会发生粘包现象。

      为了解决粘包的问题,协议会采用一种固定的方式:报头+数据

    struct模块:

      把数字转换成bytes类型。

      struct.pack('i',后面的数字)   i代表打包后的结果是4个bytes,打包的数字就是整型数字。

      struct.unpack('i',后面的数字)

    最终版:

      制作报头

        header_dic={}

      序列化:

        打包报头

      把报头大小打包成固定长度。

      

      

      

      

      

      

      

    一往无前虎山行,拨开云雾见光明
  • 相关阅读:
    day19.re正则表达式
    day18.os模块 对系统进行操作
    day17.json模块、时间模块、zipfile模块、tarfile模块
    day16.内置方法与模块
    day15.递归函数
    day14.推导式与生成器
    LeetCode-Permutations II
    LeetCode-Permutations
    LeetCode-Partition List
    LeetCode-Substring with Concatenation of All Words
  • 原文地址:https://www.cnblogs.com/yangjianbo/p/7786635.html
Copyright © 2011-2022 走看看