zoukankan      html  css  js  c++  java
  • Python学习第34天(udp套接字、tcp远程命令执行)

    今天的内容不多,就两个,udp套接字和tcp远程命令执行

    首先是一个关于昨天程序报错的处置方式:

    错误如下:

     这个是由于你的服务端仍然存在四次挥手的time_wait状态在占用地址

    1.tcp三次握手,四次挥手 2.syn洪水攻击 3.服务器高并发情况下会有大量的time_wait状态

    方法1:

    #加入一条socket配置,重用ip和端口
    
    phone=socket(AF_INET,SOCK_STREAM)
    phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加
    phone.bind(('127.0.0.1',8080))

    方法2:

    这个方法就比较牛逼了,我估计得先好好看一下Linux才能搞得定

    发现系统存在大量TIME_WAIT状态的连接,通过调整linux内核参数解决,
    vi /etc/sysctl.conf
    
    编辑文件,加入以下内容:
    net.ipv4.tcp_syncookies = 1
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_tw_recycle = 1
    net.ipv4.tcp_fin_timeout = 30
     
    然后执行 /sbin/sysctl -p 让参数生效。
     
    net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
    
    net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭;
    
    net.ipv4.tcp_tw_recycle = 1 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。
    
    net.ipv4.tcp_fin_timeout 修改系統默认的 TIMEOUT 时间

    二、基于udp套接字的服务器和客户端

    1.服务器

    import socket
    # 可以将内部可能出现的参数在建立服务前进行设置,便于后期的修改
    ip_port=('127.0.0.1',8080)
    back_log=5
    buffer_size=1024
    
    # 现在我们来建立一个udp协议的服务器
    tcp_server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    tcp_server.bind(ip_port)
    # 基于udp协议的是不需要进行listen设置的
    # 同样也不需要经过“三次握手”建立双向连接的需要,所以不需要accept
    while True:
        data,addr = tcp_server.recvfrom(buffer_size)   #收到消息也是获得两个信息,一个是信息,另一个是对方地址
        print(data.decode('utf-8'))
        print(addr)
        tcp_server.sendto(data.upper(),addr)     # 发送内容的时候是需要写地址的
    
    tcp_server.close()

    2.客户端

    import socket
    
    ip_port=('127.0.0.1',8080)
    buffer_size=1024
    while True:
        tcp_client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
        msg = input('>>>:')
        tcp_client.sendto(msg.encode('utf-8'),ip_port)
        data,addr = tcp_client.recvfrom(buffer_size)
        print(data.decode('utf-8'))

    udp套接字的优势是什么呢?

    最明显的是不需要进行三次握手和四次挥手的操作,这样就可以同时和多个客户端进行交互,从客户端可以看出,她连backlog都木得

    三、基于tcp远程命令的执行

    1.补充一个subprocess的模块

    stdout, stderr:input: 该参数是传递给Popen.communicate(),通常该参数的值必须是一个字节序列,如果universal_newlines=True,则其值应该是一个字符串。

    run()函数默认不会捕获命令执行结果的正常输出和错误输出,如果我们向获取这些内容需要传递subprocess.PIPE,然后可以通过返回的CompletedProcess类实例的stdout和stderr属性或捕获相应的内容;

    call()和check_call()函数返回的是命令执行的状态码,而不是CompletedProcess类实例,所以对于它们而言,stdout和stderr不适合赋值为subprocess.PIPE;

    check_output()函数默认就会返回命令执行结果,所以不用设置stdout的值,如果我们希望在结果中捕获错误信息,可以执行stderr=subprocess.STDOUT。

    暂时已dir命令为例

    subprocess.Popen('dir' , shell = True , stdout = subprocess.PIPE ,stderr = subprocess.PIPE,  stdin = subprocess.PIPE)

    分别对应的运行后的输出信息,报错信息和输入信息

    如果不对这三个数值进行设置,则会默认他们会直接通过数据“管道”进入屏幕显示,而此时我们是将相应的输出结果存放在管道内

    res = subprocess.Popen('dir' , shell = True , stdout = subprocess.PIPE ,stderr = subprocess.PIPE,  stdin = subprocess.PIPE)

    res.stdout.read( )   之所以要使用read方法,是因为直接取值得到的是一个类对象

    2.补充完subprocess的模块信息我们就可以开始实际操作了

    (1)先用反馈时间的进行试手吧(基于udp套接字)

    服务端:

    import socket,time
    # 可以将内部可能出现的参数在建立服务前进行设置,便于后期的修改
    ip_port=('127.0.0.1',8080)
    back_log=5
    buffer_size=1024
    
    # 现在我们来建立一个udp协议的服务器
    tcp_server = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    tcp_server.bind(ip_port)
    # 基于udp协议的是不需要进行listen设置的
    # 同样也不需要经过“三次握手”建立双向连接的需要,所以不需要accept
    while True:
        data,addr = tcp_server.recvfrom(buffer_size)   #收到消息也是获得两个信息,一个是信息,另一个是对方地址
        print(data.decode('utf-8'))
        print(addr)
        msg = data.decode('utf-8')   # 这样的设置我们可以让用户设定时间的格式
        if not msg:                  # 进行判断,用户舒润时间格式为空,我们就可以输出默认格式
            time_res = time.strftime('%Y-%m-%d  %X')
        else:                         # 不是空值的时候以用户输入参数为准
            time_res = time.strftime(msg)   # '%Y-%m-%d  %X'
        tcp_server.sendto(time_res.encode('utf-8'),addr)     # 发送内容的时候是需要写地址的
    
    tcp_server.close()

    客户端:

    import socket
    
    ip_port=('127.0.0.1',8080)
    buffer_size=1024
    while True:
        tcp_client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
        msg = input('>>>:')
        tcp_client.sendto(msg.encode('utf-8'),ip_port)
        data,addr = tcp_client.recvfrom(buffer_size)
        print(data.decode('utf-8'))

    客户端的部分基本没有什么变化,真的感觉很棒棒。

    下面是基于tcp协议实现,远程执行命令,有点类似远程协助的意思

    服务端:

    from socket import *
    import subprocess
    ip_port=('127.0.0.1',8080)
    back_log=5
    buffer_size=1024
    
    tcp_server=socket(AF_INET,SOCK_STREAM)
    tcp_server.bind(ip_port)
    tcp_server.listen(back_log)
    
    while True:
        conn,addr=tcp_server.accept()
        print('新的客户端链接',addr)
        while True:
            #
            try:
                cmd=conn.recv(buffer_size)
                if not cmd:break
                print('收到客户端的命令',cmd)
    
                #执行命令,得到命令的运行结果cmd_res
                res=subprocess.Popen(cmd.decode('utf-8'),shell=True,
                                     stderr=subprocess.PIPE,
                                     stdout=subprocess.PIPE,
                                     stdin=subprocess.PIPE)
                err=res.stderr.read()
                if err:
                    cmd_res=err
                else:
                    cmd_res=res.stdout.read()
    
                #
                if not cmd_res:
                    cmd_res='执行成功'.encode('gbk')   #为啥此处是gbk呢,这里执行系统指令会使用系统默认编码系统,对于Windows就是gbk
                conn.send(cmd_res)
            except Exception as e:
                print(e)
                break

    客户端:

    from socket import *
    ip_port=('127.0.0.1',8080)
    back_log=5
    buffer_size=1024
    
    tcp_client=socket(AF_INET,SOCK_STREAM)
    tcp_client.connect(ip_port)
    
    while True:
        cmd=input('>>: ').strip()
        if not cmd:continue
        if cmd == 'quit':break
    
        tcp_client.send(cmd.encode('utf-8'))
        cmd_res=tcp_client.recv(buffer_size)
        print('命令的执行结果是 ',cmd_res.decode('gbk'))
    tcp_client.close()

    今天的内容就是这些了,收获很多,其实udp套接字很厉害,我们用的qq就是典型的udp的,可以保证多线联系,就是这样了

    抓紧抽空看linux,弄完选课程序,基本也可以上线了

  • 相关阅读:
    linux c编程:Posix消息队列
    go语言之接口二
    linux c编程:FIFO
    python cookbook第三版学习笔记十九:未包装的函数添加参数
    linux c编程:popen
    linux c编程:管道
    Linux c编程:I/O多路复用之epoll
    Linux c编程:I/O多路复用之select
    inux c编程:记录锁
    python cookbook第三版学习笔记十八:可由用户修改的装饰器
  • 原文地址:https://www.cnblogs.com/xiaoyaotx/p/12585389.html
Copyright © 2011-2022 走看看