python套接字编程实现ntp服务和远程命令执行
python套接字编程实现ntp服务和远程命令执行
目录
1 2 3 4 | 基于udp实现ntp服务 基于tcp实现远程命令执行 基于udp实现远程命令执行 tcp与udp的比较 |
前面关于套接字基础请查阅
https://www.cnblogs.com/-wenli/p/10173888.html
基于udp实现ntp服务
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | import time from socket import * def main(): ip_port = ( '127.0.0.1' , 4444) buffer_size = 1024 s1 = socket(AF_INET,SOCK_DGRAM) #数据报 s1.bind(ip_port) while True: data,addr= s1.recvfrom(buffer_size) if not data: fmt = '%Y-%m-%d %X' #udp服务可以接收空信息,如果为空信息,则为默认格式 else : fmt = '%' +data.decode( 'utf-8' ) #自定义格式 back_time=time. strftime (fmt) s1.sendto(back_time.encode( 'utf-8' ),addr) if __name__ == '__main__' : main() |
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | from socket import * def main(): ip_port = ( '127.0.0.1' , 4444) buffer_size = 1024 s2 = socket(AF_INET,SOCK_DGRAM) #数据报 print ( '请输入回车获取当前完整时间,Y获取当前年份,m获取当前月份,,d获取当前日期,X获取当前时间' ) while True: data = input( '-->:' ) s2.sendto(data.encode( 'utf--8' ),ip_port) #udp发信息没有链接,所以每一个发送信息都需要指定ip和端口 data1,addr=s2.recvfrom(buffer_size) print ( '标准时间:' ,data1.decode( 'utf-8' )) if __name__ == '__main__' : main() |
运行结果
基于tcp实现远程执行命令
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | from socket import * import subprocess def main(): ip_port=( '127.0.0.1' ,8080) back_log=5 buffer_size=1024 s1 = socket(AF_INET,SOCK_STREAM) s1.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) s1.bind(ip_port) s1.listen(back_log) while True: conn,addr=s1.accept() while True: try : #收信息 cmd = conn.recv(buffer_size) if not cmd: break print ( '收到的命令是:' ,cmd.decode( 'utf-8' )) #执行命令 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() #发信息 #注意:执行的结果默认jbk编码方式,所以客户端必须使用gbk方式解码 conn.send(cmd_res) except Exception: break conn.close() s1.close() # 关闭服务端套接字 if __name__ == '__main__' : main() |
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | from socket import * def main(): ip_port=( '127.0.0.1' ,8080) buffer_size=2048 s1 = socket(AF_INET,SOCK_STREAM) s1.connect(ip_port) while True: cmd = input( '-->' ) if not cmd: continue if cmd == 'quite' : break s1.send(cmd.encode( 'utf-8' )) reponse = s1.recv(buffer_size) print ( '命令执行结果:' ,reponse.decode( 'gbk' )) s1.close() if __name__== '__main__' : main() |
补充知识
1 2 3 4 5 6 7 | 补充: 你从管道中读取输出,只能读取一次,输出到屏幕,管道里面的数据就会取出来 res=subprocess.Popen( 'dir' ,shell=True,stdout=subprocess.PIPE) 第一个参数为命令,第二个参数为shell=Ture,意思是使用shell作为命令解释器去解释前面的命令,后面是重定向标准输入和标准输出以及错误输出<br>(默认输出到屏幕) res.stdout.read() 从管道读取结果<br>res.stderr.read() 从管道读取错误<br>res.stdin.read() 从管道读取输入 这个程序解决两个问题: 客户端正常断开连接,在服务端加上 if not cmd: break ,判断接收信息为空就结束接收信息的循环,继续等待下一次连接,正常情况,服务端不会接收到空。 客户毒案异常中断,在服务端上加上异常处理 |
运行结果
基于udp实现远程执行命令
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | from socket import * import subprocess def main(): ip_port = ( '127.0.0.1' , 9003) bufsize = 1024 udp_server = socket(AF_INET, SOCK_DGRAM) udp_server.bind(ip_port) while True: try : # 收消息 cmd, addr = udp_server.recvfrom(bufsize) print ( '用户命令----->' , cmd.decode( 'utf-8' )) # 逻辑处理 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' ) # 发信息 # 注意:执行的结果默认jbk编码方式,所以客户端必须使用gbk方式解码 udp_server.sendto(cmd_res,addr) except Exception: break if __name__== '__main__' : main() |
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | from socket import * def main(): ip_port=( '127.0.0.1' ,9003) buffer_size=1024 udp_client=socket(AF_INET,SOCK_DGRAM) while True: cmd = input( '-->' ) if not cmd: continue if cmd == 'quite' : break udp_client.sendto(cmd.encode( 'utf-8' ),ip_port) reponse,addr = udp_client.recvfrom(buffer_size) print ( '命令执行结果:' , reponse.decode( 'gbk' )) udp_client.close() if __name__== '__main__' : main() |
运行结果
tcp与udp的比较
1 2 3 4 5 6 7 8 9 10 11 12 | tcp基于链接通信 基于链接,则需要listen(backlog),指定连接池的大小 基于链接,必须先运行的服务端,然后客户端发起链接请求 对于mac系统:如果一端断开了链接,那另外一端的链接也跟着完蛋recv将不会阻塞,收到的是空(解决方法是:服务端在收消息后加上 if 判断,空消息就 break 掉通信循环) 对于windows/linux系统:如果一端断开了链接,那另外一端的链接也跟着完蛋recv将不会阻塞,收到的是空(解决方法是:服务端通信循环内加异常处理,捕捉到异常后就 break 掉通讯循环) udp无链接 无链接,因而无需listen(backlog),更加没有什么连接池之说了 无链接,udp的sendinto不用管是否有一个正在运行的服务端,可以己端一个劲的发消息,只不过数据丢失 recvfrom收的数据小于sendinto发送的数据时,在mac和linux系统上数据直接丢失,在windows系统上发送的比接收的大直接报错 只有sendinto发送数据没有recvfrom收数据,数据丢失 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?