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