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={}

      序列化:

        打包报头

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

      

      

      

      

      

      

      

    一往无前虎山行,拨开云雾见光明
  • 相关阅读:
    hdu 1017 A Mathematical Curiosity 解题报告
    hdu 2069 Coin Change 解题报告
    hut 1574 组合问题 解题报告
    hdu 2111 Saving HDU 解题报
    hut 1054 Jesse's Code 解题报告
    hdu1131 Count the Trees解题报告
    hdu 2159 FATE 解题报告
    hdu 1879 继续畅通工程 解题报告
    oracle的系统和对象权限
    oracle 自定义函数 返回一个表类型
  • 原文地址:https://www.cnblogs.com/yangjianbo/p/7786635.html
Copyright © 2011-2022 走看看