10 Python编程:从入门到实践---socket&socketserver
socket基本语法
server端配置
1 #!/usr/bin/evn python 2 # --*-- coding: utf-8 --*-- 3 # Auther : Liu WeiDong 4 5 import socket 6 7 server = socket.socket() 8 server.bind(('localhost',6969)) 9 server.listen() 10 11 print("我要开始等电话了") 12 conn,addr = server.accept() #等连接进来 13 print(conn,addr) 14 15 print("电话来了") 16 data = conn.recv(1024) 17 print("recv:",data) 18 conn.send(data.upper()) 19 20 server.close()
client端配置
1 #!/usr/bin/evn python 2 # --*-- coding: utf-8 --*-- 3 # Auther : Liu WeiDong 4 5 import socket 6 7 client = socket.socket() #声明socket类型,同时生成socket连接对象 8 client.connect(('localhost',6969)) 9 10 client.send(b"hello world!") 11 data = client.recv(1024) 12 print("rece:",data) 13 14 client.close()
实例一:模拟ssh登录服务器,输入命令将命令结果返回客户端
代码过程:
1、server端监听客户端发来的命令
2、服务端将命令通过os.popen方法将内容字符长度和命令内容返回给客户端
3、客户端接收server端返回的命令字符长度,因为有可能一次长度超过1024,需要多次从缓冲区传输
ssh server 端代码
1 #!/usr/bin/evn python 2 # --*-- coding: utf-8 --*-- 3 # Auther : Liu WeiDong 4 5 import os 6 import socket 7 8 server = socket.socket() 9 server.bind(('localhost',9999)) 10 server.listen() 11 12 while True: 13 conn,addr = server.accept() 14 while True: 15 data = conn.recv(1024) #接收客户端发来的数据请求 16 if not data: #如果客户端发来的数据请求内容为空,则终止这次循环 17 break 18 cmd_res = os.popen(data.decode()).read() 19 if len(cmd_res) == 0: 20 cmd_res = "cmd has no output...." 21 conn.send(str(len(cmd_res.encode())).encode("UTF-8")) #发送了一个返回结果的字符长度 22 conn.send(cmd_res.encode("UTF-8")) #并且将返回内容发送过去 23 server.close()
ssh client端代码
1 #!/usr/bin/evn python 2 # --*-- coding: utf-8 --*-- 3 # Auther : Liu WeiDong 4 5 import socket 6 7 client = socket.socket() 8 client.connect(('localhost',9999)) 9 10 while True: 11 cmd = input(">>") 12 if len(cmd) == 0: 13 continue 14 client.send(cmd.encode("UTF-8")) 15 cmd_res_size = client.recv(1024) #收到服务端返回的字符大小 16 print("返回结果的字符大小为:",cmd_res_size) 17 received_size = 0 18 received_data = b'' 19 while received_size < int(cmd_res_size.decode()): #如果命令结果小于发送过来字符总大小就进行循环 20 cmd_res_msg = client.recv(1024) #返回命令结果内容 21 received_size += len(cmd_res_msg) #收到的内容可能小于1024 22 received_data += cmd_res_msg 23 else: 24 print("cmd res receive done....",received_size) 25 print(received_data.decode()) 26 client.close()
实例二:通过socket实现文件发送
代码过程:
- 读取文件名
- 检测文件是否存在
- 打开文件
- 检测文件大小
- 发送文件大小给客户端
- 等客户端确认
- 开始边读边发数据
- 发送md5校验
ftp server端代码:
1 #!/usr/bin/evn python 2 # --*-- coding: utf-8 --*-- 3 # Auther : Liu WeiDong 4 import os 5 import socket 6 import hashlib 7 8 9 server = socket.socket() 10 server.bind(('0.0.0.0',9099)) 11 server.listen() 12 13 while True: 14 conn,addr = server.accept() 15 while True: 16 data = conn.recv(1024) 17 if not data: 18 break 19 print(data) 20 cmd,filename = data.decode().split() 21 if os.path.isfile(filename): 22 f = open(filename,"rb") 23 m = hashlib.md5() 24 file_size = os.stat(filename).st_size 25 conn.send(str(file_size).encode()) 26 conn.recv(1024) #接收客户端防止粘包发送的内容 27 for line in f: 28 m.update(line) 29 conn.send(line) 30 #print("file md5",m.hexdigest()) 31 f.close() 32 conn.send(m.hexdigest().encode()) 33 server.close()
ftp client端代码:
1 #!/usr/bin/evn python 2 # --*-- coding: utf-8 --*-- 3 # Auther : Liu WeiDong 4 5 import socket 6 import hashlib 7 client = socket.socket() 8 client.connect(('localhost',9099)) 9 10 while True: 11 cmd = input(">>>").strip() 12 if len(cmd) == 0: 13 continue 14 if cmd.startswith("get"): 15 client.send(cmd.encode()) 16 server_response = client.recv(1024) #接收server端判断的数据文件大小 17 print(server_response) #打印server端判断的数据文件大小 18 client.send(b"ready to rece file") # 目的是防止粘包 19 file_total_size = int(server_response.decode()) #将server发送文件内容进行解码并转换成整数 20 received_size = 0 #初始化变量文件大小为0 21 filename = cmd.split()[1] #获取客户端输出的文件名称 22 f = open(filename + ".new","wb") #将从server端读取的文件,写入到新文件 23 m = hashlib.md5() 24 while received_size < file_total_size: #每次串1024字符 25 if file_total_size - received_size > 1024: 26 size = 1024 27 else: 28 size = file_total_size - received_size #当不满1024个字符也一次发送过去 29 30 data = client.recv(size) 31 received_size += len(data) 32 m.update(data) 33 f.write(data) 34 #print(file_total_size,received_size) 35 else: 36 new_file_md5 = m.hexdigest() 37 print("file rece done",received_size,file_total_size) 38 f.close() 39 sever_file_md5 = client.recv(1024) 40 print("server file md5:",sever_file_md5) 41 print("client file md5:",new_file_md5) 42 43 client.close()
执行结果如下:出现了以.new结尾的文件,并且md5校验码相同,说明两个文件内容相同
socketserver级别操作
1 #!/usr/bin/evn python 2 # --*-- coding: utf-8 --*-- 3 # Auther : Liu WeiDong 4 import socketserver 5 6 7 class MyTCPHandler(socketserver.BaseRequestHandler): 8 def handle(self): 9 while True: 10 try: 11 self.data = self.request.recv(1024).strip() 12 print("{} wrote:".format(self.client_address[0])) 13 print(self.data) 14 self.request.send(self.data.upper()) 15 except ConnectionError as e: 16 print("err",e) 17 break 18 if __name__ == "__main__": 19 HOST,PORT = "localhost",9999 20 server = socketserver.TCPServer((HOST,PORT),MyTCPHandler) 21 server.serve_forever()
不积跬步,无以至千里;不积小流,无以成江海。