socket 简单SSH
server
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 |
import socket import os # 初始化socket对象 server = socket.socket() # 绑定网络地址和端口 server.bind(("0.0.0.0", 8888)) # 开始监听 server.listen(5) print("开始监听...") while True: # 接受连接,并保存连接对象和对端地址信息 conn, client_addr = server.accept() print("成功建立连接...", client_addr) while True: # 接受数据存入变量 data = conn.recv(1024) if not data: print("Client has gone away...") break else: cmd = data.decode("utf-8") # 解码接收的指令 cmd_result = os.popen(cmd).read() # 执行指令 print("执行指令 %s" % cmd) result_size = len(cmd_result.encode("utf-8")) conn.send(str(result_size).encode("utf-8")) # 先发送结果长度 print("结果长度:%s" % result_size) conn.recv(1024) # 等待客户端回应 conn.send(cmd_result.encode("utf-8")) # 发送命令执行结果 print("发送完成") |
client
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 |
import socket # 初始化socket对象 client = socket.socket() # 连接服务器端地址 print("开始连接服务器...") client.connect(("127.0.0.1", 8888)) print("连接服务器成功") # 循环发送数据 while True: data = input(">>") if data == "bye": break # 输入bye关闭连接 # 发送数据(Python3中必须是bytes类型) if len(data) == 0: continue # 如果输入为空则不发送 client.send(data.encode("utf-8")) # 接收服务器返回的数据 data_size = int(client.recv(1024).decode("utf-8")) if data_size: client.send(b"ACK") print("结果长度: %s" % data_size) received_size = 0 result = "" while received_size != data_size: data = client.recv(1024) received_size += len(data) result += data.decode("utf-8") print("已接收长度: %s" % received_size) print(result) # 关闭连接 client.close() |
socket 简单FTP
server
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 |
import os import socket import hashlib # 创建socket对象 server = socket.socket() # 绑定端口 server.bind(("0.0.0.0", 8888)) # 开始监听 print("等待连接...") server.listen(5) while True: # 与客户端建立连接 conn, addr = server.accept() # 建立连接 print("与客户端%s在%s端口连接成功" % (addr[0], addr[1])) m = hashlib.md5() # 创建MD5对象 while True: # 接收客户端指令并进行分割 cmd = conn.recv(1024).decode().split() method, file_path = cmd[0], cmd[1] if os.path.isfile(file_path) and method == "get": # 判断文件是否存在 file_size = os.stat(file_path).st_size # 获取文件大小信息 print("读取文件大小:%s" % file_size) try: if file_size: with open(file_path, "rb")as f: # 以二进制方式打开文件读取 conn.send(str(file_size).encode()) # 发送文件大小给客户端 conn.recv(1024) # 等待客户端回应,避免粘包 print("开始发送文件") for line in f: conn.send(line) # 发送数据 m.update(line) # 计算当前MD5值 md5 = m.hexdigest() # 计算最终MD5值 print("文件发送完成,md5值为:%s" % md5) conn.send(md5.encode()) # 发送最终的MD5值给客户端 else: conn.send("文件为空".encode()) except PermissionError as e: conn.send(str(e).encode()) # 发送错误消息给客户端 else: conn.send("指令错误或文件不存在".encode()) |
client
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 |
import os import socket import hashlib # 创建客户端socket对象 client = socket.socket() # 连接服务器 client.connect(("127.0.0.1", 8888)) print("连接服务器成功") while True: cmd = input("# ") # 输入指令 if len(cmd.split()) != 2: # 指令应分为两部分,get命令和文件路径 print("无效指令") continue client.send(cmd.encode()) # 发送指令到服务器 file_info = client.recv(1024).decode() # 接收第一次服务器响应,如果命令和路径正确,应返回文件大小,否则会返回相应错误信息 if file_info.isdigit(): # 判断返回是否为文件大小 file_size = int(file_info) print("待接收文件大小:%s" % file_size) client.send("ACK".encode()) # 发送响应 else: print(file_info) # 未返回文件大小时直接打印返回的错误消息 continue received_size = 0 # 初始化已接收文件大小 m = hashlib.md5() # 创建md5对象,用于对数据进行校验 print("开始接收文件") while received_size < file_size: if file_size - received_size > 1024: # 判断剩余文件大小是否超出1024的缓冲区 buffer_size = 1024 else: buffer_size = file_size - received_size # 设置buffer为只接收剩余部分 save_path = os.path.split(cmd.split()[1])[1] # 获取输入的文件名,去掉路径 with open(save_path, "wb") as fw: # 将要接收的文件暂时放在当前目录下 data = client.recv(buffer_size) # 接收数据 received_size += len(data) # 累加已接收长度 # print("已接收长度: %s" % received_size) # 每次接收打印已接收过的总长度 m.update(data) # 计算MD5 fw.write(data) # 写入文件 else: print("文件接收完成") md5 = m.hexdigest() # 提取最终的MD5值 md5_remote = client.recv(1024).decode() # 获取远程文件的MD5值 print("原文件MD5: %s 接收文件MD5: %s" % (md5_remote, md5)) |
socketserver
socketserver是对socket的封装,简化了socket服务器创建流程
基本流程
1. 创建一个handler类,继承socketserver.BaseRequestHandler类 2. 重写socketserver.BaseRequestHandler类中的handler()方法,用于处理客户端请求 3. 实例化一个socketserver对象,将(监听地址、端口)和第一步创建的handler类传递给这个对象 4. 调用实例化后的socketserver类中的handle_request()或server_forever()方法接收连接 1. handle_request(): 处理一个请求后关闭socket服务器 2. server_forever(): 一直处理客户端请求,处理完不退出 5. 调用server_close()方法关闭socket服务器
socketserver_ssh
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 |
import socketserver import os class MyHandler(socketserver.BaseRequestHandler): def handle(self): while True: try: # 接收数据存入变量 data = self.request.recv(1024) except ConnectionResetError: # 当客户端断开时会抛出异常 print("Client has gone away...") break cmd = data.decode("utf-8") # 解码接收的指令 cmd_result = os.popen(cmd).read() # 执行指令 print("执行指令 %s" % cmd) if cmd_result: result_size = len(cmd_result.encode("utf-8")) self.request.sendall(str(result_size).encode("utf-8")) # 先发送结果长度 print("结果长度:%s" % result_size) self.request.recv(1024) # 等待客户端回应,避免粘包 self.request.sendall(cmd_result.encode("utf-8")) # 发送命令执行结果 else: self.request.sendall("指令错误".encode()) print("发送完成") # 实例化一个socketserver对象 # server = socketserver.TCPServer(("127.0.0.1", 8888), MyHandler) # 单进程版,一次只能处理一个请求 server = socketserver.ThreadingTCPServer(("127.0.0.1", 8888), MyHandler) # 多线程版 # server = socketserver.ForkingTCPServer(("127.0.0.1", 8888), MyHandler) # 多进程版,只能在Linux系统下使用 print("等待连接...") server.serve_forever() # 开始监听 |
原文链接:Python 从入门到放弃 - Lesson 8 Socket编程示例,转载请注明来源!