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,弄完选课程序,基本也可以上线了

posted @ 2020-03-28 00:51  崆峒山肖大侠  阅读(675)  评论(0编辑  收藏  举报